Kubernetes "Forbidden: User cannot list resource": give exactly the rights it needs with RBAC
Fix Kubernetes "Forbidden: User cannot list resource": read who and what is missing, test with kubectl auth can-i, then add a Role and RoleBinding.
by OhSudo ··
Not sure this is your cause?Find it step by step: Pod not running →
Part of a learning path:Kubernetes: debugging pods
Error from server (Forbidden): pods is forbidden: User "system:serviceaccount:ci:deployer" cannot list resource "pods" in API group "" in the namespace "web"This one tells you everything. Kubernetes knows who you are, so logging in worked. That identity has no right to do this one thing. The message names all four parts of what’s missing: who, the action, the resource, and the namespace.
- Whoserviceaccount ci:deployer(works)needs
- RoleBindinglinks who to a Rolegrants(fails)
- Roleno "list pods" in namespace web(breaks here)
TL;DR
kubectl auth can-i list pods -n web --as=system:serviceaccount:ci:deployerkubectl create role pod-reader --verb=get,list,watch --resource=pods -n webkubectl create rolebinding deployer-pod-reader --role=pod-reader --serviceaccount=ci:deployer -n webRun those as a cluster admin. The first answers no, before the fix, and yes after.
1. Read the message
| Part | Here | Means |
|---|---|---|
User "..." |
system:serviceaccount:ci:deployer |
Who: here the service account deployer in the namespace ci |
cannot list |
list | The verb: get, list, watch, create, update, patch or delete |
resource "pods" |
pods | What |
in API group "" |
the core group | "" holds pods, services and secrets. Deployments are in apps |
in the namespace "web" |
web | Where. With no namespace, it’s cluster-wide |
A person shows up as their user name, like User "jane@example.com", or as an IAM role on EKS.
2. Ask the cluster
Check any permission, for anyone, without trying it for real:
kubectl auth can-i list pods -n web --as=system:serviceaccount:ci:deployerkubectl auth can-i --list -n web --as=system:serviceaccount:ci:deployerThe second lists everything that identity can do in that namespace. To see who you are:
3. Grant it: a Role and a RoleBinding
RBAC has two halves. A Role lists what’s allowed, and a RoleBinding gives that Role to someone, in one namespace:
apiVersion: rbac.authorization.k8s.io/v1kind: Rolemetadata: name: pod-reader namespace: webrules: - apiGroups: [""] resources: ["pods", "pods/log"] verbs: ["get", "list", "watch"]---apiVersion: rbac.authorization.k8s.io/v1kind: RoleBindingmetadata: name: deployer-pod-reader namespace: websubjects: - kind: ServiceAccount name: deployer namespace: ciroleRef: kind: Role name: pod-reader apiGroup: rbac.authorization.k8s.ioNote that the service account lives in ci, and the binding in web: a binding grants rights in its own namespace, to someone from anywhere. Use the YAML ⇄ JSON converter if your tooling wants JSON.
For a person, use kind: User with their name as it appears in the message, or better, kind: Group, so that a team shares one binding.
4. Cluster-wide resources
Some resources don’t belong to a namespace: nodes, namespaces themselves, persistent volumes, and CRDs. For those, a Role can’t help:
nodes is forbidden: User "jane@example.com" cannot list resource "nodes" in API group "" at the cluster scopeUse a ClusterRole, with a ClusterRoleBinding:
kubectl create clusterrole node-reader --verb=get,list,watch --resource=nodeskubectl create clusterrolebinding jane-node-reader --clusterrole=node-reader --user=jane@example.comA ClusterRole can also be bound with a plain RoleBinding, which grants it in one namespace only. That’s a good way to reuse the built-in view and edit roles:
5. Managed clusters
EKS: an IAM user or role first has to be mapped into the cluster, with an access entry, or the older aws-auth ConfigMap. Without that you get Unauthorized, not this. Once mapped, its Kubernetes rights come from access policies or RBAC as above.
AKS with Microsoft Entra ID and GKE can use cloud roles for Kubernetes rights. On GKE, IAM and RBAC both apply, and either one can allow a request.
6. Helm and operators
helm install acts with your rights, so a chart that creates a ClusterRole needs a user who may do so. An operator’s pods use their own service account. When an operator logs this error, its chart’s RBAC is out of date, or it was installed limited to one namespace and is reaching into another.
Warning
Don’t bind cluster-admin to a service account to fix this, even “for now”: it gives full control of the cluster to anything that can read that account’s token, such as a compromised CI job. Grant the verbs and resources in the message, in the namespace in the message. kubectl auth can-i tells you when you’ve got it right.
Shell, we have a problem!
Similar, but different: error: You must be logged in to the server (Unauthorized) means your credentials didn’t work at all. x509: certificate signed by unknown authority is about trusting the cluster. admission webhook ... denied the request comes from a policy, not RBAC. And runAsNonRoot errors come from a pod’s security settings.
$ ./practice.sh
Practice this in the terminal
Open the Terminal Playground with this article’s scenario loaded. It is safe and runs in your browser.
Found this useful? Share it.
Found a mistake? Let us know at contact@ohsudo.com.