fix(rbac): scope configmaps write off the controller namespace — protect state-sync trust root (PLT-471)#406
Conversation
PR SummaryHigh Risk Overview The SeiNode
Legitimate ConfigMap writes in node namespaces (e.g. rbac-proxy, workflow-vars) are expected to come from companion platform per-namespace Roles—those should land before this controller deploy or node-namespace writes will 403. Reviewed by Cursor Bugbot for commit ca766f0. Bugbot is set up for automated code reviews on this repo. Configure here. |
The trust-root ConfigMap sei-controller-config is in the controller's namespace and read via the mounted file, not the API, yet the controller held two configmaps-write paths into that namespace: - the manager-role cluster-wide configmaps CRUD (controller.go marker) -> narrowed to get;list;watch; write is node-namespace-scoped via platform Roles. - a configmaps rule in leader-election-role -> removed (leader election is Lease-based; the grant was unused). Regenerated role.yaml / manifests/role.yaml. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
15dc1a0 to
ca766f0
Compare
What
Closes PLT-471 (controller side): the controller can no longer rewrite its own state-sync trust-root ConfigMap
sei-controller-configvia its ServiceAccount token.The trust root lives in
sei-k8s-controller-systemand is read via the mounted file, not the API — yet the controller held two configmaps-write paths into that namespace:configmapsCRUD (manager-role, from thecontroller.gomarker) → narrowed toget;list;watch(the informer cache needs cluster-wide read; write moves to node namespaces).configmapsCRUD rule inleader-election-role→ deleted. Leader election is Lease-based (controller-runtime default; verified live: leasebc1f5b0a.sei.ioheld, no leader-election ConfigMap), so this grant was dead and was the only remaining configmaps-write path in the controller's namespace.Regenerated
role.yaml/manifests/role.yamlviamake manifests.Why not move the trust root to its own namespace
A pod can only mount a ConfigMap from its own namespace, and the controller reads the trust root via a mount — so it must stay in
sei-k8s-controller-system. In-place scoping (this PR) is the viable path.Companion (required before rollout) — platform per-namespace write Roles
The controller still legitimately writes ConfigMaps in node namespaces (rbac-proxy config, workflow-vars). A follow-up platform-repo PR adds a
Role+RoleBinding(subjectsei-k8s-controller-manager) granting configmaps write in each chain namespace: prod{pacific-1, arctic-1, atlantic-2}, prod-euw1{arctic-1}, prod-use2{arctic-1}, harbor{staging}. Those must reconcile before this controller ref deploys (else node-namespace configmap writes 403 → reconciles wedge) — additive + safe to land first.Security acceptance criteria (from the threat model)
kubectl auth can-i {create,update,patch,delete} configmaps -n sei-k8s-controller-system --as=...:sei-k8s-controller-manager→ no (both holes closed).Verification done
Build clean;
verify-generatedsatisfied (freshmake manifests generateyields no diff); live harbor confirms Lease-based election + SA name + no other configmaps-write SA in the namespace.🤖 Generated with Claude Code