diff --git a/pkg/api/accesscontrol.go b/pkg/api/accesscontrol.go index 6f08cfd6382..dffe67e03a8 100644 --- a/pkg/api/accesscontrol.go +++ b/pkg/api/accesscontrol.go @@ -5,6 +5,7 @@ import ( ac "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/datasources" + "github.com/grafana/grafana/pkg/services/serviceaccounts" "github.com/grafana/grafana/pkg/setting" ) @@ -462,6 +463,12 @@ var teamsEditAccessEvaluator = ac.EvalAll( ), ) +// apiKeyAccessEvaluator is used to protect the "Configuration > API keys" page access +var apiKeyAccessEvaluator = ac.EvalPermission(ac.ActionAPIKeyRead) + +// serviceAccountAccessEvaluator is used to protect the "Configuration > Service accounts" page access +var serviceAccountAccessEvaluator = ac.EvalPermission(serviceaccounts.ActionRead) + // Metadata helpers // getAccessControlMetadata returns the accesscontrol metadata associated with a given resource func (hs *HTTPServer) getAccessControlMetadata(c *models.ReqContext, diff --git a/pkg/api/api.go b/pkg/api/api.go index 4836363dfaf..a7de6111fab 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -14,6 +14,7 @@ import ( "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/featuremgmt" + "github.com/grafana/grafana/pkg/services/serviceaccounts" "github.com/grafana/grafana/pkg/web" ) @@ -62,9 +63,9 @@ func (hs *HTTPServer) registerRoutes() { r.Get("/org/teams", authorize(reqCanAccessTeams, ac.EvalPermission(ac.ActionTeamsRead)), hs.Index) r.Get("/org/teams/edit/*", authorize(reqCanAccessTeams, teamsEditAccessEvaluator), hs.Index) r.Get("/org/teams/new", authorize(reqCanAccessTeams, ac.EvalPermission(ac.ActionTeamsCreate)), hs.Index) - r.Get("/org/serviceaccounts", middleware.ReqOrgAdmin, hs.Index) - r.Get("/org/serviceaccounts/:serviceAccountId", middleware.ReqOrgAdmin, hs.Index) - r.Get("/org/apikeys/", reqOrgAdmin, hs.Index) + r.Get("/org/serviceaccounts", authorize(reqOrgAdmin, ac.EvalPermission(serviceaccounts.ActionRead)), hs.Index) + r.Get("/org/serviceaccounts/:serviceAccountId", authorize(reqOrgAdmin, ac.EvalPermission(serviceaccounts.ActionRead)), hs.Index) + r.Get("/org/apikeys/", authorize(reqOrgAdmin, ac.EvalPermission(ac.ActionAPIKeyRead)), hs.Index) r.Get("/dashboard/import/", reqSignedIn, hs.Index) r.Get("/configuration", reqGrafanaAdmin, hs.Index) r.Get("/admin", reqGrafanaAdmin, hs.Index) diff --git a/pkg/api/index.go b/pkg/api/index.go index 3167a3012e0..6f1bf97ee54 100644 --- a/pkg/api/index.go +++ b/pkg/api/index.go @@ -149,8 +149,11 @@ func (hs *HTTPServer) getAppLinks(c *models.ReqContext) ([]*dtos.NavLink, error) } func enableServiceAccount(hs *HTTPServer, c *models.ReqContext) bool { - return (c.OrgRole == models.ROLE_ADMIN || (hs.Cfg.EditorsCanAdmin && c.OrgRole == models.ROLE_EDITOR)) && - hs.Features.IsEnabled(featuremgmt.FlagServiceAccounts) + if !hs.Features.IsEnabled(featuremgmt.FlagServiceAccounts) { + return false + } + hasAccess := ac.HasAccess(hs.AccessControl, c) + return hasAccess(ac.ReqOrgAdmin, serviceAccountAccessEvaluator) } func (hs *HTTPServer) ReqCanAdminTeams(c *models.ReqContext) bool { @@ -291,7 +294,7 @@ func (hs *HTTPServer) getNavTree(c *models.ReqContext, hasEditPerm bool) ([]*dto }) } - if c.OrgRole == models.ROLE_ADMIN { + if hasAccess(ac.ReqOrgAdmin, apiKeyAccessEvaluator) { configNodes = append(configNodes, &dtos.NavLink{ Text: "API keys", Id: "apikeys", diff --git a/public/app/features/serviceaccounts/ServiceAccountsListItem.tsx b/public/app/features/serviceaccounts/ServiceAccountsListItem.tsx index e5d875a9be6..d0de3b2e9e9 100644 --- a/public/app/features/serviceaccounts/ServiceAccountsListItem.tsx +++ b/public/app/features/serviceaccounts/ServiceAccountsListItem.tsx @@ -28,7 +28,10 @@ const ServiceAccountListItem = memo( const editUrl = `org/serviceaccounts/${serviceAccount.id}`; const styles = useStyles2(getStyles); const canUpdateRole = contextSrv.hasPermissionInMetadata(AccessControlAction.ServiceAccountsWrite, serviceAccount); - const rolePickerDisabled = !canUpdateRole; + const displayRolePicker = + contextSrv.hasPermission(AccessControlAction.ActionRolesList) && + contextSrv.hasPermission(AccessControlAction.ActionUserRolesList); + const enableRolePicker = contextSrv.hasPermission(AccessControlAction.OrgUsersRoleUpdate) && canUpdateRole; return (