Fix a Forbidden Error with a Role and RoleBinding
In namespace audit, Pod log-collector exists but is failing with authorization errors. Check the Pod logs to identify what permissions are needed: The logs show a Forbidden error: pods is forbidden:…
Live lab access
This task description is public. Live practice requires full access unless this is the selected free weekly task. AI Lab Coach is available in single-task labs, including the free weekly task. See this week's free task.
Create an account to continue →
On a phone? Read the task and create your account here, then sign in on a desktop or laptop for the terminal lab. Nothing starts until you choose Start.
The task
Task
In namespace audit, Pod log-collector exists but is failing with authorization errors.
Check the Pod logs to identify what permissions are needed:
kubectl logs -n audit log-collector
The logs show a Forbidden error: pods is forbidden: User "system:serviceaccount:audit:default" cannot list resource "pods" in API group "" in the namespace "audit"
Requirements
- Create a ServiceAccount named
log-sain namespaceaudit - Create a Role
log-rolethat grantsget,list, andwatchon resourcepods - Create a RoleBinding
log-rbbindinglog-roletolog-sa - Update Pod
log-collectorto use ServiceAccountlog-sa
Original Prepium guide · Written for Kubernetes v1.35 and checked against the official documentation on 6 October 2026. Use a disposable practice cluster. You need an admin kubeconfig, because the examples impersonate a ServiceAccount with --as.
Read a Forbidden error, then grant exactly what it asks for
When a client calls the API with an identity that RBAC does not allow, the API server answers HTTP 403. The message a client prints usually names everything you need for the fix: the user, the verb, the resource, the API group and the namespace. Reading it field by field gives you a Role that is as small as the request, which is faster on the exam than guessing and safer than reaching for a broad ClusterRole.
User "system:serviceaccount:NS:NAME" ──→ RoleBinding subject (kind ServiceAccount)
cannot VERB ──→ Role rule: verbs
resource "RESOURCE" ──→ Role rule: resources
in API group "GROUP" ──→ Role rule: apiGroups ("" means core)
in the namespace "NS" ──→ where the Role and RoleBinding live
1. Reproduce a denial without writing an app
Impersonation lets an admin send a request as another identity, so you see the same denial a Pod running under that ServiceAccount would get.
kubectl create namespace prepium-tutorial
kubectl -n prepium-tutorial create serviceaccount report-bot
kubectl -n prepium-tutorial create deployment web --image=nginx:1.27-alpine
kubectl -n prepium-tutorial get deployments \
--as=system:serviceaccount:prepium-tutorial:report-bot
The reply is a Forbidden error. Read it in this order. The user string follows the documented pattern system:serviceaccount:<namespace>:<name>, so it tells you which ServiceAccount to bind and where it lives. The verb is list, not get, because a GET on a whole collection is authorized as list (a GET on one named object is get, and following changes is a separate verb, watch). The resource is deployments and the group is apps. An empty group "" would mean the core group, home of Pods, Services, ConfigMaps and Secrets.
2. Write the Role from the message, not from memory
kubectl -n prepium-tutorial create role deploy-watcher \
--verb=list,watch --resource=deployments.apps
kubectl -n prepium-tutorial get role deploy-watcher -o yaml
The resource.group form keeps the rule in the right group. Check the YAML: the rule should show apiGroups: ["apps"]. We added watch deliberately because a controller-style client that lists usually watches next; add only verbs you can justify. RBAC has no deny rules, so anything you leave out stays forbidden.
3. Bind it to the ServiceAccount
kubectl -n prepium-tutorial create rolebinding report-bot-deploys \
--role=deploy-watcher --serviceaccount=prepium-tutorial:report-bot
--serviceaccount takes namespace:name. A RoleBinding only grants inside its own namespace, even if the subject lives elsewhere. Its roleRef cannot be changed after creation; to point a binding at a different Role, delete and recreate it.
4. Prove it, including what must still fail
SA=system:serviceaccount:prepium-tutorial:report-bot
kubectl auth can-i list deployments.apps -n prepium-tutorial --as=$SA
kubectl auth can-i watch deployments.apps -n prepium-tutorial --as=$SA
kubectl auth can-i delete deployments.apps -n prepium-tutorial --as=$SA
kubectl auth can-i list deployments.apps -n default --as=$SA
kubectl auth can-i --list -n prepium-tutorial --as=$SA
Expect yes, yes, no, no. The two negatives matter as much as the positives: they show the grant is narrow and namespaced. Finally, a Pod only acts as this identity if its spec.serviceAccountName names it, and that field can only be set when the Pod is created.
Common mistakes
- Putting a non-core resource under
apiGroups: [""]. The Role applies cleanly, but the next request is still Forbidden and the message still says the real group. - Granting
podsbut not thepods/logsubresource. Listing works, reading logs is denied. Subresources are written with a slash in the rule and checked withcan-i get pods --subresource=log. - Running
kubectl auth can-iwithout--as. You test your own admin rights, which always say yes. - Getting the subject namespace wrong in
--serviceaccount. The binding exists but binds a different (or nonexistent) account.
| Example check | Evidence |
|---|---|
| Rule matches the denied request | verbs, resources and apiGroups in the Role match the message |
| Binding targets the right identity | RoleBinding subject is kind: ServiceAccount with the correct name and namespace |
| Permission works | kubectl auth can-i ... --as=system:serviceaccount:... prints yes |
| Permission is narrow | An unrelated verb or another namespace prints no |
Cleanup: kubectl delete namespace prepium-tutorial. References: Using RBAC Authorization, Authorization (request verbs and can-i), kubectl auth can-i. Next, try choosing the right ServiceAccount or CKA RBAC.
What this tests
Wire up configmaps, secrets, service accounts, RBAC, securityContext, and resource limits. On the CKAD exam, Application Environment, Configuration and Security tasks are graded purely on what you build in the cluster - not multiple choice - so the only way to get faster is to do them on a real cluster against a clock.
Practice it for real
The public description lets you study the task before signing up. Full access includes this live lab; the selected Task of the Week is free with an account. You solve the task in a real terminal, hit validate, and a programmatic checker scores exactly what you got right and wrong (with partial credit). You can open the solution while practising, then retry and use the failed checks to improve your score.