Skip to content

⚠️ (helm/v2-plugin): enhance RBAC support with namespace-scoped deployments, multi-namespace configuration, and dynamic Role/ClusterRole rendering (rename rbacHelpers to rbac.helpers)#5579

Open
camilamacedo86 wants to merge 1 commit intokubernetes-sigs:masterfrom
camilamacedo86:helm-rbac-roles

Conversation

@camilamacedo86
Copy link
Copy Markdown
Member

@camilamacedo86 camilamacedo86 commented Apr 2, 2026

This PR introduces two new RBAC configuration options to the Helm v2-alpha plugin.

1. rbac.namespaced — Namespace-scoped operator deployments

Allows switching between cluster-wide and namespace-scoped RBAC.

Example values:

rbac:
  namespaced: true  # Uses Role/RoleBinding instead of ClusterRole/ClusterRoleBinding

Example install:
helm install my-operator ./dist/chart --set rbac.namespaced=true

2. rbac.roleNamespaces — Multi-namespace RBAC

Enables deploying Roles and RoleBindings into specific namespaces using kubebuilder annotations.

Example annotations:

// +kubebuilder:rbac:groups=apps,namespace=infrastructure,resources=deployments,verbs=get;list;watch
// +kubebuilder:rbac:groups="",namespace=users,resources=secrets,verbs=get;list;watch

Generated values:

rbac:
  roleNamespaces:
    manager-role-infrastructure: infrastructure
    manager-role-users: users

Override at install:

helm install my-operator ./dist/chart \
  --set 'rbac.roleNamespaces[manager-role-infrastructure]=prod-infra'

Breaking Change

RBAC values structure has changed:

Before:

rbacHelpers:
  enable: false

After:

rbac:
  helpers:
    enable: false

Closes:

Partially: #5517

@k8s-ci-robot k8s-ci-robot added approved Indicates a PR has been approved by an approver from all required OWNERS files. size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. labels Apr 2, 2026
@camilamacedo86 camilamacedo86 changed the title chore(helm/v2-alpha): Add support to install solution as namespaced scope ⚠️ chore(helm/v2-alpha): Add support to install solution as namespaced scope Apr 2, 2026
@camilamacedo86 camilamacedo86 changed the title ⚠️ chore(helm/v2-alpha): Add support to install solution as namespaced scope ⚠️ helm/v2-alpha): Add support to install solution as namespaced scope Apr 2, 2026
@camilamacedo86 camilamacedo86 changed the title ⚠️ helm/v2-alpha): Add support to install solution as namespaced scope ⚠️ (helm/v2-alpha): Add support to install solution as namespaced scope Apr 2, 2026
@camilamacedo86
Copy link
Copy Markdown
Member Author

@Allex1 could you please give a hand on this one?
WDYT?

@camilamacedo86 camilamacedo86 force-pushed the helm-rbac-roles branch 3 times, most recently from 30eb9a4 to 9dfc400 Compare April 2, 2026 21:41
@camilamacedo86
Copy link
Copy Markdown
Member Author

Hi @sam-mcbr could you please help us to validate this one.

@camilamacedo86 camilamacedo86 force-pushed the helm-rbac-roles branch 2 times, most recently from e313e68 to da20941 Compare April 2, 2026 22:31
@sam-mcbr
Copy link
Copy Markdown

sam-mcbr commented Apr 2, 2026

Hi @camilamacedo86! I think this PR looks good. I tested with our deployment and I do see when I remove cluster-scoped RBAC scaffolding it generates a correct ClusterRole/Role (and associated binding) with a Values.yaml that would allow making sure they are rendered as Roles.

I do see this doesn't solve the issue I opened (#5546) where we need both cluster-scoped RBAC and namespace-scoped RBAC (but that seems intended since you didn't mark it as fixed in the description. I only mention this because when both kinds of scaffolds are included, the manager-role.yaml file in the chart only includes the cluster-scoped RBAC and the namespace-scoped RBAC is ignored. I'm assuming this is intentional since this PR doesn't say it addresses the issue I opened 😄

Thanks for the fast improvements to the chart generation!

@camilamacedo86
Copy link
Copy Markdown
Member Author

Hi @sam-mcbr

Thank you a lot for the fast review and for raise this one 🎉
The whole magic is here:

{{- if .Values.rbac.namespaced }}
kind: Role
{{- else }}
kind: ClusterRole
{{- end }}
metadata:
{{- if .Values.rbac.namespaced }}
  namespace: {{ .Release.Namespace }}
{{- end }}

So, we do not need to duplicate the roles. We do that conditionally.
Why that?

WDYT? Does not this solve the scenario?

@sam-mcbr
Copy link
Copy Markdown

sam-mcbr commented Apr 2, 2026

@camilamacedo86 maybe I'm missing something about the changes. To clarify, our use-case is:

We have an operator that monitors CustomResources across a cluster, and then uses those to create/reconcile a single ConfigMap in a single namespace. In the spirit of least-privilege, I was thinking ideally we could have the chart:

  • Deploy a ClusterRole (and binding) for permissions to read, update status, etc. of our CustomResource type and
  • Deploy a Role (and binding) for permissions to read, write, update, etc. ConfigMaps in a single namespace.

Please correct me if I'm misunderstanding the changes in your PR, but to me it looks like the chart only supports either a ClusterRole and binding or a Role and binding. Again, definitely let me know if I'm misunderstanding something!

@camilamacedo86
Copy link
Copy Markdown
Member Author

That is true. So, now I understand better your case. Let me think more about
/hold

@k8s-ci-robot k8s-ci-robot added the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Apr 2, 2026
@camilamacedo86
Copy link
Copy Markdown
Member Author

camilamacedo86 commented Apr 4, 2026

Hi @sam-mcbr

Your issue scenario has no relation with this PR.
We need a new release of controller-tools to address that.
See; #5546 (comment) I provided all info there.

Then that would either work with this one, because the goal here is allow the cluster-admin/consumer of the chart install only using namespaced scoped instead of cluster scoped options.

But I am changing this PR to either cover this specific scenario.
It is a great input. Thank you so much 🎉

@camilamacedo86 camilamacedo86 changed the title ⚠️ (helm/v2-alpha): Add support to install solution as namespaced scope ⚠️ (helm/v2-alpha): Add support to install solution as namespaced scope and multi-namespace solutions. Apr 4, 2026
@k8s-ci-robot k8s-ci-robot added size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. and removed size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. labels Apr 4, 2026
@camilamacedo86 camilamacedo86 changed the title ⚠️ (helm/v2-alpha): Add support to install solution as namespaced scope and multi-namespace solutions. ⚠️ (helm/v2-plugin): enhance RBAC support with namespace-scoped deployments, multi-namespace configuration, and dynamic Role/ClusterRole rendering (rename rbacHelpers to rbac.helpers) Apr 4, 2026
@camilamacedo86 camilamacedo86 removed the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Apr 4, 2026
@camilamacedo86 camilamacedo86 requested a review from Copilot April 5, 2026 04:53
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 53 changed files in this pull request and generated 2 comments.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 53 changed files in this pull request and generated 3 comments.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 53 changed files in this pull request and generated 3 comments.

@camilamacedo86 camilamacedo86 changed the title ⚠️ (helm/v2-plugin): enhance RBAC support with namespace-scoped deployments, multi-namespace configuration, and dynamic Role/ClusterRole rendering (rename rbacHelpers to rbac.helpers) WIP ⚠️ (helm/v2-plugin): enhance RBAC support with namespace-scoped deployments, multi-namespace configuration, and dynamic Role/ClusterRole rendering (rename rbacHelpers to rbac.helpers) Apr 8, 2026
@k8s-ci-robot k8s-ci-robot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Apr 8, 2026
@camilamacedo86 camilamacedo86 requested a review from Copilot April 8, 2026 08:14
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 65 changed files in this pull request and generated 2 comments.

@camilamacedo86 camilamacedo86 requested a review from Copilot April 8, 2026 08:22
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 65 changed files in this pull request and generated 1 comment.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 65 changed files in this pull request and generated no new comments.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 65 changed files in this pull request and generated 1 comment.

@camilamacedo86
Copy link
Copy Markdown
Member Author

Hi @sam-mcbr and @Allex1

Now, it seems good to get merged.
Could you please give a look?

If yes, could you please LGTM this one?
@porridge , if you be able to help with this one would be great either.

@Allex1
Copy link
Copy Markdown

Allex1 commented Apr 8, 2026

/lgtm

thanks for this

@k8s-ci-robot
Copy link
Copy Markdown
Contributor

@Allex1: changing LGTM is restricted to collaborators

Details

In response to this:

/lgtm

thanks for this

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@k8s-ci-robot
Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: Allex1, camilamacedo86

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

detectedPrefix: "test-project",
chartName: "test-project",
managerNamespace: "user", // Short namespace that appears as substring
roleNamespaces: make(map[string]string),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't a nil map work too?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, done

Comment on lines +123 to +124
// Exclude metrics-auth-role which is always cluster-scoped
if !strings.Contains(name, "metrics") {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment does not seem to match the code.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

chartConverter := kustomize.NewChartConverter(resources, namePrefix, chartName, s.outputDir)

// Detect multi-namespace RBAC scenarios.
// Extract manager namespace first to identify which namespaces are "specific"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WDYM by "specific"?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Improved

}
}

// Collect Roles and RoleBindings that deploy to specific namespaces (not manager namespace)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, not manager ns. Perhaps move this definition up?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Improved

…loyments, multi-namespace configuration, and dynamic Role/ClusterRole rendering

Generated-by: Claude
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 65 changed files in this pull request and generated 3 comments.

Comment on lines +1750 to +1757
func (t *HelmTemplater) handleRBACConditionalWrappers(yamlContent, kind, name string) string {
// Distinguish between essential RBAC and helper RBAC
isHelper := strings.Contains(name, "admin-role") || strings.Contains(name, "editor-role") ||
strings.Contains(name, "viewer-role")

// Check for specific Kubebuilder-scaffolded metrics RBAC resources
isMetricsAuthRole := strings.Contains(name, "metrics-auth-role")
isMetricsAuthBinding := strings.Contains(name, "metrics-auth-rolebinding")
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

handleRBACConditionalWrappers classifies RBAC resources as “metrics-related” via strings.Contains(name, "metrics"). Because RBAC resource names include the project prefix, a project whose name/prefix contains metrics (e.g. metrics-operator-manager-role) will be misclassified and wrapped by the metrics conditionals, potentially preventing essential RBAC from being rendered when metrics is disabled. Prefer matching specific known metrics RBAC resource suffixes (e.g., -metrics-auth-role, -metrics-reader, -metrics-auth-rolebinding) or otherwise using a delimiter/suffix-based match rather than a broad substring check.

Copilot uses AI. Check for mistakes.
Comment on lines +1720 to +1744
func (t *HelmTemplater) handleCertificateConditionalWrappers(yamlContent, name string) string {
// Handle different certificate types
isMetricsCert := strings.Contains(name, "metrics-cert") || strings.Contains(name, "metrics")
if isMetricsCert {
// Metrics certificates need certManager, metrics enabled, AND secure metrics (TLS)
// When metrics.secure=false, metrics use HTTP so TLS certs are not needed
return fmt.Sprintf(
"{{- if and .Values.certManager.enable .Values.metrics.enable .Values.metrics.secure }}\n%s{{- end }}\n",
yamlContent)
}
// Other certificates (webhook serving certs) only need certManager enabled
return fmt.Sprintf("{{- if .Values.certManager.enable }}\n%s{{- end }}", yamlContent)
}

// handleServiceConditionalWrappers handles conditional logic for Service resources
func (t *HelmTemplater) handleServiceConditionalWrappers(yamlContent, name string) string {
// Services need conditional logic based on their purpose
if strings.Contains(name, "metrics") {
// Metrics services need metrics enabled
return fmt.Sprintf("{{- if .Values.metrics.enable }}\n%s{{- end }}\n", yamlContent)
}
if strings.Contains(name, "webhook") {
// Webhook services need webhook enabled
return fmt.Sprintf("{{- if .Values.webhook.enable }}\n%s{{- end }}\n", yamlContent)
}
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

handleCertificateConditionalWrappers / handleServiceConditionalWrappers use broad substring checks like strings.Contains(name, "metrics") (and "webhook") to decide conditional wrappers. Since resource names are typically prefixed with the project name, this can misclassify unrelated resources when the project prefix contains those substrings (e.g., metrics-operator-webhook-service would be treated as a metrics Service). Consider switching to suffix- or pattern-based matching for the well-known resource names you intend to target (metrics service, metrics certs, webhook service, etc.).

Copilot uses AI. Check for mistakes.
Comment on lines +119 to +129
// Check if project has cluster-scoped RBAC (ClusterRole resources for business logic).
// By default, Kubebuilder scaffolds metrics-auth-role (for TokenReview/SubjectAccessReview APIs)
// and metrics-reader (for /metrics nonResourceURLs). Both must always remain ClusterRoles as they
// access cluster-scoped APIs. This check identifies whether the project has additional ClusterRoles
// for business logic (e.g., controller permissions), which can optionally be converted to namespace-scoped
// Roles via the rbac.namespaced toggle.
hasClusterScopedRBAC := false
for _, cr := range resources.ClusterRoles {
name := cr.GetName()
// Exclude the specific Kubebuilder-scaffolded metrics roles which are always cluster-scoped
if strings.Contains(name, "metrics-auth-role") || strings.Contains(name, "metrics-reader") {
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hasClusterScopedRBAC detection excludes any ClusterRole whose name contains "metrics". Because ClusterRole names include the project prefix, projects with metrics in their name/prefix will incorrectly be treated as having no cluster-scoped RBAC, which can suppress emitting the rbac.namespaced value/docs. Consider excluding only the specific metrics ClusterRoles (e.g., metrics-auth-role/metrics-reader) using suffix/pattern matches rather than a generic substring.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. helm/v2-alpha size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants