grafana-iam: Use the UniStore as the default store (#113614)
* `grafana-iam`: Use the UniStore as the default store * Refactor all instantiations * Remove enableDualWriter * Nit. dw is clear enough * Use the correct access control client
This commit is contained in:
@@ -8,6 +8,10 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/iam/legacy"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/iam/serviceaccount"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/iam/sso"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/iam/team"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/iam/teambinding"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/iam/user"
|
||||
"github.com/grafana/grafana/pkg/services/apiserver/builder"
|
||||
"github.com/grafana/grafana/pkg/services/authz/zanzana"
|
||||
@@ -42,7 +46,13 @@ type ExternalGroupMappingStorageBackend interface{ resource.StorageBackend }
|
||||
// This is used just so wire has something unique to return
|
||||
type IdentityAccessManagementAPIBuilder struct {
|
||||
// Stores
|
||||
store legacy.LegacyIdentityStore
|
||||
store legacy.LegacyIdentityStore
|
||||
|
||||
userLegacyStore *user.LegacyStore
|
||||
saLegacyStore *serviceaccount.LegacyStore
|
||||
legacyTeamStore *team.LegacyStore
|
||||
teamBindingLegacyStore *teambinding.LegacyBindingStore
|
||||
ssoLegacyStore *sso.LegacyStore
|
||||
coreRolesStorage CoreRoleStorageBackend
|
||||
rolesStorage RoleStorageBackend
|
||||
resourcePermissionsStorage resource.StorageBackend
|
||||
@@ -78,7 +88,4 @@ type IdentityAccessManagementAPIBuilder struct {
|
||||
|
||||
// Toggle for enabling authz management apis
|
||||
features featuremgmt.FeatureToggles
|
||||
|
||||
// Toggle for enabling dual writer
|
||||
enableDualWriter bool
|
||||
}
|
||||
|
||||
+101
-111
@@ -31,7 +31,6 @@ import (
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/iam/externalgroupmapping"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/iam/legacy"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/iam/noopstorage"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/iam/resourcepermission"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/iam/serviceaccount"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/iam/sso"
|
||||
@@ -76,8 +75,16 @@ func RegisterAPIService(
|
||||
authorizer := newIAMAuthorizer(accessClient, legacyAccessClient)
|
||||
registerMetrics(reg)
|
||||
|
||||
//nolint:staticcheck // not yet migrated to OpenFeature
|
||||
enableAuthnMutation := features.IsEnabledGlobally(featuremgmt.FlagKubernetesAuthnMutation)
|
||||
|
||||
builder := &IdentityAccessManagementAPIBuilder{
|
||||
store: store,
|
||||
userLegacyStore: user.NewLegacyStore(store, accessClient, enableAuthnMutation),
|
||||
saLegacyStore: serviceaccount.NewLegacyStore(store, accessClient, enableAuthnMutation),
|
||||
legacyTeamStore: team.NewLegacyStore(store, legacyAccessClient, enableAuthnMutation),
|
||||
teamBindingLegacyStore: teambinding.NewLegacyBindingStore(store, enableAuthnMutation),
|
||||
ssoLegacyStore: sso.NewLegacyStore(ssoService),
|
||||
coreRolesStorage: coreRolesStorage,
|
||||
rolesStorage: rolesStorage,
|
||||
resourcePermissionsStorage: resourcepermission.ProvideStorageBackend(dbProvider),
|
||||
@@ -93,7 +100,6 @@ func RegisterAPIService(
|
||||
reg: reg,
|
||||
logger: log.New("iam.apis"),
|
||||
features: features,
|
||||
enableDualWriter: true,
|
||||
dual: dual,
|
||||
unified: unified,
|
||||
userSearchClient: resource.NewSearchClient(dualwrite.NewSearchAdapter(dual), iamv0.UserResourceInfo.GroupResource(), unified, user.NewUserLegacySearchClient(userService), features),
|
||||
@@ -113,18 +119,16 @@ func NewAPIService(
|
||||
store := legacy.NewLegacySQLStores(dbProvider)
|
||||
resourcePermissionsStorage := resourcepermission.ProvideStorageBackend(dbProvider)
|
||||
resourceAuthorizer := gfauthorizer.NewResourceAuthorizer(accessClient)
|
||||
noopStorage := noopstorage.ProvideStorageBackend()
|
||||
registerMetrics(reg)
|
||||
return &IdentityAccessManagementAPIBuilder{
|
||||
store: store,
|
||||
display: user.NewLegacyDisplayREST(store),
|
||||
resourcePermissionsStorage: resourcePermissionsStorage,
|
||||
externalGroupMappingStorage: noopStorage,
|
||||
logger: log.New("iam.apis"),
|
||||
features: features,
|
||||
zClient: zClient,
|
||||
zTickets: make(chan bool, MaxConcurrentZanzanaWrites),
|
||||
reg: reg,
|
||||
store: store,
|
||||
display: user.NewLegacyDisplayREST(store),
|
||||
resourcePermissionsStorage: resourcePermissionsStorage,
|
||||
logger: log.New("iam.apis"),
|
||||
features: features,
|
||||
zClient: zClient,
|
||||
zTickets: make(chan bool, MaxConcurrentZanzanaWrites),
|
||||
reg: reg,
|
||||
authorizer: authorizer.AuthorizerFunc(
|
||||
func(ctx context.Context, a authorizer.Attributes) (authorizer.Decision, string, error) {
|
||||
// For now only authorize resourcepermissions resource
|
||||
@@ -183,8 +187,7 @@ func (b *IdentityAccessManagementAPIBuilder) AllowedV0Alpha1Resources() []string
|
||||
|
||||
func (b *IdentityAccessManagementAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver.APIGroupInfo, opts builder.APIGroupOptions) error {
|
||||
storage := map[string]rest.Storage{}
|
||||
//nolint:staticcheck // not yet migrated to OpenFeature
|
||||
enableAuthnMutation := b.features.IsEnabledGlobally(featuremgmt.FlagKubernetesAuthnMutation)
|
||||
|
||||
//nolint:staticcheck // not yet migrated to OpenFeature
|
||||
enableZanzanaSync := b.features.IsEnabledGlobally(featuremgmt.FlagKubernetesAuthzZanzanaSync)
|
||||
|
||||
@@ -197,69 +200,63 @@ func (b *IdentityAccessManagementAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *ge
|
||||
})
|
||||
|
||||
teamResource := iamv0.TeamResourceInfo
|
||||
teamLegacyStore := team.NewLegacyStore(b.store, b.legacyAccessClient, enableAuthnMutation)
|
||||
storage[teamResource.StoragePath()] = teamLegacyStore
|
||||
storage[teamResource.StoragePath("members")] = team.NewLegacyTeamMemberREST(b.store)
|
||||
teamUniStore, err := grafanaregistry.NewRegistryStore(opts.Scheme, teamResource, opts.OptsGetter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
storage[teamResource.StoragePath()] = teamUniStore
|
||||
|
||||
if b.enableDualWriter {
|
||||
teamStore, err := grafanaregistry.NewRegistryStore(opts.Scheme, teamResource, opts.OptsGetter)
|
||||
if b.legacyTeamStore != nil {
|
||||
dw, err := opts.DualWriteBuilder(teamResource.GroupResource(), b.legacyTeamStore, teamUniStore)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
teamDW, err := opts.DualWriteBuilder(teamResource.GroupResource(), teamLegacyStore, teamStore)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
storage[teamResource.StoragePath()] = teamDW
|
||||
storage[teamResource.StoragePath()] = dw
|
||||
}
|
||||
|
||||
storage[teamResource.StoragePath("members")] = team.NewLegacyTeamMemberREST(b.store)
|
||||
|
||||
teamBindingResource := iamv0.TeamBindingResourceInfo
|
||||
teamBindingLegacyStore := teambinding.NewLegacyBindingStore(b.store, enableAuthnMutation)
|
||||
storage[teamBindingResource.StoragePath()] = teamBindingLegacyStore
|
||||
teamBindingUniStore, err := grafanaregistry.NewRegistryStore(opts.Scheme, teamBindingResource, opts.OptsGetter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
storage[teamBindingResource.StoragePath()] = teamBindingUniStore
|
||||
|
||||
if b.enableDualWriter {
|
||||
teamBindingStore, err := grafanaregistry.NewRegistryStore(opts.Scheme, teamBindingResource, opts.OptsGetter)
|
||||
// Only teamBindingStore exposes the AfterCreate, AfterDelete, and BeginUpdate hooks
|
||||
if enableZanzanaSync {
|
||||
b.logger.Info("Enabling hooks for TeamBinding to sync to Zanzana")
|
||||
teamBindingUniStore.AfterCreate = b.AfterTeamBindingCreate
|
||||
teamBindingUniStore.AfterDelete = b.AfterTeamBindingDelete
|
||||
teamBindingUniStore.BeginUpdate = b.BeginTeamBindingUpdate
|
||||
}
|
||||
|
||||
if b.teamBindingLegacyStore != nil {
|
||||
dw, err := opts.DualWriteBuilder(teamBindingResource.GroupResource(), b.teamBindingLegacyStore, teamBindingUniStore)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
teamBindingDW, err := opts.DualWriteBuilder(teamBindingResource.GroupResource(), teamBindingLegacyStore, teamBindingStore)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Only teamBindingStore exposes the AfterCreate, AfterDelete, and BeginUpdate hooks
|
||||
if enableZanzanaSync {
|
||||
b.logger.Info("Enabling hooks for TeamBinding to sync to Zanzana")
|
||||
teamBindingStore.AfterCreate = b.AfterTeamBindingCreate
|
||||
teamBindingStore.AfterDelete = b.AfterTeamBindingDelete
|
||||
teamBindingStore.BeginUpdate = b.BeginTeamBindingUpdate
|
||||
}
|
||||
|
||||
storage[teamBindingResource.StoragePath()] = teamBindingDW
|
||||
storage[teamBindingResource.StoragePath()] = dw
|
||||
}
|
||||
|
||||
// User store registration
|
||||
userResource := iamv0.UserResourceInfo
|
||||
legacyStore := user.NewLegacyStore(b.store, b.accessClient, enableAuthnMutation)
|
||||
storage[userResource.StoragePath()] = legacyStore
|
||||
userUniStore, err := grafanaregistry.NewRegistryStore(opts.Scheme, userResource, opts.OptsGetter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
storage[userResource.StoragePath()] = userUniStore
|
||||
|
||||
if b.enableDualWriter {
|
||||
store, err := grafanaregistry.NewRegistryStore(opts.Scheme, userResource, opts.OptsGetter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if enableZanzanaSync {
|
||||
b.logger.Info("Enabling hooks for User to sync basic role assignments to Zanzana")
|
||||
userUniStore.AfterCreate = b.AfterUserCreate
|
||||
userUniStore.BeginUpdate = b.BeginUserUpdate
|
||||
userUniStore.AfterDelete = b.AfterUserDelete
|
||||
}
|
||||
|
||||
if enableZanzanaSync {
|
||||
b.logger.Info("Enabling hooks for User to sync basic role assignments to Zanzana")
|
||||
store.AfterCreate = b.AfterUserCreate
|
||||
store.BeginUpdate = b.BeginUserUpdate
|
||||
store.AfterDelete = b.AfterUserDelete
|
||||
}
|
||||
|
||||
dw, err := opts.DualWriteBuilder(userResource.GroupResource(), legacyStore, store)
|
||||
if b.userLegacyStore != nil {
|
||||
dw, err := opts.DualWriteBuilder(userResource.GroupResource(), b.userLegacyStore, userUniStore)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -270,50 +267,46 @@ func (b *IdentityAccessManagementAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *ge
|
||||
storage[userResource.StoragePath("teams")] = user.NewLegacyTeamMemberREST(b.store)
|
||||
|
||||
// Service Accounts store registration
|
||||
serviceAccountResource := iamv0.ServiceAccountResourceInfo
|
||||
saLegacyStore := serviceaccount.NewLegacyStore(b.store, b.accessClient, enableAuthnMutation)
|
||||
storage[serviceAccountResource.StoragePath()] = saLegacyStore
|
||||
|
||||
if b.enableDualWriter {
|
||||
store, err := grafanaregistry.NewRegistryStore(opts.Scheme, serviceAccountResource, opts.OptsGetter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dw, err := opts.DualWriteBuilder(serviceAccountResource.GroupResource(), saLegacyStore, store)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
storage[serviceAccountResource.StoragePath()] = dw
|
||||
}
|
||||
|
||||
storage[serviceAccountResource.StoragePath("tokens")] = serviceaccount.NewLegacyTokenREST(b.store)
|
||||
|
||||
if b.sso != nil {
|
||||
ssoResource := legacyiamv0.SSOSettingResourceInfo
|
||||
storage[ssoResource.StoragePath()] = sso.NewLegacyStore(b.sso)
|
||||
}
|
||||
|
||||
externalGroupMappingResource := iamv0.ExternalGroupMappingResourceInfo
|
||||
externalGroupMappingLegacyStore, err := NewLocalStore(externalGroupMappingResource, apiGroupInfo.Scheme, opts.OptsGetter, b.reg, b.accessClient, b.externalGroupMappingStorage)
|
||||
saResource := iamv0.ServiceAccountResourceInfo
|
||||
saUniStore, err := grafanaregistry.NewRegistryStore(opts.Scheme, saResource, opts.OptsGetter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
storage[externalGroupMappingResource.StoragePath()] = externalGroupMappingLegacyStore
|
||||
storage[saResource.StoragePath()] = saUniStore
|
||||
|
||||
if b.enableDualWriter {
|
||||
externalGroupMappingStore, err := grafanaregistry.NewRegistryStore(opts.Scheme, externalGroupMappingResource, opts.OptsGetter)
|
||||
if b.saLegacyStore != nil {
|
||||
dw, err := opts.DualWriteBuilder(saResource.GroupResource(), b.saLegacyStore, saUniStore)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
storage[saResource.StoragePath()] = dw
|
||||
}
|
||||
|
||||
storage[saResource.StoragePath("tokens")] = serviceaccount.NewLegacyTokenREST(b.store)
|
||||
|
||||
if b.ssoLegacyStore != nil {
|
||||
ssoResource := legacyiamv0.SSOSettingResourceInfo
|
||||
storage[ssoResource.StoragePath()] = b.ssoLegacyStore
|
||||
}
|
||||
|
||||
extGroupMappingResource := iamv0.ExternalGroupMappingResourceInfo
|
||||
extGroupMappingUniStore, err := grafanaregistry.NewRegistryStore(opts.Scheme, extGroupMappingResource, opts.OptsGetter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
storage[extGroupMappingResource.StoragePath()] = extGroupMappingUniStore
|
||||
|
||||
if b.externalGroupMappingStorage != nil {
|
||||
extGroupMappingLegacyStore, err := NewLocalStore(extGroupMappingResource, apiGroupInfo.Scheme, opts.OptsGetter, b.reg, b.accessClient, b.externalGroupMappingStorage)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
externalGroupMappingDW, err := opts.DualWriteBuilder(externalGroupMappingResource.GroupResource(), externalGroupMappingLegacyStore, externalGroupMappingStore)
|
||||
dw, err := opts.DualWriteBuilder(extGroupMappingResource.GroupResource(), extGroupMappingLegacyStore, extGroupMappingUniStore)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
storage[externalGroupMappingResource.StoragePath()] = externalGroupMappingDW
|
||||
storage[extGroupMappingResource.StoragePath()] = dw
|
||||
}
|
||||
|
||||
//nolint:staticcheck // not yet migrated to OpenFeature
|
||||
@@ -351,7 +344,7 @@ func (b *IdentityAccessManagementAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *ge
|
||||
}
|
||||
//nolint:staticcheck // not yet migrated to OpenFeature
|
||||
if b.features.IsEnabledGlobally(featuremgmt.FlagKubernetesAuthzResourcePermissionApis) {
|
||||
if err := b.UpdateResourcePermissionsAPIGroup(apiGroupInfo, opts, storage, b.enableDualWriter, enableZanzanaSync); err != nil {
|
||||
if err := b.UpdateResourcePermissionsAPIGroup(apiGroupInfo, opts, storage, enableZanzanaSync); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -364,11 +357,19 @@ func (b *IdentityAccessManagementAPIBuilder) UpdateResourcePermissionsAPIGroup(
|
||||
apiGroupInfo *genericapiserver.APIGroupInfo,
|
||||
opts builder.APIGroupOptions,
|
||||
storage map[string]rest.Storage,
|
||||
enableDualWriter bool,
|
||||
enableZanzanaSync bool,
|
||||
) error {
|
||||
var store rest.Storage
|
||||
// Create the legacy store first
|
||||
uniStore, err := grafanaregistry.NewRegistryStore(opts.Scheme, iamv0.ResourcePermissionInfo, opts.OptsGetter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
storage[iamv0.ResourcePermissionInfo.StoragePath()] = uniStore
|
||||
|
||||
if b.resourcePermissionsStorage == nil {
|
||||
// No legacy storage configured, nothing more to do
|
||||
return nil
|
||||
}
|
||||
|
||||
legacyStore, err := NewLocalStore(iamv0.ResourcePermissionInfo, apiGroupInfo.Scheme, opts.OptsGetter, b.reg, b.accessClient, b.resourcePermissionsStorage)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -384,23 +385,12 @@ func (b *IdentityAccessManagementAPIBuilder) UpdateResourcePermissionsAPIGroup(
|
||||
legacyStore.AfterDelete = b.AfterResourcePermissionDelete
|
||||
}
|
||||
|
||||
// Set the default store to the legacy store
|
||||
store = legacyStore
|
||||
|
||||
if enableDualWriter {
|
||||
// Create the dual write store (UniStore + LegacyStore)
|
||||
uniStore, err := grafanaregistry.NewRegistryStore(apiGroupInfo.Scheme, iamv0.ResourcePermissionInfo, opts.OptsGetter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
store, err = opts.DualWriteBuilder(iamv0.ResourcePermissionInfo.GroupResource(), legacyStore, uniStore)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dw, err := opts.DualWriteBuilder(iamv0.ResourcePermissionInfo.GroupResource(), legacyStore, uniStore)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
storage[iamv0.ResourcePermissionInfo.StoragePath()] = store
|
||||
storage[iamv0.ResourcePermissionInfo.StoragePath()] = dw
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user