📋 What Is It?
Overly Permissive RBAC is the failure mode where Roles and ClusterRoles grant an identity far more than it needs. RBAC is additive and allow-only - there are no deny rules, so every permission granted stays granted until a binding is removed. A single over-broad rule - a wildcard verb, cluster-admin bound to a ServiceAccount, or broad Secret access - turns one compromised container into full control of the cluster. Because the flaw lives in YAML, it is invisible to code review and survives every redeploy.
K03
OWASP Rank
Authorization
Focus Area
Medium
To Prevent
⚠️ Common Exploits
- Token Read + Enumerate: Read the mounted SA token, then
kubectl auth can-i --listto map the escalation surface - Cluster-Wide Secret Read:
get/liston Secrets harvests every credential, including other SAs' tokens - Pod Creation:
createon Pods schedules a Pod running as a more privileged SA to steal its token - escalate / bind: Self-grant wildcard rules or bind yourself to
cluster-adminin one command - impersonate: Act as any user, group, or SA - including the RBAC-bypassing
system:masters - pods/exec: Run commands inside existing privileged containers to inherit their identity
- TokenRequest:
createonserviceaccounts/tokenmints fresh tokens for stronger identities
🔴 Attack Flow
1. Obtain identity: read mounted SA token from a Pod
↓
2. Enumerate:
↓
3. Find primitive: secrets, create pods, escalate/bind
↓
4. Escalate: mint/steal a higher-privileged token
↓
5. IMPACT: Bind to cluster-admin - full takeover!
↓
2. Enumerate:
kubectl auth can-i --list↓
3. Find primitive: secrets, create pods, escalate/bind
↓
4. Escalate: mint/steal a higher-privileged token
↓
5. IMPACT: Bind to cluster-admin - full takeover!
❌ Vulnerable Code
# Bad: "give it everything so it works" ClusterRole, bound cluster-wide
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: app-superpowers
rules:
- apiGroups: ["*"] # every API group, including future CRDs
resources: ["*"] # pods, secrets, nodes, rolebindings, ...
verbs: ["*"] # get, create, delete, escalate, bind, impersonate
---
kind: ClusterRoleBinding
metadata:
name: app-superpowers-binding
subjects:
- kind: ServiceAccount
name: payments-api
namespace: payments
roleRef:
kind: ClusterRole
name: app-superpowers
# Effect: this ServiceAccount is cluster-admin. One RCE = full takeover.
# Bad: cluster-admin bound to a CI ServiceAccount token living in a Pod
roleRef: { kind: ClusterRole, name: cluster-admin }
# Bad: binding to "default" leaks the grant to EVERY pod in the namespace
subjects: [ { kind: ServiceAccount, name: default, namespace: apps } ]
✅ Secure Code
# Good: only the verbs and resources this app actually uses, in its namespace
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: payments-api-role
namespace: payments
rules:
- apiGroups: [""] # core group only
resources: ["configmaps"]
resourceNames: ["payments-config"] # a single named object
verbs: ["get", "list", "watch"] # read-only, no create/delete
---
kind: RoleBinding # namespaced, not ClusterRoleBinding
metadata:
name: payments-api-binding
namespace: payments
subjects:
- kind: ServiceAccount
name: payments-api # dedicated SA, not "default"
namespace: payments
roleRef:
kind: Role
name: payments-api-role
# Good: read ONE named secret with get (not list, which ignores names)
resources: ["secrets"]
resourceNames: ["payments-db-credentials"]
verbs: ["get"]
# Good: disable token automount where the API is not called
automountServiceAccountToken: false
✓ Prevention Checklist
- No
*inverbs,resources, orapiGroupsfor any custom role - Never bind
cluster-adminto a ServiceAccount or a wide group - Give every workload a dedicated SA; leave
defaultunused and unbound - Set
automountServiceAccountToken: falsewherever the API isn't called - Grant
escalate/bind/impersonateonly to reviewed infra identities - Scope Secret access by namespace and, where feasible,
resourceNames - Prefer namespaced Roles unless the resource is genuinely cluster-scoped
- Enforce admission policy that rejects wildcard rules and dangerous bindings
- Run
kubectl auth can-iallow/deny assertions in CI - Audit RBAC on a schedule (rbac-tool, kubectl-who-can, KubiScan) with alerting
- Enable API server audit logging; alert on new admin bindings and impersonation
🔍 Detection & Tools
RBAC Auditors:
kubectl auth can-i
kubectl-who-can
rbac-tool
KubiScan
kubescape
kube-bench
Admission Enforcement:
Kyverno
OPA/Gatekeeper
ValidatingAdmissionPolicy
How to Test:
- Enumerate as a SA:
kubectl auth can-i --list --as=system:serviceaccount:ns:sa - Probe:
kubectl auth can-i '*' '*' --all-namespaces --as=$SA - Find admin bindings:
kubectl get clusterrolebindings -o json | jq ...cluster-admin - Find wildcard rules across roles with a jq filter on
* - Ask who can act:
kubectl who-can list secrets/create clusterrolebindings
🌍 Real-World
- Compromised Pod to cluster-admin via a bound role: An app SA with cluster-wide
secrets [get,list]plus a CI token stored as a Secret lets one RCE harvest the CI token and authenticate as cluster-admin. - escalate/bind self-promotion: An operator SA given
bindon clusterrolebindings andescalateon clusterroles can create a binding tying its own identity to cluster-admin - the escalation-prevention check no longer applies. - Over-permissioned default ServiceAccount: Binding a broad
editrole todefaultin a shared namespace silently gives every Pod - including internet-facing ones - the ability to create Pods and read Secrets. - Note: These are described as incident classes. Over-broad RBAC is common, cheap to find with
kubectl auth can-i, and devastating when chained from a single foothold; the takeaway is the mechanism, not a statistic.
📌 Quick Tips
- DO NOT use
*in verbs, resources, or apiGroups - DO NOT bind
cluster-adminto a ServiceAccount - DO NOT bind roles to
defaultorsystem:authenticated - DO grant the minimum verbs on named resources
- DO use a dedicated SA per workload
- DO guard escalate / bind / impersonate
- DO audit RBAC continuously and alert on changes
📜 Compliance
Related Standards:
- CIS Kubernetes Benchmark - RBAC & Service Accounts
- NSA/CISA Kubernetes Hardening - Authorization
- NIST 800-53 AC-6 - Least Privilege
- SOC 2 CC6.1 - Logical Access
- PCI-DSS Requirement 7 - Restrict Access