Kubernetes Error Guide: 'cannot list resource' RBAC Forbidden Failures
Fix Kubernetes RBAC 'Forbidden: cannot list resource' errors: missing RoleBindings, wrong namespace or subject, cluster-scoped resources, and ServiceAccount tokens.
- #kubernetes
- #troubleshooting
- #errors
- #rbac
Exact Error Message
A human user lacking permission to list pods sees:
Error from server (Forbidden): pods is forbidden: User "jane@example.com" cannot list resource "pods" in API group "" in the namespace "default"
The same error from a ServiceAccount names the subject as system:serviceaccount:<namespace>:<name>:
Error from server (Forbidden): pods is forbidden: User "system:serviceaccount:ci:deployer" cannot list resource "pods" in API group "" in the namespace "staging"
Cluster-scoped resources report no namespace at all:
Error from server (Forbidden): nodes is forbidden: User "jane@example.com" cannot list resource "nodes" in API group "" at the cluster scope
What the Error Means
This is a 403 Forbidden from the Kubernetes authorization layer. The request was authenticated — the API server knows who you are — but not authorized: no RBAC rule grants the identity permission to perform the verb (list) on the resource (pods) in the scope (namespace "default"). This is fundamentally different from a 401 Unauthorized, where the API server could not identify you at all.
Every part of the message is a clue. User "..." is the subject RBAC evaluated. cannot list is the verb. resource "pods" and API group "" (the empty string is the core group) identify exactly what a rule must allow. in the namespace "default" versus at the cluster scope tells you whether a namespaced Role/RoleBinding or a cluster-wide ClusterRole/ClusterRoleBinding is required. RBAC is purely additive: with no matching allow rule, access is denied by default.
Common Causes
- No Role/ClusterRole binding at all for the subject — the most common case, especially for a freshly created ServiceAccount.
- RoleBinding in the wrong namespace. A
RoleBindingonly grants access in its own namespace; a binding indefaultdoes nothing for requests againststaging. - Cluster-scoped resource bound with a namespaced Role. Listing
nodes,namespaces, orpersistentvolumesrequires aClusterRole+ClusterRoleBinding; aRolecan never grant cluster-scoped access. - Wrong subject name or kind. A typo in the user/SA name, or
kind: Userwhere it should bekind: ServiceAccount(or a missingnamespaceon the SA subject), means the binding matches nothing. - Wrong
apiGrouporresourcein the rule. Puttingpodsunder the wrong group, or usingdeploymentinstead ofdeployments, leaves the real request uncovered. - Using a ServiceAccount token without any binding. A pod or CI job authenticates as its SA but no
RoleBindingreferences that SA. - Aggregated ClusterRoles. A custom rule was added expecting it to be picked up by an aggregated role (like
view) but theaggregationRulelabels do not match.
How to Reproduce the Error
Create a ServiceAccount with no bindings and try to list pods as it:
kubectl create serviceaccount deployer -n staging
kubectl auth can-i list pods -n staging \
--as=system:serviceaccount:staging:deployer
no
kubectl get pods -n staging \
--as=system:serviceaccount:staging:deployer
Error from server (Forbidden): pods is forbidden: User "system:serviceaccount:staging:deployer" cannot list resource "pods" in API group "" in the namespace "staging"
Diagnostic Commands
Impersonate the subject and ask whether the exact action is allowed:
kubectl auth can-i list pods -n staging \
--as=system:serviceaccount:staging:deployer
List every permission the subject actually has — invaluable for spotting what is missing:
kubectl auth can-i --list -n staging \
--as=system:serviceaccount:staging:deployer
Resources Non-Resource URLs Resource Names Verbs
selfsubjectreviews.authorization.k8s.io [] [] [create]
*.* [/api/*] [] []
Find every binding that references the subject across the cluster:
kubectl get rolebindings,clusterrolebindings -A -o wide \
| grep -E 'deployer|NAMESPACE'
NAMESPACE NAME ROLE AGE USERS GROUPS SERVICEACCOUNTS
staging deploy-binding Role/deploy-role 2d staging/deployer
Inspect what a referenced Role or ClusterRole actually permits:
kubectl describe role deploy-role -n staging
PolicyRule:
Resources Non-Resource URLs Resource Names Verbs
--------- ----------------- -------------- -----
pods [] [] [get watch] # note: no "list"!
That output reveals the bug: the rule grants get and watch but not list.
Step-by-Step Resolution
1. Confirm the gap with kubectl auth can-i --list so you know exactly which verb/resource/scope is missing.
2. Decide the scope. Namespaced resource (pods, deployments, services) → Role + RoleBinding in the target namespace. Cluster-scoped resource (nodes, namespaces, persistentvolumes) → ClusterRole + ClusterRoleBinding.
3. Create a Role granting the missing verbs (note apiGroups: [""] for core resources):
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-reader
namespace: staging
rules:
- apiGroups: [""] # "" is the core API group (pods, services, configmaps)
resources: ["pods", "pods/log"]
verbs: ["get", "list", "watch"]
4. Bind it to the subject. For a ServiceAccount, the subject kind is ServiceAccount with its own namespace:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: deployer-pod-reader
namespace: staging # MUST match the namespace you want access in
subjects:
- kind: ServiceAccount
name: deployer
namespace: staging
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
5. Apply and verify:
kubectl apply -f pod-reader-role.yaml -f deployer-binding.yaml
kubectl auth can-i list pods -n staging \
--as=system:serviceaccount:staging:deployer
yes
6. For cluster-scoped access, swap both kinds to their cluster equivalents — a ClusterRole with resources: ["nodes"] bound by a ClusterRoleBinding. A namespaced RoleBinding can never authorize kubectl get nodes.
Prevention and Best Practices
- Grant the least privilege that works: scope to specific namespaces and resources rather than
*andcluster-admin. - Bind to groups (e.g. an OIDC group) instead of individual users so onboarding does not require new RBAC objects each time.
- Remember the scope rule: namespaced resources need
Role/RoleBinding; cluster-scoped resources needClusterRole/ClusterRoleBinding. Mixing them is the single most frequent mistake. - Double-check the
apiGroup: core resources use"",deploymentsuseapps,ingressesusenetworking.k8s.io. A wrong group silently grants nothing. - Reuse the built-in
view,edit, andadminClusterRoles viaRoleBindinginstead of hand-writing rules where they fit. - Audit access in CI with
kubectl auth can-i --list --as=<subject>so a missing binding fails the pipeline, not production.
Related Errors
error: You must be logged in to the server (Unauthorized)— a401, meaning authentication failed entirely. Contrast 401 (who are you?) vs 403 (you may not do this) in the Unauthorized error guide.Error from server (Forbidden): ... cannot create resource ... at the cluster scope— same RBAC failure for a cluster-scoped verb; needs a ClusterRole.Error from server (Forbidden): ... requires one of ["...","..."] but ServiceAccount ... has none— a PodSecurity admission denial, not RBAC; check Pod Security Standards labels.the server doesn't have a resource type "..."— the resource/CRD does not exist; distinct from being forbidden to access it.
Frequently Asked Questions
What is the difference between this 403 and a 401 Unauthorized?
A 401 Unauthorized means the API server could not authenticate you — bad or missing credentials. A 403 Forbidden (“cannot list resource”) means you are authenticated but no RBAC rule grants the action. Fix 401 by sorting out your token or kubeconfig; fix 403 by adding a Role/RoleBinding. See the Unauthorized guide for the 401 path.
My RoleBinding exists but I’m still forbidden — why?
Check three things: the RoleBinding is in the same namespace you are querying, the subject kind/name/namespace exactly matches the identity in the error, and the referenced Role actually lists the verb you need. A binding in default does nothing for requests against staging.
Why does kubectl get nodes fail even though my user can list pods?
nodes is a cluster-scoped resource. A namespaced Role/RoleBinding can only grant namespaced resources. You need a ClusterRole granting list on nodes bound with a ClusterRoleBinding.
How do I see exactly what a ServiceAccount is allowed to do?
Impersonate it: kubectl auth can-i --list --as=system:serviceaccount:<ns>:<name>. This enumerates every resource/verb the subject can access, making missing permissions obvious without trial-and-error.
What does API group "" mean in the error?
The empty string is the core API group — it covers pods, services, configmaps, secrets, and nodes. In a Role rule you write apiGroups: [""] to grant access to those resources; using any other group there will not match the request.
Download the Free 500-Prompt DevOps AI Toolkit
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.