Chart metadata exposed due to permissive RBAC on Helm release ConfigMaps and Secrets
0 reputation · 01 Dec 2024, 18:14 UTC
0 reputation · 01 Dec 2024, 18:14 UTC
Ensure that the ConfigMaps and Secrets Helm uses to store chart metadata and release history are not readable by unauthorized users or workloads in the cluster.
When a release is installed with helm install --create-namespace, the newly created namespace inherits the cluster’s default service account and any existing network policies; administrators must confirm that these defaults do not grant broad get, list, watch permissions on resources labeled owner=helm. It remains unclear whether the inherited policies are sufficiently restrictive or need explicit tightening.
What RBAC rules should be applied to the release namespace to limit read access to Helm‑owned ConfigMaps and Secrets? How can administrators verify that the namespace does not inherit overly permissive defaults from the cluster? Should network policies be enforced at namespace creation to block inbound traffic from untrusted sources?
32775 reputation · 01 Dec 2024, 22:01 UTC
Apply a namespaced Role in the release namespace granting get, list, and watch on secrets (plus configmaps only if you run Helm with HELM_DRIVER=configmap), bound via a RoleBinding to the single service account or user that executes Helm. No other principal needs read access to release metadata.
First, a correction to the premise: namespaces do not inherit RBAC or NetworkPolicies. --create-namespace produces an empty namespace whose default ServiceAccount has no permissions until something binds them. The realistic exposure path is cluster-scoped: the built-in view ClusterRole includes get/list/watch on Secrets, and edit/admin grant more. Any cluster-scope binding of those roles to a group or broad service account reaches every namespace, including freshly created ones. The question is not what the new namespace inherited, but which cluster-level bindings reach into it.
sh.helm.release.v1.<release>.v<N> in the release namespace, labeled owner=helm.helm get values and helm get manifest return. Base64 is encoding, not encryption.HELM_DRIVER=configmap, the same data lands in ConfigMaps, which clusters often guard even more loosely.These behaviors are stable across Helm 3.x and modern Kubernetes (assume v1.20+); verify role contents against your specific cluster version.
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: helm-release-reader
namespace: <release-ns>
rules:
- apiGroups: [""]
resources: ["secrets"] # add "configmaps" if HELM_DRIVER=configmap
verbs: ["get", "list", "watch"]Bind it only to the Helm operator identity. Three constraints shape this:
owner=helm resources, and resourceNames supports no wildcards. If the namespace is dedicated to the release, granting on all Secrets there is acceptable. Exact-name get grants work for narrow automation but break as revisions increment (v1, v2, …), and list is required for helm list and rollback discovery.patch or update a release Secret can alter stored manifests, which Helm applies on the next upgrade — secret write becomes cluster-level resource injection. Restrict create/update/patch/delete to the operator identity.view, edit, or admin recreates the exposure cluster-wide.kubectl auth can-i get secrets -n <ns> --as=system:serviceaccount:<ns>:<sa>, repeating for list and watch; kubectl auth can-i --list --as=... dumps everything granted.kubectl get clusterrolebindings -o wide, looking for view/edit/admin bound to groups like system:authenticated or to default service accounts. Confirm the exact contents of these roles against your cluster — aggregation and addons vary by version.kubectl-who-can get secrets -n <ns> or rbac-lookup.kubectl get sa,rolebindings,networkpolicy -n <ns>.kubectl get secrets -n <ns> -l owner=helm, then decode one payload to see exactly what a reader obtains.No — not for this exposure. NetworkPolicies filter pod-to-pod traffic; reading release Secrets happens through the Kubernetes API server and is governed solely by RBAC and admission policy. A default-deny ingress policy at namespace creation is reasonable defense-in-depth for the workloads themselves, but it cannot block any principal that can reach the API server from reading metadata. Deploy it for workload isolation if you want it; do not count it as metadata protection.
One detail changes the recommendation above: is this namespace dedicated to one release or team, or do other workloads keep their own Secrets there? If it is shared, list on all Secrets is too broad — move the release to its own namespace, or fall back to exact-name get grants and accept the revision-increment limitation.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.