Home › CKAD › Topics › Practice tasks › RBAC & Permissions
CKAD · Application Environment, Configuration and Security

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:…

Check live lab access → All CKAD tasks

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 →

Read this week's free task →

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

  1. Create a ServiceAccount named log-sa in namespace audit
  2. Create a Role log-role that grants get, list, and watch on resource pods
  3. Create a RoleBinding log-rb binding log-role to log-sa
  4. Update Pod log-collector to use ServiceAccount log-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

Example checkEvidence
Rule matches the denied requestverbs, resources and apiGroups in the Role match the message
Binding targets the right identityRoleBinding subject is kind: ServiceAccount with the correct name and namespace
Permission workskubectl auth can-i ... --as=system:serviceaccount:... prints yes
Permission is narrowAn 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.

Exam
CKAD
Domain
Application Environment, Configuration and Security
Grading
Programmatic · partial credit

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.

Related CKAD tasks