RBAC: Feature to override default assignments (#66561)

* RBAC: Feature to override default assignments

Co-authored-by: Kalle Persson <kalle.persson@grafana.com>

* Add test and trim spaces

* Pass linting

* Apply the rbac overrides to fixed_authentication.config_writer

* Removing from the default ini file for now

* Add grants overrides section to cfg

* slimmer handleGrantOverrides function

---------

Co-authored-by: Kalle Persson <kalle.persson@grafana.com>
This commit is contained in:
Gabriel MABILLE 2023-04-14 17:17:59 +02:00 committed by GitHub
parent 02951e8a26
commit 3b63844390
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 106 additions and 5 deletions

View File

@ -166,7 +166,12 @@ func (s *Service) DeclareFixedRoles(registrations ...accesscontrol.RoleRegistrat
return nil
}
for _, r := range registrations {
for i := range registrations {
r := registrations[i]
if r.AllowGrantsOverride {
s.handleGrantOverrides(&r)
}
err := accesscontrol.ValidateFixedRole(r.Role)
if err != nil {
return err
@ -183,6 +188,15 @@ func (s *Service) DeclareFixedRoles(registrations ...accesscontrol.RoleRegistrat
return nil
}
func (s *Service) handleGrantOverrides(r *accesscontrol.RoleRegistration) {
// Replace ":" and "." with "_" to match the key in the config
key := strings.ReplaceAll(strings.ReplaceAll(r.Role.Name, ":", "_"), ".", "_")
if overrides, ok := s.cfg.RBACGrantOverrides[key]; ok {
r.Grants = overrides
s.log.Info("Overriding grants for role", "role", r.Role.Name, "overrides", overrides)
}
}
// RegisterFixedRoles registers all declared roles in RAM
func (s *Service) RegisterFixedRoles(ctx context.Context) error {
// If accesscontrol is disabled no need to register roles

View File

@ -161,6 +161,77 @@ func TestService_DeclareFixedRoles(t *testing.T) {
}
}
func TestService_DeclareFixedRoles_Overrides(t *testing.T) {
tests := []struct {
name string
registration accesscontrol.RoleRegistration
overrides map[string][]string
wantGrants []string
wantErr bool
}{
{
name: "no grant override",
registration: accesscontrol.RoleRegistration{
Role: accesscontrol.RoleDTO{Name: "fixed:test:test"},
Grants: []string{"Admin"},
AllowGrantsOverride: true,
},
wantGrants: []string{"Admin"},
wantErr: false,
},
{
name: "should account for grant overrides",
registration: accesscontrol.RoleRegistration{
Role: accesscontrol.RoleDTO{Name: "fixed:test:test"},
Grants: []string{"Admin"},
AllowGrantsOverride: true,
},
overrides: map[string][]string{"fixed_test_test": {"Viewer", "Grafana Admin"}},
wantGrants: []string{"Viewer", "Grafana Admin"},
wantErr: false,
},
{
name: "should not account for grant overrides",
registration: accesscontrol.RoleRegistration{
Role: accesscontrol.RoleDTO{Name: "fixed:test:test"},
Grants: []string{"Admin"},
AllowGrantsOverride: false,
},
overrides: map[string][]string{"fixed_test_test": {"Viewer", "Grafana Admin"}},
wantGrants: []string{"Admin"},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ac := setupTestEnv(t)
// Reset the registations
ac.registrations = accesscontrol.RegistrationList{}
ac.cfg.RBACGrantOverrides = tt.overrides
// Test
err := ac.DeclareFixedRoles(tt.registration)
if tt.wantErr {
require.Error(t, err)
return
}
require.NoError(t, err)
registrationCnt := 0
grants := []string{}
ac.registrations.Range(func(registration accesscontrol.RoleRegistration) bool {
registrationCnt++
grants = registration.Grants
return true
})
require.Equal(t, 1, registrationCnt,
"expected service registration list to contain the registration")
require.ElementsMatch(t, tt.wantGrants, grants)
})
}
}
func TestService_DeclarePluginRoles(t *testing.T) {
tests := []struct {
name string

View File

@ -16,8 +16,9 @@ var ErrInternal = errutil.NewBase(errutil.StatusInternal, "accesscontrol.interna
// RoleRegistration stores a role and its assignments to built-in roles
// (Viewer, Editor, Admin, Grafana Admin)
type RoleRegistration struct {
Role RoleDTO
Grants []string
Role RoleDTO
Grants []string
AllowGrantsOverride bool
}
// Role is the model for Role in RBAC.

View File

@ -233,8 +233,9 @@ func DeclareFixedRoles(service Service) error {
Grants: []string{RoleGrafanaAdmin},
}
authenticationConfigWriter := RoleRegistration{
Role: authenticationConfigWriterRole,
Grants: []string{RoleGrafanaAdmin},
Role: authenticationConfigWriterRole,
Grants: []string{RoleGrafanaAdmin},
AllowGrantsOverride: true,
}
return service.DeclareFixedRoles(ldapReader, ldapWriter, orgUsersReader, orgUsersWriter,

View File

@ -505,6 +505,9 @@ type Cfg struct {
RBACPermissionValidationEnabled bool
// Reset basic roles permissions on start-up
RBACResetBasicRoles bool
// Override default fixed role assignments
RBACGrantOverrides map[string][]string
// GRPC Server.
GRPCServerNetwork string
GRPCServerAddress string
@ -1559,6 +1562,17 @@ func readAccessControlSettings(iniFile *ini.File, cfg *Cfg) {
cfg.RBACPermissionCache = rbac.Key("permission_cache").MustBool(true)
cfg.RBACPermissionValidationEnabled = rbac.Key("permission_validation_enabled").MustBool(false)
cfg.RBACResetBasicRoles = rbac.Key("reset_basic_roles").MustBool(false)
rbacOverrides := iniFile.Section("rbac.overrides")
cfg.RBACGrantOverrides = map[string][]string{}
for _, key := range rbacOverrides.Keys() {
value := key.MustString("")
grants := strings.Split(value, ",")
for i, grant := range grants {
grants[i] = strings.TrimSpace(grant)
}
cfg.RBACGrantOverrides[key.Name()] = grants
}
}
func readUserSettings(iniFile *ini.File, cfg *Cfg) error {