RBAC Forbidden — serviceaccount cannot access API resources
kubectl logs show 'Error from server (Forbidden): pods is forbidden'
Focused incident mode — strips away everything but this runbook.
Symptoms
- kubectl logs show 'Error from server (Forbidden): pods is forbidden'
- In-cluster application fails to list pods or secrets via the API
- Controllers or operators report authorization errors in logs
Use kubectl auth can-i --list --as=system:serviceaccount:<ns>:<sa> to see ALL permissions for a service account. This is the fastest way to debug RBAC issues.
Evidence to grab
Collect these artifacts before you change anything — they prove (or rule out) each cause.
RBAC role bindings
kubectl get rolebinding,clusterrolebinding -A | grep <serviceaccount>ServiceAccount details
kubectl get sa <sa> -n <namespace> -o yaml
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
- kubectl auth can-i returns no
- No binding found for the SA
Confirm before fixing
kubectl auth can-i get pods --as=system:serviceaccount:<namespace>:<sa>Test SA permission
Fix
kubectl create role pod-reader --verb=get,list,watch --resource=pods -n <namespace> && kubectl create rolebinding pod-reader-binding --role=pod-reader --serviceaccount=<namespace>:<sa> -n <namespace>Create a RoleBinding for the service account
Expected: rolebinding.rbac.authorization.k8s.io/pod-reader-binding 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 get pods --as=system:serviceaccount:<namespace>:<sa>Test the service account's permission
kubectl get rolebinding,clusterrolebinding -A -o yaml | grep -A5 <sa>Find existing bindings
kubectl create role <role> --verb=get,list,watch --resource=pods -n <namespace>Create a Role granting the needed permissions
kubectl create rolebinding <name> --role=<role> --serviceaccount=<namespace>:<sa> -n <namespace>Bind the role to the service account
kubectl auth can-i get pods --as=system:serviceaccount:<namespace>:<sa>Verify the permission now works
Prevention
- Follow least-privilege: grant only the verbs and resources the SA needs.
- Use ClusterRole + ClusterRoleBinding only when cross-namespace access is required.
- Audit RBAC bindings regularly with kubectl auth can-i --list.
- Use tools like rakkess or kubectl-who-can to review effective permissions.
Commands marked READ CHANGE DESTRUCTIVE — never run DESTRUCTIVE commands against production data you cannot restore. Copy → verify → execute.