diff --git a/packages/grafana-data/src/types/featureToggles.gen.ts b/packages/grafana-data/src/types/featureToggles.gen.ts index 97f2ba25bcd..31c573480ad 100644 --- a/packages/grafana-data/src/types/featureToggles.gen.ts +++ b/packages/grafana-data/src/types/featureToggles.gen.ts @@ -995,6 +995,10 @@ export interface FeatureToggles { */ kubernetesAuthzApis?: boolean; /** + * Enables create, delete, and update mutations for resources owned by IAM identity + */ + kubernetesAuthnMutation?: boolean; + /** * Enables restore deleted dashboards feature * @default false */ diff --git a/pkg/registry/apis/iam/models.go b/pkg/registry/apis/iam/models.go index 63c74d6ed0e..d4c96edf03a 100644 --- a/pkg/registry/apis/iam/models.go +++ b/pkg/registry/apis/iam/models.go @@ -44,6 +44,9 @@ type IdentityAccessManagementAPIBuilder struct { // Toggle for enabling authz management apis enableAuthZApis bool + // Toggle for enabling authn mutation + enableAuthnMutation bool + // Toggle for enabling dual writer enableDualWriter bool } diff --git a/pkg/registry/apis/iam/register.go b/pkg/registry/apis/iam/register.go index eac9f6340c3..22d15d2e518 100644 --- a/pkg/registry/apis/iam/register.go +++ b/pkg/registry/apis/iam/register.go @@ -56,16 +56,17 @@ func RegisterAPIService( authorizer := newIAMAuthorizer(accessClient, legacyAccessClient) builder := &IdentityAccessManagementAPIBuilder{ - store: store, - coreRolesStorage: coreRolesStorage, - sso: ssoService, - authorizer: authorizer, - legacyAccessClient: legacyAccessClient, - accessClient: accessClient, - display: user.NewLegacyDisplayREST(store), - reg: reg, - enableAuthZApis: features.IsEnabledGlobally(featuremgmt.FlagKubernetesAuthzApis), - enableDualWriter: true, + store: store, + coreRolesStorage: coreRolesStorage, + sso: ssoService, + authorizer: authorizer, + legacyAccessClient: legacyAccessClient, + accessClient: accessClient, + display: user.NewLegacyDisplayREST(store), + reg: reg, + enableAuthZApis: features.IsEnabledGlobally(featuremgmt.FlagKubernetesAuthzApis), + enableAuthnMutation: features.IsEnabledGlobally(featuremgmt.FlagKubernetesAuthnMutation), + enableDualWriter: true, } apiregistration.RegisterAPI(builder) @@ -127,7 +128,7 @@ func (b *IdentityAccessManagementAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *ge storage[teamBindingResource.StoragePath()] = team.NewLegacyBindingStore(b.store) userResource := legacyiamv0.UserResourceInfo - legacyStore := user.NewLegacyStore(b.store, b.legacyAccessClient) + legacyStore := user.NewLegacyStore(b.store, b.legacyAccessClient, b.enableAuthnMutation) storage[userResource.StoragePath()] = legacyStore if b.enableDualWriter { diff --git a/pkg/registry/apis/iam/user/store.go b/pkg/registry/apis/iam/user/store.go index bb4f0458486..c211ece5001 100644 --- a/pkg/registry/apis/iam/user/store.go +++ b/pkg/registry/apis/iam/user/store.go @@ -37,18 +37,19 @@ var ( var resource = iamv0.UserResourceInfo -func NewLegacyStore(store legacy.LegacyIdentityStore, ac claims.AccessClient) *LegacyStore { - return &LegacyStore{store, ac} +func NewLegacyStore(store legacy.LegacyIdentityStore, ac claims.AccessClient, enableAuthnMutation bool) *LegacyStore { + return &LegacyStore{store, ac, enableAuthnMutation} } type LegacyStore struct { - store legacy.LegacyIdentityStore - ac claims.AccessClient + store legacy.LegacyIdentityStore + ac claims.AccessClient + enableAuthnMutation bool } // Update implements rest.Updater. func (s *LegacyStore) Update(ctx context.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error) { - return nil, false, fmt.Errorf("method not yet implemented") + return nil, false, apierrors.NewMethodNotSupported(resource.GroupResource(), "update") } // DeleteCollection implements rest.CollectionDeleter. @@ -58,6 +59,10 @@ func (s *LegacyStore) DeleteCollection(ctx context.Context, deleteValidation res // Delete implements rest.GracefulDeleter. func (s *LegacyStore) Delete(ctx context.Context, name string, deleteValidation rest.ValidateObjectFunc, options *metav1.DeleteOptions) (runtime.Object, bool, error) { + if !s.enableAuthnMutation { + return nil, false, apierrors.NewMethodNotSupported(resource.GroupResource(), "delete") + } + ns, err := request.NamespaceInfoFrom(ctx, true) if err != nil { return nil, false, err @@ -178,6 +183,10 @@ func (s *LegacyStore) Get(ctx context.Context, name string, options *metav1.GetO // Create implements rest.Creater. func (s *LegacyStore) Create(ctx context.Context, obj runtime.Object, createValidation rest.ValidateObjectFunc, options *metav1.CreateOptions) (runtime.Object, error) { + if !s.enableAuthnMutation { + return nil, apierrors.NewMethodNotSupported(resource.GroupResource(), "create") + } + ns, err := request.NamespaceInfoFrom(ctx, true) if err != nil { return nil, err diff --git a/pkg/services/featuremgmt/registry.go b/pkg/services/featuremgmt/registry.go index 8bce171f419..dd1687c386d 100644 --- a/pkg/services/featuremgmt/registry.go +++ b/pkg/services/featuremgmt/registry.go @@ -1715,6 +1715,14 @@ var ( HideFromAdminPage: true, HideFromDocs: true, }, + { + Name: "kubernetesAuthnMutation", + Description: "Enables create, delete, and update mutations for resources owned by IAM identity", + Stage: FeatureStageExperimental, + Owner: identityAccessTeam, + HideFromAdminPage: true, + HideFromDocs: true, + }, { Name: "restoreDashboards", Description: "Enables restore deleted dashboards feature", diff --git a/pkg/services/featuremgmt/toggles_gen.csv b/pkg/services/featuremgmt/toggles_gen.csv index 778164b525b..c851a0edb47 100644 --- a/pkg/services/featuremgmt/toggles_gen.csv +++ b/pkg/services/featuremgmt/toggles_gen.csv @@ -223,6 +223,7 @@ alertingListViewV2PreviewToggle,privatePreview,@grafana/alerting-squad,false,fal alertRuleUseFiredAtForStartsAt,experimental,@grafana/alerting-squad,false,false,false alertingBulkActionsInUI,GA,@grafana/alerting-squad,false,false,true kubernetesAuthzApis,experimental,@grafana/identity-access-team,false,false,false +kubernetesAuthnMutation,experimental,@grafana/identity-access-team,false,false,false restoreDashboards,experimental,@grafana/grafana-frontend-platform,false,false,false skipTokenRotationIfRecent,GA,@grafana/identity-access-team,false,false,false alertEnrichment,experimental,@grafana/alerting-squad,false,false,false diff --git a/pkg/services/featuremgmt/toggles_gen.go b/pkg/services/featuremgmt/toggles_gen.go index 810b1e641cb..43df1d31604 100644 --- a/pkg/services/featuremgmt/toggles_gen.go +++ b/pkg/services/featuremgmt/toggles_gen.go @@ -903,6 +903,10 @@ const ( // Registers AuthZ /apis endpoint FlagKubernetesAuthzApis = "kubernetesAuthzApis" + // FlagKubernetesAuthnMutation + // Enables create, delete, and update mutations for resources owned by IAM identity + FlagKubernetesAuthnMutation = "kubernetesAuthnMutation" + // FlagRestoreDashboards // Enables restore deleted dashboards feature FlagRestoreDashboards = "restoreDashboards" diff --git a/pkg/services/featuremgmt/toggles_gen.json b/pkg/services/featuremgmt/toggles_gen.json index 18fde824fc9..3510eae27df 100644 --- a/pkg/services/featuremgmt/toggles_gen.json +++ b/pkg/services/featuremgmt/toggles_gen.json @@ -1670,6 +1670,23 @@ "requiresRestart": true } }, + { + "metadata": { + "name": "kubernetesAuthnMutation", + "resourceVersion": "1753454405614", + "creationTimestamp": "2025-07-25T14:12:51Z", + "annotations": { + "grafana.app/updatedTimestamp": "2025-07-25 14:40:05.614358 +0000 UTC" + } + }, + "spec": { + "description": "Enables create, delete, and update mutations for resources owned by IAM identity", + "stage": "experimental", + "codeowner": "@grafana/identity-access-team", + "hideFromAdminPage": true, + "hideFromDocs": true + } + }, { "metadata": { "name": "kubernetesAuthzApis", diff --git a/pkg/tests/apis/iam/iam_test.go b/pkg/tests/apis/iam/iam_test.go index 65af0d8e75f..2deaf6a94fd 100644 --- a/pkg/tests/apis/iam/iam_test.go +++ b/pkg/tests/apis/iam/iam_test.go @@ -198,6 +198,7 @@ func TestIntegrationUsers(t *testing.T) { }, EnableFeatureToggles: []string{ featuremgmt.FlagGrafanaAPIServerWithExperimentalAPIs, + featuremgmt.FlagKubernetesAuthnMutation, }, }) doUserCRUDTestsUsingTheNewAPIs(t, helper)