Skip to main content
cd ../config-traps
risk/register/kube-systems-default-sa-bound-to-cluster-admin.html
Kubernetes RBACcritical severityKubernetes

kube-system's Default SA Bound to cluster-admin

Severity
critical
Reviewed
16 Jul 2026
Remediation
~20 minutes
Overview

A cluster-admin ClusterRoleBinding attached to the default service account in kube-system means every pod landing there without an explicit serviceAccountName inherits a live, unscoped API token. RBAC reviews scoped to named accounts miss it entirely, and one compromised kube-system pod becomes full cluster takeover.

Operational summary

At a glance

Symptom
Any kube-system pod without an explicit serviceAccountName inherits the default SA's cluster-admin token via automount.
Likely cause
A ClusterRoleBinding grants the cluster-admin ClusterRole to system:serviceaccount:kube-system:default.
Impact
A single compromised kube-system pod obtains cluster-admin API access, enabling secret theft, privileged pod creation, and RBAC persistence cluster-wide.
Verification signal
Re-run the detection test and a controlled negative-path test.
Safe correction
Delete the offending ClusterRoleBinding, disable automount on the default SA, and enforce named ServiceAccounts with scoped RoleBindings via a Gatekeeper constraint.
Rollback or recovery
Restore the exported configuration if the new control blocks required production traffic, then narrow the policy before redeployment.

The Trap

A ClusterRoleBinding — commonly named permissive-binding or copied from an old Kubernetes Dashboard install guide — binds the cluster-admin ClusterRole to the subject system:serviceaccount:kube-system:default. This exact command still circulates in bootstrap scripts, Helm post-install hooks, and internal wiki pages: kubectl create clusterrolebinding permissive-binding --clusterrole=cluster-admin --serviceaccount=kube-system:default.

The Default State

Engineers add this binding to unblock a stuck dashboard, metrics-server, or CI runner during initial cluster setup, then never remove it. Because the target is the default service account rather than a named one, it doesn’t show up when access reviews grep for specific ServiceAccount names. Combine this with automountServiceAccountToken left at its cluster-wide default of true, and any pod scheduled into kube-system without an explicit serviceAccountName field silently mounts a cluster-admin-capable token at /var/run/secrets/kubernetes.io/serviceaccount.

The Blast Radius

DaemonSets, log shippers, node-exporter sidecars, and misconfigured operator pods routinely land in kube-system and inherit this SA by omission, not by design. A single container escape or dependency CVE inside any of those pods now has an authenticated, cluster-admin bearer token: it can read every Secret in every namespace, create privileged pods on arbitrary nodes, rewrite RBAC to plant persistence, and exfiltrate node kubelet credentials. OPA/Gatekeeper policies written against workload PodSecurity context rarely inspect ClusterRoleBinding subjects, so this path survives PodSecurity admission entirely and only surfaces in a full RBAC subject audit.

The Lead Mechanic Fix

Run kubectl get clusterrolebindings -o json | jq '.items[] | select(.subjects[]?.name=="default" and .subjects[]?.namespace=="kube-system")' to enumerate offending bindings, then kubectl delete clusterrolebinding permissive-binding. Patch the default SA with kubectl patch serviceaccount default -n kube-system -p '{"automountServiceAccountToken": false}'. Require every workload to declare a named, minimally scoped ServiceAccount bound via RoleBinding rather than ClusterRoleBinding, and add a Gatekeeper ConstraintTemplate that denies any ClusterRoleBinding whose subject kind is ServiceAccount with name default. Validate ongoing drift with rbac-lookup 'system:serviceaccount:kube-system:default' in CI.

03

Apply the safer control

Before you change production

Confirm the affected scope, export the current configuration, and test the replacement control in a non-production environment first.

Fix commands and configuration

kubectl get clusterrolebindings -o json | jq '.items[] | select(.subjects[]?.name=="default" and .subjects[]?.namespace=="kube-system")'
kubectl delete clusterrolebinding permissive-binding
kubectl patch serviceaccount default -n kube-system -p '{"automountServiceAccountToken": false}'
04

Verify, roll back or escalate

Verify

Re-run the detection test and a controlled negative-path test. Confirm the unsafe behaviour is blocked while approved traffic still succeeds.

Rollback

Restore the exported configuration if the new control blocks required production traffic, then narrow the policy before redeployment.

Escalate

Escalate when the blast radius is uncertain, the control cannot be tested safely, or remediation requires an outage or security exception.

After remediation

Further reading stays below the corrective workflow and is selected by platform, category and shared technical keywords.

Discover more

Connected KBY resources