From f23fc5f03c105f62c67258c418555bd89596c7ed Mon Sep 17 00:00:00 2001 From: Mukul Sharma Date: Sat, 5 Sep 2026 01:49:49 +0530 Subject: [PATCH] deployer: permission to manage app configuration Secrets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Environment variables are delivered through a Secret so values never appear in the pod spec, but the ClusterRole was never given the resource — so every deploy with configuration failed on a forbidden error, minutes after the change looked fine. Granted without list or watch. Kubernetes RBAC cannot scope a ClusterRole to a namespace pattern, so this necessarily covers every namespace; withholding list at least stops deployer enumerating the cluster's secrets, leaving only access by a name it already knows. That narrows the blast radius rather than removing it, and is called out in the manifest. The proper fix, once there are tenants who are not the operator, is a RoleBinding created per app namespace. That requires deployer to be able to create RoleBindings, which is its own escalation path and wants deciding deliberately rather than being slipped in here. --- extra-manifests/toolshed-deployer-rbac.yaml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/extra-manifests/toolshed-deployer-rbac.yaml b/extra-manifests/toolshed-deployer-rbac.yaml index 870a2d9..7137f70 100644 --- a/extra-manifests/toolshed-deployer-rbac.yaml +++ b/extra-manifests/toolshed-deployer-rbac.yaml @@ -31,6 +31,23 @@ rules: - apiGroups: [""] resources: ["services", "resourcequotas"] verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] + # An app's configuration, delivered as a Secret so values never appear in + # the pod spec. + # + # Deliberately without list or watch. Kubernetes RBAC cannot scope a + # ClusterRole to a namespace pattern, so this necessarily covers every + # namespace — but without list, deployer cannot enumerate the cluster's + # secrets, only address ones by a name it already knows. That narrows the + # blast radius without removing it: get on a known name still reaches any + # secret in the cluster. + # + # The proper fix, when this has tenants who are not the operator, is a + # RoleBinding created per app namespace instead of one ClusterRole. That + # needs deployer to hold permission to create RoleBindings, which is its + # own escalation path and wants thinking about rather than adding here. + - apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "create", "update", "patch", "delete"] # Read-only. Pods are listed to report why a rollout failed, never changed. - apiGroups: [""] resources: ["pods"]