In-cluster RBAC Forbidden — pod can't call the Kubernetes API
Application logs show 'Forbidden: User cannot get resource pods'
Focused incident mode — strips away everything but this runbook.
Symptoms
- Application logs show 'Forbidden: User cannot get resource pods'
- Kubernetes client inside a pod gets 403 on the in-cluster API
- Works with kubectl locally but not from the pod
Evidence to grab
Collect these artifacts before you change anything — they prove (or rule out) each cause.
Which service account the pod runs under
kubectl get pod <pod> -n <namespace> -o jsonpath='{.spec.serviceAccountName}'Existing bindings
kubectl get rolebinding,clusterrolebinding -n <namespace> | grep <sa-name>
Diagnostic flow
Run the steps in order, marking each claim confirmed or refuted. The evidence you gather feeds the ranked causes below.
Guided decision tree is ready.
Steps with commands, expected output, and pass/fail branches.
Ranked root causes
Evidence checklist
- auth can-i shows 'no' for the required verbs
- No binding exists between SA and a Role granting those verbs
Confirm before fixing
kubectl get rolebindings -n <namespace> -o json | jq '.items[].subjects // empty'Find bindings for the SA
Fix
kubectl create rolebinding <app>-read --clusterrole=view --serviceaccount=<namespace>:<sa-name> -n <namespace>Bind the SA to an appropriate Role/ClusterRole
Expected: rolebinding.rbac.authorization.k8s.io/<app>-read created
Resolution runbook
Apply from top to bottom after the cause is confirmed. Review every command before running it — risk tags are shown on each.
kubectl auth can-i --list --as=system:serviceaccount:<namespace>:<sa-name>Confirm exactly which verbs the SA lacks
kubectl get rolebinding -n <namespace>Review existing bindings
kubectl create rolebinding <app>-read --clusterrole=view --serviceaccount=<namespace>:<sa-name> -n <namespace>Grant the needed access (least privilege)
Prevention
- One SA per workload with explicit Roles; no blanket cluster-admin.
- Add RBAC self-review to CI (kubectl auth can-i in tests).
- Use impersonation in console workflows instead of opening up permissions.
Related runbooks
Same stack, same failure family — worth a skim.
A leaked API key keeps working for months
kubectl logs show 'Error from server (Forbidden): pods is forbidden'
Commands marked READ CHANGE DESTRUCTIVE — never run DESTRUCTIVE commands against production data you cannot restore. Copy → verify → execute.