feat: scoped multi-namespace RBAC mode (Role per namespace, no ClusterRole)#1162
Open
michal-marszalek-h2oai wants to merge 1 commit into
Open
Conversation
Add a third RBAC posture between watch-globally (ClusterRole) and single namespace: give Reloader an explicit list of namespaces to watch. The chart creates a namespace-scoped Role + RoleBinding in each listed namespace (no ClusterRole), and one install covers them all. Go: - new --namespaces flag / options.Namespaces - resolveWatchNamespaces() picks list -> KUBERNETES_NAMESPACE -> all - controller creation loops over the watched namespaces - namespaces-to-ignore is now only honored in global mode (watchGlobally=true); in single-namespace and scoped modes the watched set is already explicit Helm: - new reloader.namespaces value (active when watchGlobally=false); accepts either a YAML list or a comma-separated string for consistency with the sibling namespace options - reloader-watchNamespaces helper (release ns always auto-included, deduped) - shared reloader-namespaced-rules template reused per namespace - role.yaml/rolebinding.yaml range over the list; deployment passes --namespaces - --namespaces-to-ignore only rendered when watchGlobally=true - fail guard for watchGlobally=true + namespaces set Tests: unit test for resolveWatchNamespaces; scoped-namespaces e2e case. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This was referenced Jun 26, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds a scoped multi-namespace mode: a third RBAC posture between the existing
watchGlobally: true(cluster-wide, needs aClusterRole) and single-namespace mode. You give Reloader an explicit list of namespaces, and it watches exactly those — with a namespace-scopedRole+RoleBindingcreated in each, noClusterRole, from a single install.Why
Today watching N namespaces means either granting cluster-wide RBAC (
watchGlobally: true) or running N separate Reloader installs. Many clusters (multi-tenant / restricted RBAC) forbidClusterRolegrants, and one-install-per-namespace is wasteful. This closes that gap: one install, scoped permissions, no cluster-scoped objects.How
Helm
reloader.namespacesvalue, active whenwatchGlobally: false. Accepts either a YAML list (["team-a","team-b"]) or a comma-separated string ("team-a,team-b") for consistency withignoreNamespaces/namespaceSelector.role.yaml/rolebinding.yamlrange over the deduped namespace set, emitting oneRole+RoleBindingper namespace. The rule set is factored into a sharedreloader-namespaced-ruleshelper to avoid duplication. The RoleBinding subject is the ServiceAccount in the release namespace (standard cross-namespace binding).deployment.yamlpasses--namespaces=<csv>and omitsKUBERNETES_NAMESPACEin scoped mode.failguard rejects the contradictorywatchGlobally: true+namespacescombination.Binary
--namespacesflag (StringSlice, consistent with the other namespace flags).resolveWatchNamespaces()picks the watched set with precedence:--namespaces→KUBERNETES_NAMESPACE→ all namespaces.--namespaces-to-ignoreis now only honored in global mode (watchGlobally: true); in single-namespace and scoped modes the watched set is already explicit, mirroring how--namespace-selectoris already gated.Backward compatibility
Fully backward compatible. With
reloader.namespacesempty (the default), rendered output is identical to today for bothwatchGlobally: trueandwatchGlobally: false(verified by diffing rendered manifests against the previous templates — the only delta is one cosmetic blank line removed by a cleanerapiVersionblock).Testing
make build,go vet ./...,gofmt— clean.resolveWatchNamespaces(all precedence cases).test/e2e/flags/watch_globally_test.go: reloads in a listed namespace and in the auto-included release namespace; does not reload in an unlisted namespace.helm template/helm lintverified across modes: scoped mode produces aRole+RoleBindingper namespace, zeroClusterRole, correct--namespacesarg; list and string inputs render identically; thefailguard fires on the bad combo.Example: