Forbidden: User cannot list resource
This error occurs when the API server rejects a request because the authenticated user lacks the necessary RBAC permissions to execute the action.
Usually happens because:
- ☑ User or ServiceAccount lacks a Role/ClusterRole granting resource permissions
- ☑ The Role exists but has not been bound to the user name using a RoleBinding
- ☑ Wrong apiGroups parameter specified for custom resource definitions
🔍 Quick Checklist:
What is Forbidden: User cannot list resource?
A 'Forbidden: User cannot list resource' (HTTP 403) error is raised by the API server when the client is successfully authenticated, but lacks the necessary Role-Based Access Control (RBAC) permissions (Role, ClusterRole, RoleBinding, or ClusterRoleBinding) to perform the requested verb (like get, list, create, watch) on the specified resource type. In Kubernetes v1.36, RBAC validations are strictly audited.
Common Causes
- Missing Role or ClusterRole permissions: The user or service account has no corresponding Rule authorizing the verb on the resource namespace.
- Missing RoleBinding: The Role exists, but has not been bound to the user's name or active group namespace.
- Mismatched API group scope: Authorizing resources without specifying their API group namespaces (e.g. listing 'deployments' under group '' instead of 'apps').
| Cause | Frequency |
|---|---|
| User has not been bound to a Role/ClusterRole (missing binding) | ⭐⭐⭐⭐⭐ |
| Missing verb (e.g. list, watch) inside the Role rules configuration | ⭐⭐⭐⭐ |
| Incorrect API group namespace scope (e.g. missing apps group) | ⭐⭐⭐ |
Common Mistakes
- Leaving `apiGroups` empty when authorizing custom resource definitions (e.g. writing `apiGroups: [""]` to authorize a Prometheus custom resource, which defaults to the core namespace, raising a Forbidden error).
- Binding Roles in different namespaces than the target workload ServiceAccount.
How to Fix
Kubernetes Operations & Verification
Create a Role authorizing pods list actions and bind it to a ServiceAccount using a RoleBinding in Kubernetes v1.36.
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default
name: pod-reader
rules:
- apiGroups: [""] # Core API group
resources: ["pods"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-pods-binding
namespace: default
subjects:
- kind: ServiceAccount
name: app-sa
namespace: default
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.ioPlatform Specific Fixes
Trace API server audit events to track forbidden request logs.
# Check API server audit log files for 403 Forbidden events
grep -i "403" /var/log/kubernetes/audit.log | grep -i "cannot list"Best Practices
- Apply least-privilege configurations systematically when creating service accounts.
- Verify RBAC alignments inside local development environments before deploying upgrades to production.
Frequently Asked Questions (FAQ)
Q: What is the difference between Unauthorized and Forbidden?
Unauthorized (HTTP 401) means the server doesn't know who you are. Forbidden (HTTP 403) means the server successfully verified your identity, but your user account does not have RBAC permissions to perform the requested action.
Q: How do I check if my user can perform a specific action?
Use the 'kubectl auth can-i' command. For example, to check if you can list pods in the current namespace, run: 'kubectl auth can-i list pods'. It returns 'yes' or 'no'.
Q: How do I authorize a service account to list pods?
You must create a Role that grants the 'list' verb on 'pods', and then create a RoleBinding that binds that Role to your ServiceAccount in the target namespace.
Q: Why do I get Forbidden for custom resources (CRDs)?
When granting RBAC for custom resources, you must specify the custom resource's exact API group (e.g. 'apiGroups: ["monitoring.coreos.com"]') inside the Role definition. If you leave it empty ('apiGroups: [""]'), the API server assumes the core group and rejects the call.