Fix a Pod Running with the Wrong ServiceAccount
In namespace monitoring, Pod metrics-pod is using ServiceAccount wrong-sa and receiving authorization errors. Multiple ServiceAccounts, Roles, and RoleBindings already exist in the namespace:…
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 monitoring, Pod metrics-pod is using ServiceAccount wrong-sa and receiving authorization errors.
Multiple ServiceAccounts, Roles, and RoleBindings already exist in the namespace:
- ServiceAccounts:
monitor-sa,wrong-sa,admin-sa - Roles:
metrics-reader,full-access,view-only - RoleBindings:
monitor-binding,admin-binding
Requirements
- Identify which ServiceAccount/Role/RoleBinding combination has the correct permissions
- Update Pod
metrics-podto use the correct ServiceAccount - Verify the Pod stops showing authorization errors
Hint: Check existing RoleBindings to see which ServiceAccount is bound to which Role.
Original Prepium guide · Written for Kubernetes v1.35 and checked against the official documentation on 6 October 2026. Use a disposable practice cluster.
Find which ServiceAccount really has the access, then move the workload onto it
A Pod talks to the API as exactly one ServiceAccount, the one named in spec.serviceAccountName (or default if nothing was set). What that identity may do is decided only by RoleBindings and ClusterRoleBindings that list it as a subject. So when several accounts and Roles exist side by side, names prove nothing: you follow the bindings. Then you have to change the identity in a way the API actually allows, because that field is fixed once a Pod exists.
Pod.spec.serviceAccountName ──→ ServiceAccount
▲ subject
RoleBinding ── roleRef ──→ Role ──→ rules (verbs, resources, apiGroups)
1. Build a small maze to practise on
kubectl create namespace prepium-tutorial
kubectl -n prepium-tutorial create serviceaccount ci-runner
kubectl -n prepium-tutorial create serviceaccount config-bot
kubectl -n prepium-tutorial create role cm-reader --verb=get,list --resource=configmaps
kubectl -n prepium-tutorial create role cm-admin --verb=get,list,create,update,delete --resource=configmaps
kubectl -n prepium-tutorial create rolebinding cm-reader-for-bot --role=cm-reader \
--serviceaccount=prepium-tutorial:config-bot
kubectl -n prepium-tutorial create deployment config-sync --image=nginx:1.27-alpine
kubectl -n prepium-tutorial set serviceaccount deployment config-sync ci-runner
Note that cm-admin exists but nothing binds it. An unbound Role grants nothing to anyone, however promising its name sounds.
2. Read the bindings, not the names
kubectl -n prepium-tutorial get rolebindings -o custom-columns='BINDING:.metadata.name,KIND:.roleRef.kind,ROLE:.roleRef.name,SUBJECTS:.subjects[*].name'
kubectl -n prepium-tutorial describe role cm-reader
The first command prints each binding with the Role it points to and its subjects, so you can draw the chain in one glance. Check roleRef.kind too: a RoleBinding can also reference a ClusterRole, in which case the rules come from that ClusterRole but only apply inside this namespace. Also check the subject's namespace with -o yaml; a subject with the right name in another namespace is a different account.
3. Ask the authorizer, account by account
for sa in ci-runner config-bot default; do
echo "== $sa"
kubectl auth can-i list configmaps -n prepium-tutorial \
--as=system:serviceaccount:prepium-tutorial:$sa
done
In this fresh namespace only config-bot answers yes. This is the evidence you want before touching the workload: the authorizer's own decision, not your reading of YAML. Add --list to see an account's full set of allowed actions in the namespace.
4. Change the identity the way the API allows
Try the tempting shortcut first and read the refusal:
POD=$(kubectl -n prepium-tutorial get pod -l app=config-sync -o name | head -1)
kubectl -n prepium-tutorial patch $POD -p '{"spec":{"serviceAccountName":"config-bot"}}'
The API rejects it: an existing Pod accepts only a short list of in-place changes (container images, tolerations and a few timing fields), and the ServiceAccount is not on it. For a Deployment, change the Pod template instead; the controller rolls out new Pods with the new identity:
kubectl -n prepium-tutorial set serviceaccount deployment config-sync config-bot
kubectl -n prepium-tutorial rollout status deployment/config-sync
kubectl -n prepium-tutorial get pods -l app=config-sync \
-o custom-columns=POD:.metadata.name,SA:.spec.serviceAccountName
For a bare Pod with no controller, save its manifest, edit serviceAccountName, and recreate it: kubectl replace --force -f pod.yaml deletes the old object and creates the new one in a single command.
Common mistakes
- Choosing the account whose name sounds right. Without a binding it has no access.
- Editing the Pod instead of the Deployment template. The patch is refused, and every Pod the controller creates later still comes from the unchanged template.
- Reading old logs. Authorization errors from the previous Pod are still in its history; check the logs of the newly created Pod.
- Assuming the most powerful Role is the one in use. Look for a binding that references it.
| Example check | Evidence |
|---|---|
| Correct chain identified | Binding's roleRef and subjects link the chosen account to the needed rules |
| Account is authorized | kubectl auth can-i ... --as=system:serviceaccount:... prints yes |
| Workload uses it | Running Pod's spec.serviceAccountName shows the new account |
| Errors stopped | Logs of the new Pod show no Forbidden responses |
Cleanup: kubectl delete namespace prepium-tutorial. References: Configure Service Accounts for Pods, Using RBAC Authorization, Pod update and replacement. Next, try building a Role from a Forbidden error or controlling token automount.
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.