Allows posting to prom rules endpoints via ds_proxy (#32946)

* allows posting to prom rules endpoints via ds_proxy

* prom proxy routes via plugin and fix proxy route matching bug

* bump ci
This commit is contained in:
Owen Diehl 2021-04-14 13:06:20 -04:00 committed by GitHub
parent b3ac63dad7
commit dadccdda06
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 96 additions and 17 deletions

View File

@ -246,18 +246,6 @@ func (proxy *DataSourceProxy) validateRequest() error {
return errors.New("target URL is not a valid target")
}
if proxy.ds.Type == models.DS_PROMETHEUS {
if proxy.ctx.Req.Request.Method == "DELETE" {
return errors.New("deletes not allowed on proxied Prometheus datasource")
}
if proxy.ctx.Req.Request.Method == "PUT" {
return errors.New("puts not allowed on proxied Prometheus datasource")
}
if proxy.ctx.Req.Request.Method == "POST" && !(proxy.proxyPath == "api/v1/query" || proxy.proxyPath == "api/v1/query_range" || proxy.proxyPath == "api/v1/series" || proxy.proxyPath == "api/v1/labels" || proxy.proxyPath == "api/v1/query_exemplars") {
return errors.New("posts not allowed on proxied Prometheus datasource except on /query, /query_range, /series and /labels")
}
}
if proxy.ds.Type == models.DS_ES {
if proxy.ctx.Req.Request.Method == "DELETE" {
return errors.New("deletes not allowed on proxied Elasticsearch datasource")
@ -278,16 +266,29 @@ func (proxy *DataSourceProxy) validateRequest() error {
continue
}
// route match
if !strings.HasPrefix(proxy.proxyPath, route.Path) {
continue
}
if route.ReqRole.IsValid() {
if !proxy.ctx.HasUserRole(route.ReqRole) {
return errors.New("plugin proxy route access denied")
}
}
if strings.HasPrefix(proxy.proxyPath, route.Path) {
proxy.route = route
break
}
proxy.route = route
return nil
}
}
// Trailing validation below this point for routes that were not matched
if proxy.ds.Type == models.DS_PROMETHEUS {
if proxy.ctx.Req.Request.Method == "DELETE" {
return errors.New("non allow-listed DELETEs not allowed on proxied Prometheus datasource")
}
if proxy.ctx.Req.Request.Method == "PUT" {
return errors.New("non allow-listed PUTs not allowed on proxied Prometheus datasource")
}
}

View File

@ -895,3 +895,40 @@ func runDatasourceAuthTest(t *testing.T, test *testCase) {
test.checkReq(req)
}
func Test_PathCheck(t *testing.T) {
// Ensure that we test routes appropriately. This test reproduces a historical bug where two routes were defined with different role requirements but the same method and the more privileged route was tested first. Here we ensure auth checks are applied based on the correct route, not just the method.
plugin := &plugins.DataSourcePlugin{
Routes: []*plugins.AppPluginRoute{
{
Path: "a",
URL: "https://www.google.com",
ReqRole: models.ROLE_EDITOR,
Method: http.MethodGet,
},
{
Path: "b",
URL: "https://www.google.com",
ReqRole: models.ROLE_VIEWER,
Method: http.MethodGet,
},
},
}
setUp := func() (*models.ReqContext, *http.Request) {
req, err := http.NewRequest("GET", "http://localhost/asd", nil)
require.NoError(t, err)
ctx := &models.ReqContext{
Context: &macaron.Context{
Req: macaron.Request{Request: req},
},
SignedInUser: &models.SignedInUser{OrgRole: models.ROLE_VIEWER},
}
return ctx, req
}
ctx, _ := setUp()
proxy, err := NewDataSourceProxy(&models.DataSource{}, plugin, ctx, "b", &setting.Cfg{})
require.NoError(t, err)
require.Nil(t, proxy.validateRequest())
require.Equal(t, plugin.Routes[1], proxy.route)
}

View File

@ -3,7 +3,48 @@
"name": "Prometheus",
"id": "prometheus",
"category": "tsdb",
"routes": [
{
"method": "POST",
"path": "api/v1/query",
"reqRole": "Viewer"
},
{
"method": "POST",
"path": "api/v1/query_range",
"reqRole": "Viewer"
},
{
"method": "POST",
"path": "api/v1/series",
"reqRole": "Viewer"
},
{
"method": "POST",
"path": "api/v1/labels",
"reqRole": "Viewer"
},
{
"method": "POST",
"path": "api/v1/query_exemplars",
"reqRole": "Viewer"
},
{
"method": "GET",
"path": "api/v1/rules",
"reqRole": "Viewer"
},
{
"method": "POST",
"path": "api/v1/rules",
"reqRole": "Editor"
},
{
"method": "DELETE",
"path": "api/v1/rules",
"reqRole": "Editor"
}
],
"includes": [
{
"type": "dashboard",