ADR-2647: the operator records events in every namespace through a write-only ClusterRole¶
- Status: Accepted
- Date: 2026-10-08
- Deciders: maintainer, agent
- Tags: helm, rbac, operator, security, k8s, fork-local
Context¶
ADR-1058 split the operator's RBAC into a ClusterRole for its custom resources and a Role in the release namespace for pods, events and leader-election leases. The custom-resource grant is cluster-wide on purpose: the chart has no list of watched namespaces, the operator's controller-runtime cache is not limited to one, and it reconciles VmafxJob, VmafxNode and VmafxModelTraining objects wherever they are created.
The VmafxModelTraining reconciler records an event when a checkpoint is written. client-go's recorder (tools/record, makeEvent) creates the event in the namespace of the object it is about, so for a resource outside the release namespace the API server refused the event: the Role reached only the release namespace. The reconciler logs the refusal and goes on, so nothing failed visibly; the event was lost. The maintainer asked for the grant to follow the chart's namespace model (2026-10-08).
Decision¶
The chart gives the operator's service account a second ClusterRole, <fullname>-operator-events, bound cluster-wide, with create and patch on core events and nothing else; the release-namespace Role keeps pods and leases only. The event grant reaches exactly as far as the custom-resource grant, because an event is written where the resource it describes lives, and it stays write-only: the operator cannot read, list, watch, update or delete events anywhere. The custom-resource ClusterRole stays limited to the custom resources, as ADR-1058 has it.
Alternatives considered¶
| Option | Pros | Cons | Why not chosen |
|---|---|---|---|
A write-only events ClusterRole bound cluster-wide (chosen) | Covers every namespace the operator reconciles; no new values; read access to events stays denied | Cluster-wide write of event records | — |
Add the events rule to the custom-resource ClusterRole | One object less | Mixes a core resource into the role ADR-1058 keeps to the custom resources; the events grant is no longer reviewable on its own | Two separate grants are clearer at the same reach |
A Role and RoleBinding per namespace from a new operator.namespaces list | Event writes limited to listed namespaces | The chart renders into the release namespace only and has no namespace list; the operator still watches every namespace, so objects outside the list would lose their events silently, as before | Needs a namespace model the chart and the operator do not have; would only move the bug |
Keep the release-namespace Role and document the limit | No change | Events of resources in other namespaces stay lost | Leaves the defect |
| Limit the operator to the release namespace | Every grant namespaced | Changes the operator's documented scope and breaks clusters with resources in several namespaces | Out of proportion for an event grant |
Consequences¶
- Positive: checkpoint events of
VmafxModelTrainingresources reach their namespace; leader-election events keep working in the release namespace. - Negative: the operator can create and patch event records in any namespace. It could already reconcile and update its custom resources in any namespace, and it gains no read access.
- Neutral / follow-ups:
scripts/ci/tests/test_helm_service_accounts.pyresolves bindings per namespace and fails when events are granted only in the release namespace, when the grant gains a read verb, or when pods or leases leave the release namespace. ADR-1058's status line points here for the events rule. If the operator ever gets a namespace list, this grant moves to per-namespaceRoles with it.
References¶
- ADR-1058 — the RBAC split this changes for events.
- ADR-1592 — service accounts and the tenant reader.
req(maintainer, via the coordinator, 2026-10-08): "Operator events RBAC: fix now as its own small PR from master — grant event creation where the model-training controller records them, consistent with the chart's tenancy model (ClusterRole vs per-namespace Roles: pick per the chart's existing namespace handling and say why), a test that fails on the current chart, and a docs/state.md row closed by the PR."