Update DS Proxy to use RBAC action (#87517)

iam-team: Update DS Proxy to use RBAC action
This commit is contained in:
Aaron Godin 2024-05-21 08:05:16 -05:00 committed by GitHub
parent 410e3b17e9
commit 0072e4a92d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 56 additions and 7 deletions

View File

@ -189,4 +189,5 @@ export interface FeatureToggles {
newDashboardSharingComponent?: boolean;
notificationBanner?: boolean;
dashboardRestore?: boolean;
datasourceProxyDisableRBAC?: boolean;
}

View File

@ -19,6 +19,7 @@ import (
glog "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/tracing"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/services/accesscontrol"
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
"github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/featuremgmt"
@ -304,8 +305,14 @@ func (proxy *DataSourceProxy) validateRequest() error {
continue
}
if route.ReqRole.IsValid() {
if !proxy.ctx.HasUserRole(route.ReqRole) {
if proxy.features.IsEnabled(proxy.ctx.Req.Context(), featuremgmt.FlagDatasourceProxyDisableRBAC) {
// TODO(aarongodin): following logic can be removed with FlagDatasourceProxyDisableRBAC as it is covered by
// proxy.hasAccessToRoute(..)
if route.ReqRole.IsValid() && !proxy.ctx.HasUserRole(route.ReqRole) {
return errors.New("plugin proxy route access denied")
}
} else {
if !proxy.hasAccessToRoute(route) {
return errors.New("plugin proxy route access denied")
}
}
@ -330,6 +337,26 @@ func (proxy *DataSourceProxy) validateRequest() error {
return nil
}
func (proxy *DataSourceProxy) hasAccessToRoute(route *plugins.Route) bool {
ctxLogger := logger.FromContext(proxy.ctx.Req.Context())
useRBAC := proxy.features.IsEnabled(proxy.ctx.Req.Context(), featuremgmt.FlagAccessControlOnCall) && route.ReqAction != ""
if useRBAC {
routeEval := accesscontrol.EvalPermission(route.ReqAction)
ok := routeEval.Evaluate(proxy.ctx.GetPermissions())
if !ok {
ctxLogger.Debug("plugin route is covered by RBAC, user doesn't have access", "route", proxy.ctx.Req.URL.Path, "action", route.ReqAction, "path", route.Path, "method", route.Method)
}
return ok
}
if route.ReqRole.IsValid() {
if hasUserRole := proxy.ctx.HasUserRole(route.ReqRole); !hasUserRole {
ctxLogger.Debug("plugin route is covered by org role, user doesn't have access", "route", proxy.ctx.Req.URL.Path, "role", route.ReqRole, "path", route.Path, "method", route.Method)
return false
}
}
return true
}
func (proxy *DataSourceProxy) logRequest() {
if !proxy.cfg.DataProxyLogging {
return

View File

@ -122,7 +122,7 @@ func (proxy *PluginProxy) HandleRequest() {
}
func (proxy *PluginProxy) hasAccessToRoute(route *plugins.Route) bool {
useRBAC := proxy.features.IsEnabled(proxy.ctx.Req.Context(), featuremgmt.FlagAccessControlOnCall) && route.RequiresRBACAction()
useRBAC := proxy.features.IsEnabled(proxy.ctx.Req.Context(), featuremgmt.FlagAccessControlOnCall) && route.ReqAction != ""
if useRBAC {
hasAccess := ac.HasAccess(proxy.accessControl, proxy.ctx)(ac.EvalPermission(route.ReqAction))
if !hasAccess {

View File

@ -207,10 +207,6 @@ type Route struct {
Body json.RawMessage `json:"body"`
}
func (r *Route) RequiresRBACAction() bool {
return r.ReqAction != ""
}
// Header describes an HTTP header that is forwarded with
// the proxied request for a plugin route
type Header struct {

View File

@ -1275,6 +1275,13 @@ var (
HideFromDocs: true,
HideFromAdminPage: true,
},
{
Name: "datasourceProxyDisableRBAC",
Description: "Disables applying a plugin route's ReqAction field to authorization",
Stage: FeatureStageGeneralAvailability,
Owner: identityAccessTeam,
HideFromDocs: true,
},
}
)

View File

@ -170,3 +170,4 @@ logsExploreTableDefaultVisualization,experimental,@grafana/observability-logs,fa
newDashboardSharingComponent,experimental,@grafana/sharing-squad,false,false,true
notificationBanner,experimental,@grafana/grafana-frontend-platform,false,false,false
dashboardRestore,experimental,@grafana/grafana-frontend-platform,false,false,false
datasourceProxyDisableRBAC,GA,@grafana/identity-access-team,false,false,false

1 Name Stage Owner requiresDevMode RequiresRestart FrontendOnly
170 newDashboardSharingComponent experimental @grafana/sharing-squad false false true
171 notificationBanner experimental @grafana/grafana-frontend-platform false false false
172 dashboardRestore experimental @grafana/grafana-frontend-platform false false false
173 datasourceProxyDisableRBAC GA @grafana/identity-access-team false false false

View File

@ -690,4 +690,8 @@ const (
// FlagDashboardRestore
// Enables deleted dashboard restore feature
FlagDashboardRestore = "dashboardRestore"
// FlagDatasourceProxyDisableRBAC
// Disables applying a plugin route's ReqAction field to authorization
FlagDatasourceProxyDisableRBAC = "datasourceProxyDisableRBAC"
)

View File

@ -2222,6 +2222,19 @@
"hideFromAdminPage": true,
"hideFromDocs": true
}
},
{
"metadata": {
"name": "datasourceProxyDisableRBAC",
"resourceVersion": "1715889033198",
"creationTimestamp": "2024-05-16T19:50:33Z"
},
"spec": {
"description": "Disables applying a plugin route's ReqAction field to authorization",
"stage": "GA",
"codeowner": "@grafana/identity-access-team",
"hideFromDocs": true
}
}
]
}