Add auth spans and remove deduplication code for scopes (#89804)

Adds more spans for timing in accesscontrol and remove permission deduplicating code after benchmarking

---------

Signed-off-by: Dave Henderson <dave.henderson@grafana.com>
Co-authored-by: Dave Henderson <dave.henderson@grafana.com>
Co-authored-by: Ieva <ieva.vasiljeva@grafana.com>
This commit is contained in:
Jeff Levin
2024-07-02 22:08:57 -08:00
committed by GitHub
co-authored by Dave Henderson Ieva
parent 5b6edc96d9
commit cfe8317d45
36 changed files with 279 additions and 97 deletions
+46 -3
View File
@@ -114,6 +114,7 @@ func (s *Service) GetUsageStats(_ context.Context) map[string]any {
func (s *Service) GetUserPermissions(ctx context.Context, user identity.Requester, options accesscontrol.Options) ([]accesscontrol.Permission, error) {
ctx, span := s.tracer.Start(ctx, "authz.GetUserPermissionsOSS")
defer span.End()
timer := prometheus.NewTimer(metrics.MAccessPermissionsSummary)
defer timer.ObserveDuration()
@@ -125,6 +126,9 @@ func (s *Service) GetUserPermissions(ctx context.Context, user identity.Requeste
}
func (s *Service) getUserPermissions(ctx context.Context, user identity.Requester, options accesscontrol.Options) ([]accesscontrol.Permission, error) {
ctx, span := s.tracer.Start(ctx, "authz.getUserPermissions")
defer span.End()
permissions := make([]accesscontrol.Permission, 0)
for _, builtin := range accesscontrol.GetOrgRoles(user) {
if basicRole, ok := s.roles[builtin]; ok {
@@ -265,8 +269,10 @@ func (s *Service) getCachedBasicRolesPermissions(ctx context.Context, user ident
defer span.End()
basicRoles := accesscontrol.GetOrgRoles(user)
span.SetAttributes(attribute.Int("roles", len(basicRoles)))
for _, role := range basicRoles {
perms, err := s.getCachedBasicRolePermissions(ctx, role, user.GetOrgID(), options)
span.SetAttributes(attribute.Int(fmt.Sprintf("role_%s_permissions", role), len(perms)))
if err != nil {
return nil, err
}
@@ -301,12 +307,13 @@ type getPermissionsFunc = func(ctx context.Context) ([]accesscontrol.Permission,
// Generic method for getting various permissions from cache
func (s *Service) getCachedPermissions(ctx context.Context, key string, getPermissionsFn getPermissionsFunc, options accesscontrol.Options) ([]accesscontrol.Permission, error) {
_, span := s.tracer.Start(ctx, "authz.getCachedPermissions")
ctx, span := s.tracer.Start(ctx, "authz.getCachedPermissions")
defer span.End()
if !options.ReloadCache {
permissions, ok := s.cache.Get(key)
if ok {
span.SetAttributes(attribute.Int("num_permissions_cached", len(permissions.([]accesscontrol.Permission))))
metrics.MAccessPermissionsCacheUsage.WithLabelValues(accesscontrol.CacheHit).Inc()
return permissions.([]accesscontrol.Permission), nil
}
@@ -315,6 +322,7 @@ func (s *Service) getCachedPermissions(ctx context.Context, key string, getPermi
span.AddEvent("cache miss")
metrics.MAccessPermissionsCacheUsage.WithLabelValues(accesscontrol.CacheMiss).Inc()
permissions, err := getPermissionsFn(ctx)
span.SetAttributes(attribute.Int("num_permissions_fetched", len(permissions)))
if err != nil {
return nil, err
}
@@ -338,6 +346,7 @@ func (s *Service) getCachedTeamsPermissions(ctx context.Context, user identity.R
teamPermissions, ok := s.cache.Get(key)
if ok {
metrics.MAccessPermissionsCacheUsage.WithLabelValues(accesscontrol.CacheHit).Inc()
span.SetAttributes(attribute.Int("num_permissions_cached", len(teamPermissions.([]accesscontrol.Permission))))
permissions = append(permissions, teamPermissions.([]accesscontrol.Permission)...)
} else {
miss = append(miss, teamID)
@@ -349,6 +358,7 @@ func (s *Service) getCachedTeamsPermissions(ctx context.Context, user identity.R
span.AddEvent("cache miss")
metrics.MAccessPermissionsCacheUsage.WithLabelValues(accesscontrol.CacheMiss).Inc()
teamsPermissions, err := s.getTeamsPermissions(ctx, miss, orgID)
span.SetAttributes(attribute.Int("num_permissions_fetched", len(teamsPermissions)))
if err != nil {
return nil, err
}
@@ -369,10 +379,16 @@ func (s *Service) ClearUserPermissionCache(user identity.Requester) {
}
func (s *Service) DeleteUserPermissions(ctx context.Context, orgID int64, userID int64) error {
ctx, span := s.tracer.Start(ctx, "authz.DeleteUserPermissions")
defer span.End()
return s.store.DeleteUserPermissions(ctx, orgID, userID)
}
func (s *Service) DeleteTeamPermissions(ctx context.Context, orgID int64, teamID int64) error {
ctx, span := s.tracer.Start(ctx, "authz.DeleteTeamPermissions")
defer span.End()
return s.store.DeleteTeamPermissions(ctx, orgID, teamID)
}
@@ -398,6 +414,9 @@ func (s *Service) DeclareFixedRoles(registrations ...accesscontrol.RoleRegistrat
// RegisterFixedRoles registers all declared roles in RAM
func (s *Service) RegisterFixedRoles(ctx context.Context) error {
_, span := s.tracer.Start(ctx, "authz.RegisterFixedRoles")
defer span.End()
s.registrations.Range(func(registration accesscontrol.RoleRegistration) bool {
for br := range accesscontrol.BuiltInRolesWithParents(registration.Grants) {
if basicRole, ok := s.roles[br]; ok {
@@ -421,6 +440,9 @@ func (s *Service) RegisterFixedRoles(ctx context.Context) error {
// DeclarePluginRoles allow the caller to declare, to the service, plugin roles and their assignments
// to organization roles ("Viewer", "Editor", "Admin") or "Grafana Admin"
func (s *Service) DeclarePluginRoles(ctx context.Context, ID, name string, regs []plugins.RoleRegistration) error {
ctx, span := s.tracer.Start(ctx, "authz.DeclarePluginRoles")
defer span.End()
// Protect behind feature toggle
if !s.features.IsEnabled(ctx, featuremgmt.FlagAccessControlOnCall) {
return nil
@@ -455,6 +477,9 @@ func GetActionFilter(options accesscontrol.SearchOptions) func(action string) bo
// SearchUsersPermissions returns all users' permissions filtered by action prefixes
func (s *Service) SearchUsersPermissions(ctx context.Context, usr identity.Requester, options accesscontrol.SearchOptions) (map[int64][]accesscontrol.Permission, error) {
ctx, span := s.tracer.Start(ctx, "authz.SearchUsersPermissions")
defer span.End()
// Limit roles to available in OSS
options.RolePrefixes = OSSRolesPrefixes
if options.NamespacedID != "" {
@@ -566,6 +591,9 @@ func (s *Service) SearchUsersPermissions(ctx context.Context, usr identity.Reque
}
func (s *Service) SearchUserPermissions(ctx context.Context, orgID int64, searchOptions accesscontrol.SearchOptions) ([]accesscontrol.Permission, error) {
ctx, span := s.tracer.Start(ctx, "authz.SearchUserPermissions")
defer span.End()
timer := prometheus.NewTimer(metrics.MAccessPermissionsSummary)
defer timer.ObserveDuration()
@@ -573,13 +601,16 @@ func (s *Service) SearchUserPermissions(ctx context.Context, orgID int64, search
return nil, fmt.Errorf("expected namespaced ID to be specified")
}
if permissions, success := s.searchUserPermissionsFromCache(orgID, searchOptions); success {
if permissions, success := s.searchUserPermissionsFromCache(ctx, orgID, searchOptions); success {
return permissions, nil
}
return s.searchUserPermissions(ctx, orgID, searchOptions)
}
func (s *Service) searchUserPermissions(ctx context.Context, orgID int64, searchOptions accesscontrol.SearchOptions) ([]accesscontrol.Permission, error) {
ctx, span := s.tracer.Start(ctx, "authz.searchUserPermissions")
defer span.End()
userID, err := searchOptions.ComputeUserID()
if err != nil {
return nil, err
@@ -629,7 +660,10 @@ func (s *Service) searchUserPermissions(ctx context.Context, orgID int64, search
return permissions, nil
}
func (s *Service) searchUserPermissionsFromCache(orgID int64, searchOptions accesscontrol.SearchOptions) ([]accesscontrol.Permission, bool) {
func (s *Service) searchUserPermissionsFromCache(ctx context.Context, orgID int64, searchOptions accesscontrol.SearchOptions) ([]accesscontrol.Permission, bool) {
_, span := s.tracer.Start(ctx, "authz.searchUserPermissionsFromCache")
defer span.End()
userID, err := searchOptions.ComputeUserID()
if err != nil {
return nil, false
@@ -669,6 +703,9 @@ func PermissionMatchesSearchOptions(permission accesscontrol.Permission, searchO
}
func (s *Service) SaveExternalServiceRole(ctx context.Context, cmd accesscontrol.SaveExternalServiceRoleCommand) error {
ctx, span := s.tracer.Start(ctx, "authz.SaveExternalServiceRole")
defer span.End()
if !s.features.IsEnabled(ctx, featuremgmt.FlagExternalServiceAccounts) {
s.log.Debug("Registering an external service role is behind a feature flag, enable it to use this feature.")
return nil
@@ -682,6 +719,9 @@ func (s *Service) SaveExternalServiceRole(ctx context.Context, cmd accesscontrol
}
func (s *Service) DeleteExternalServiceRole(ctx context.Context, externalServiceID string) error {
ctx, span := s.tracer.Start(ctx, "authz.DeleteExternalServiceRole")
defer span.End()
if !s.features.IsEnabled(ctx, featuremgmt.FlagExternalServiceAccounts) {
s.log.Debug("Deleting an external service role is behind a feature flag, enable it to use this feature.")
return nil
@@ -697,6 +737,9 @@ func (*Service) SyncUserRoles(ctx context.Context, orgID int64, cmd accesscontro
}
func (s *Service) GetRoleByName(ctx context.Context, orgID int64, roleName string) (*accesscontrol.RoleDTO, error) {
_, span := s.tracer.Start(ctx, "authz.GetRoleByName")
defer span.End()
err := accesscontrol.ErrRoleNotFound
if _, ok := s.roles[roleName]; ok {
return nil, err
@@ -42,6 +42,7 @@ func setupTestEnv(t testing.TB) *Service {
registrations: accesscontrol.RegistrationList{},
roles: accesscontrol.BuildBasicRoleDefinitions(),
store: database.ProvideService(db.InitTestDB(t)),
tracer: tracing.InitializeTracerForTest(),
}
require.NoError(t, ac.RegisterFixedRoles(context.Background()))
return ac