From 04d9226de858ab7079c31f5fc646cf83a20d3ca3 Mon Sep 17 00:00:00 2001 From: Camila Macedo <7708031+camilamacedo86@users.noreply.github.com> Date: Wed, 28 Jan 2026 11:18:43 +0000 Subject: [PATCH] Fix namespace-scoped RBAC Role name conflicts with kustomize When using namespace-scoped RBAC markers with different namespaces, controller-gen would generate multiple Roles with the same name in different namespaces. This caused kustomize to fail with "namespace transformation produces ID conflict" when applying a global namespace transformation, as both Roles would end up in the same namespace with identical names. Changes: - Append namespace to Role name for namespace-scoped Roles (e.g., "manager-role-infrastructure" for namespace "infrastructure") - ClusterRoles maintain original name without suffix - Updated documentation to clarify the naming behavior - Added test scenario covering the reported issue with different resource types in different namespaces (apps/deployments in infrastructure namespace, core/secrets in users namespace) This ensures uniqueness when kustomize transforms namespaces, preventing the ID conflict error. --- pkg/rbac/parser.go | 5 +++- pkg/rbac/testdata/controller.go | 2 ++ pkg/rbac/testdata/role.yaml | 39 ++++++++++++++++++++++++++--- pkg/rbac/zz_generated.markerhelp.go | 2 +- 4 files changed, 42 insertions(+), 6 deletions(-) diff --git a/pkg/rbac/parser.go b/pkg/rbac/parser.go index 5ed27a849..059acbb32 100644 --- a/pkg/rbac/parser.go +++ b/pkg/rbac/parser.go @@ -59,6 +59,9 @@ type Rule struct { // Namespace specifies the scope of the Rule. // If not set, the Rule belongs to the generated ClusterRole. // If set, the Rule belongs to a Role, whose namespace is specified by this field. + // The generated Role name will be suffixed with the namespace (e.g., "manager-role-namespace") + // to ensure uniqueness when multiple namespace-scoped Roles are generated. This suffix is + // ONLY applied to namespace-scoped Roles, not to ClusterRoles. Namespace string `marker:",optional"` } @@ -347,7 +350,7 @@ func GenerateRoles(ctx *genall.GenerationContext, roleName string) ([]any, error APIVersion: rbacv1.SchemeGroupVersion.String(), }, ObjectMeta: metav1.ObjectMeta{ - Name: roleName, + Name: fmt.Sprintf("%s-%s", roleName, ns), Namespace: ns, }, Rules: policyRules, diff --git a/pkg/rbac/testdata/controller.go b/pkg/rbac/testdata/controller.go index 984557e50..172eeba6a 100644 --- a/pkg/rbac/testdata/controller.go +++ b/pkg/rbac/testdata/controller.go @@ -37,3 +37,5 @@ package controller // +kubebuilder:rbac:groups=core;"";some-other-to-deduplicate-with-core,resources=me,verbs=list;get // +kubebuilder:rbac:groups=deduplicate-groups5,resources=abc,verbs=get;update;patch;create,namespace=here // +kubebuilder:rbac:groups=deduplicate-groups5,resources=abc,verbs=*,namespace=here +// +kubebuilder:rbac:groups=apps,namespace=infrastructure,resources=deployments,verbs=get;list;watch;update;patch +// +kubebuilder:rbac:groups="",namespace=users,resources=secrets,verbs=get;list;watch diff --git a/pkg/rbac/testdata/role.yaml b/pkg/rbac/testdata/role.yaml index a28e37a92..e603b6148 100644 --- a/pkg/rbac/testdata/role.yaml +++ b/pkg/rbac/testdata/role.yaml @@ -132,7 +132,7 @@ rules: apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: - name: manager-role + name: manager-role-here namespace: here rules: - apiGroups: @@ -145,7 +145,24 @@ rules: apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: - name: manager-role + name: manager-role-infrastructure + namespace: infrastructure +rules: +- apiGroups: + - apps + resources: + - deployments + verbs: + - get + - list + - patch + - update + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: manager-role-park namespace: park rules: - apiGroups: @@ -158,7 +175,22 @@ rules: apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: - name: manager-role + name: manager-role-users + namespace: users +rules: +- apiGroups: + - "" + resources: + - secrets + verbs: + - get + - list + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: manager-role-zoo namespace: zoo rules: - apiGroups: @@ -168,4 +200,3 @@ rules: - jobs verbs: - get - diff --git a/pkg/rbac/zz_generated.markerhelp.go b/pkg/rbac/zz_generated.markerhelp.go index 085898ab5..4fe7b42ea 100644 --- a/pkg/rbac/zz_generated.markerhelp.go +++ b/pkg/rbac/zz_generated.markerhelp.go @@ -82,7 +82,7 @@ func (Rule) Help() *markers.DefinitionHelp { }, "Namespace": { Summary: "specifies the scope of the Rule.", - Details: "If not set, the Rule belongs to the generated ClusterRole.\nIf set, the Rule belongs to a Role, whose namespace is specified by this field.", + Details: "If not set, the Rule belongs to the generated ClusterRole.\nIf set, the Rule belongs to a Role, whose namespace is specified by this field.\nThe generated Role name will be suffixed with the namespace (e.g., \"manager-role-namespace\")\nto ensure uniqueness when multiple namespace-scoped Roles are generated. This suffix is\nONLY applied to namespace-scoped Roles, not to ClusterRoles.", }, }, }