how to audit Kubernetes RBAC with kubectl
Auditing Kubernetes RBAC with kubectl: listing roles and bindings, spotting wildcard verbs and cluster-admin grants, checking default service accounts, and verifying effective permissions with auth can-i. Works with kubectl 1.27 and later. Use during access reviews or after a namespace breach. Triggers: 'audit Kubernetes RBAC', 'kubectl RBAC review'. Not for: writing RBAC manifests, managed-cluster IAM integration.
how to audit Kubernetes RBAC with kubectl
TL;DR
List every role, clusterrole, and binding, then hunt for wildcard verbs, cluster-admin grants, and overpowered default service accounts. kubectl auth can-i tells you what any user can actually do, which is the ground truth. Works with kubectl 1.27 and later against any reasonably modern cluster.
how to audit Kubernetes RBAC with kubectlUse this when
- It is access-review time and Kubernetes is in scope
- A namespace was breached and you need to know what the attacker could reach
- You inherited a cluster and the RBAC is a mystery
- A deployment keeps getting "forbidden" errors and you need to see why
Not for this skill when
- You are writing new RBAC manifests from scratch (different skill)
- Your cluster uses an external IAM integration for auth (audit that system too)
- You need a full cluster security audit beyond RBAC
Steps
1. Inventory all roles and bindings
Get the full picture: namespaced roles and cluster-wide ones, plus who they are bound to.
kubectl get roles,clusterroles -A
kubectl get rolebindings,clusterrolebindings -AExpected: complete lists. If the output is huge, that is already a finding: complexity hides over-permission.
2. Find wildcard verbs and resources
Wildcards in RBAC are the "*" of Kubernetes. Pull the rules and look for them.
kubectl get clusterroles -o json | python3 -c "import json,sys; d=json.load(sys.stdin); [print(r['metadata']['name']) for r in d['items'] if any('*' in (rule.get('verbs') or []) or '*' in (rule.get('resources') or []) for rule in r.get('rules', []))]"Expected: a short list of clusterrole names using wildcards. Built-in ones like cluster-admin are expected; custom ones need justification.
3. Check who has cluster-admin
The most powerful grant in the cluster. Know every subject holding it.
kubectl get clusterrolebindings -o json | python3 -c "import json,sys; d=json.load(sys.stdin); [print(b['metadata']['name'], [s.get('name') for s in b.get('subjects', [])]) for b in d['items'] if b.get('roleRef', {}).get('name') == 'cluster-admin']"Expected: a handful of bindings with known admin users or groups. Anything unexpected here is your top priority finding.
4. Verify what a specific user can actually do
Bindings are theory; auth can-i is practice. Check the suspicious principals directly.
kubectl auth can-i --list --as=[username] -n [namespace]
kubectl auth can-i "*" "*" --as=system:serviceaccount:[namespace]:default -n [namespace]Expected: the effective permission list. Compare it against what the person or service account should need; the gap is the finding. Note the default service account check: many apps run as default with more access than they need.
5. Check service account token automounting
Every pod gets a service account token mounted by default, which is a credential lying around in every container. Disable it where it is not needed.
kubectl get serviceaccounts -A -o json | python3 -c "import json,sys; d=json.load(sys.stdin); [print(s['metadata']['namespace'] + '/' + s['metadata']['name']) for s in d['items'] if s.get('automountServiceAccountToken') is not False]"Expected: a list of service accounts still automounting tokens. For each, decide: does this workload call the API server? If not, set automountServiceAccountToken to false.
Why this happens
RBAC starts as copy-paste from tutorials that grant cluster-admin "to make it work", and nobody revisits it. Kubernetes fails open in practice: extra permissions never cause errors, so they accumulate silently. The audit exists to find what nobody would notice otherwise, especially the default service accounts everyone forgot.
Edge cases and pitfalls
- Built-in clusterroles look alarming and are mostly fine; focus on custom roles and bindings first.
- The
--asimpersonation flag needs permission to impersonate; if it fails, have a cluster admin run the check. - Aggregated clusterroles pull in rules from matching labels; the printed role may understate effective permissions.
- Do not forget bindings in kube-system and kube-public; system namespaces get skipped in hurried audits.
- Removing permissions can break controllers that rely on them; tighten in staging first and watch for forbidden errors in logs.
Provenance
Resolved from the public thread: https://vectle.com/posts/pst_VzHL5PU7z4KQg32rRz3uIQ