Kubernetes RBAC is the authorization layer that determines what subjects (users, groups, service accounts) can do within a cluster. It’s expressive and powerful, but its flexibility means misconfiguration is common — and the consequences of a misconfigured RBAC policy in a multi-tenant cluster or a cloud-hosted Kubernetes service (EKS, AKS, GKE) can be cluster-wide compromise or cloud credential theft.
The RBAC Model: A Quick Orientation
Kubernetes RBAC has four core object types:
- Role — namespaced permission set (rules over resources within one namespace)
- ClusterRole — cluster-wide permission set
- RoleBinding — binds a Role or ClusterRole to subjects within a namespace
- ClusterRoleBinding — binds a ClusterRole to subjects cluster-wide
Rules specify apiGroups, resources, and verbs. The danger lies in how broadly each is defined.
Pitfall 1: Wildcard Rules
The most dangerous single RBAC misconfiguration:
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["*"]
This is equivalent to cluster-admin. It appears in:
- Default service accounts in some older Helm charts
- Developer RBAC copied from examples without pruning
- Emergency access roles never removed after an incident
A less obvious wildcard that’s still dangerous:
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["*"]
verbs: ["*"] on secrets allows listing, reading, creating, and deleting all secrets in scope — this is effectively credential access to every secret in the cluster.
Least-privilege alternative:
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get"]
resourceNames: ["specific-secret-name"]
Use resourceNames to restrict access to specific named resources, and prefer get over list where the application only needs to fetch a specific secret.
Pitfall 2: Overuse of cluster-admin
cluster-admin is the superuser ClusterRole in Kubernetes. It grants all verbs on all resources. Legitimate use cases are narrow: the control plane itself, break-glass emergency access. Common problematic uses:
# Giving a developer broad access
kubectl create clusterrolebinding dev-admin \
--clusterrole=cluster-admin \
--user=developer@company.com
# CI/CD pipeline service account with cluster-admin
kubectl create clusterrolebinding ci-admin \
--clusterrole=cluster-admin \
--serviceaccount=ci-namespace:ci-runner
A compromised CI pipeline with cluster-admin binding can:
- Read all secrets (including cloud credentials and TLS certs)
- Modify admission webhooks to intercept all pod creation
- Create privileged pods to escape to the host node
- Modify RBAC policies to persist access
Audit existing cluster-admin bindings:
kubectl get clusterrolebindings \
-o json | jq -r '.items[] | select(.roleRef.name=="cluster-admin") |
"\(.metadata.name): \(.subjects[]? | "\(.kind)/\(.name)")"'
This one-liner shows every ClusterRoleBinding to cluster-admin and its subjects. Review this list and remove any bindings that aren’t strictly necessary.
Pitfall 3: Automounted Service Account Tokens
By default, Kubernetes mounts a service account token into every pod at /var/run/secrets/kubernetes.io/serviceaccount/token. Any process in the pod can use this token to authenticate to the Kubernetes API server.
# From inside a pod:
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
curl -s -k -H "Authorization: Bearer $TOKEN" \
https://kubernetes.default.svc/api/v1/namespaces/default/secrets
If the pod’s service account has broad RBAC permissions, this token is equivalent to those permissions. Attackers who achieve container escape or exec access into a pod will immediately check for this token.
Disable automount globally on a service account:
apiVersion: v1
kind: ServiceAccount
metadata:
name: myapp-sa
namespace: production
automountServiceAccountToken: false
Disable automount per-pod (overrides service account setting):
spec:
automountServiceAccountToken: false
For applications that don’t need to call the Kubernetes API (most web services, batch jobs, databases), there is no reason to mount the token. Setting automountServiceAccountToken: false on service accounts is a zero-cost hardening step with no application impact.
Pitfall 4: Permissive Pod Security — Privilege Escalation via exec
A ClusterRole that allows pods/exec is more dangerous than it appears:
rules:
- apiGroups: [""]
resources: ["pods/exec"]
verbs: ["create"]
kubectl exec into a privileged pod or a pod running as root is often a path to node compromise. Combined with hostPath mounts or hostPID: true, an exec into any pod on a node can become full host takeover.
Treat pods/exec permissions with the same scrutiny as cluster-admin. If your CI pipeline needs it for debugging, scope it to a specific namespace and add audit logging.
Pitfall 5: Namespace Isolation Failures
A common misconception: creating separate namespaces provides isolation. RBAC provides isolation; namespaces are just a scope boundary. A ClusterRoleBinding to a wide role nullifies namespace boundaries:
# This grants access to ALL namespaces, not just 'dev'
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: developer-binding
subjects:
- kind: User
name: developer@company.com
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole # <-- ClusterRole, not Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
If you want namespace-scoped access, use a RoleBinding (not ClusterRoleBinding), even if the Role or ClusterRole referenced is cluster-scoped.
Detection and Auditing
kube-audit log analysis — enable audit logging and ship to a SIEM. Key events to alert on:
clusterrolebindingsPOST/PUT withcluster-adminroleRefpods/execorpods/portforwardcreate events for production namespacessecretsLIST events from unexpected service accounts
rbac-tool audit:
kubectl krew install rbac-tool
kubectl rbac-tool who-can get secrets -n production
kubectl rbac-tool who-can create clusterrolebindings
who-can shows every subject that has a given permission — invaluable for finding overpermissioned identities.
KubiScan:
python3 KubiScan.py -rba # Enumerate risky role bindings
python3 KubiScan.py -rs # Enumerate risky subjects
Hardening Checklist
- Audit all cluster-admin bindings — remove all except break-glass and control-plane subjects.
- Disable
automountServiceAccountTokenon all service accounts that don’t call the K8s API. - Replace wildcard rules with explicit verb+resource combinations.
- Use
RoleBindingoverClusterRoleBindingwherever possible. - Restrict
pods/execto dedicated debug namespaces; remove from CI service accounts. - Enable Kubernetes Audit Logging and ship to centralized logging.
- Run
kubectl rbac-tool who-can get secretsmonthly and review output. - Use OPA/Gatekeeper or Kyverno to enforce RBAC policies as code, preventing drift.
Sample Kyverno policy to block new cluster-admin bindings:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: restrict-clusteradmin-binding
spec:
validationFailureAction: Enforce
rules:
- name: block-cluster-admin-binding
match:
any:
- resources:
kinds: [ClusterRoleBinding, RoleBinding]
validate:
message: "Binding to cluster-admin is not allowed. Use scoped roles."
deny:
conditions:
any:
- key: "{{ request.object.roleRef.name }}"
operator: Equals
value: cluster-admin
Kubernetes RBAC misconfigurations are among the most commonly exploited issues in managed Kubernetes breach reports. The controls above are not complex — the challenge is maintaining discipline as clusters grow and teams add permissions incrementally without removal hygiene.