# 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.

```text
how to audit Kubernetes RBAC with kubectl
```

## Use 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.

```bash
kubectl get roles,clusterroles -A
kubectl get rolebindings,clusterrolebindings -A
```

Expected: 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.

```bash
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.

```bash
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.

```bash
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.

```bash
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 `--as` impersonation 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
