Disable ServiceAccount Token Automounting
First, modify the existing ServiceAccount stats-monitor-sa in the namespace monitoring to turn off automounting of API credentials.
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
Context
A security audit has identified a Deployment improperly handling service account tokens, which could lead to security vulnerabilities.
Task
First, modify the existing ServiceAccount stats-monitor-sa in the namespace monitoring to turn off automounting of API credentials.
Next, modify the existing Deployment stats-monitor in the namespace monitoring to inject a ServiceAccount token mounted at /var/run/secrets/kubernetes.io/serviceaccount/token.
Use a Projected Volume named token to inject the ServiceAccount token and ensure that it is mounted read-only.
Original Prepium guide · Written for Kubernetes v1.35 and checked against the official documentation on 6 October 2026. Use a disposable practice cluster.
Stop automatic token mounts, then hand out a scoped, short-lived token on purpose
By default every Pod gets a ServiceAccount token, a CA bundle and its namespace name in a projected volume at /var/run/secrets/kubernetes.io/serviceaccount. If the application never talks to the API, that token is only something an attacker can steal. CKS hardening therefore has two halves: turn the automatic mount off, and where a token is genuinely needed, project one explicitly with a narrow audience, a short lifetime and a read-only mount.
ServiceAccount.automountServiceAccountToken ─┐
Pod.spec.automountServiceAccountToken ───────┴─→ Pod value wins if both are set
│ true (or unset)
▼
admission adds kube-api-access-<suffix> (token, ca.crt, namespace)
explicit projected volume ─→ serviceAccountToken {path, audience, expirationSeconds}
─→ kubelet fetches and rotates it ─→ your mountPath (readOnly)
1. Look at the default first
kubectl create namespace prepium-tutorial
kubectl -n prepium-tutorial create serviceaccount metrics-shipper
kubectl -n prepium-tutorial run before --image=busybox:1.36 \
--overrides='{"apiVersion":"v1","spec":{"serviceAccountName":"metrics-shipper"}}' -- sleep 3600
kubectl -n prepium-tutorial describe pod before
Under Mounts you see the service account path coming from a volume named kube-api-access- plus a random suffix, marked (ro). Under Volumes it is listed as a projected volume with a token expiration of 3607 seconds, the kube-root-ca.crt ConfigMap and the downward API.
2. Turn automounting off on the ServiceAccount
kubectl -n prepium-tutorial patch serviceaccount metrics-shipper \
-p '{"automountServiceAccountToken": false}'
kubectl -n prepium-tutorial get pod before -o jsonpath='{.spec.volumes[*].name}'
The existing Pod still lists its kube-api-access volume. The ServiceAccount admission controller only acts when a Pod is created, so changes reach new Pods only; for a Deployment that means a rollout. Remember precedence: if a Pod spec sets automountServiceAccountToken itself, that value beats the ServiceAccount's. A Pod with true still gets the token even though the account says false, so check both places during an audit.
3. Project a token you actually control
Save this as cks-automount-pod.yaml and apply it.
apiVersion: v1
kind: Pod
metadata:
name: shipper
namespace: prepium-tutorial
spec:
serviceAccountName: metrics-shipper # the account has automount turned off
containers:
- name: shipper
image: busybox:1.36
command: ["sh", "-c", "sleep 3600"]
volumeMounts:
- name: gateway-cred
mountPath: /var/run/secrets/gateway
readOnly: true
volumes:
- name: gateway-cred
projected:
sources:
- serviceAccountToken:
path: gateway-token # file name inside the mount
audience: metrics-gateway # who should accept this token
expirationSeconds: 1200 # 20 minutes; the minimum is 600
Each field narrows the risk. audience marks who the token is for; a recipient is expected to reject tokens that do not name it (when omitted it defaults to the API server's identifier). expirationSeconds defaults to one hour and cannot go below 600. The kubelet requests the token through the TokenRequest API and rotates it once it is older than 80% of its lifetime or older than 24 hours, so the application must re-read the file rather than cache it. Avoid subPath for this mount, because subPath mounts of projected sources do not receive updates.
4. Verify from inside
kubectl apply -f cks-automount-pod.yaml
kubectl -n prepium-tutorial get pod shipper -o jsonpath='{.spec.volumes[*].name}'
kubectl -n prepium-tutorial exec shipper -- ls /var/run/secrets/gateway
kubectl -n prepium-tutorial exec shipper -- ls /var/run/secrets/kubernetes.io/serviceaccount
kubectl -n prepium-tutorial exec shipper -- grep /var/run/secrets/gateway /proc/mounts
The volume list shows only gateway-cred, with no kube-api-access entry. The second command lists gateway-token; the third fails because nothing was mounted at the default path. In /proc/mounts the option list for the gateway mount includes ro. The token is a JWT, so a standard JWT decoder run on your workstation shows its aud and exp claims if you want to confirm the audience and lifetime.
Common mistakes
- Setting
expirationSecondsbelow 600. The documented minimum is 10 minutes, so the Pod is not accepted. - Patching the ServiceAccount and checking an old Pod. Nothing changes until a new Pod is created.
- Forgetting
readOnly: trueon the volumeMount. The token works, but a hardening check that looks for a read-only mount fails. - Disabling automount on the account while a Pod template still says
automountServiceAccountToken: true. The Pod-level value wins.
| Example check | Evidence |
|---|---|
| Automount disabled | automountServiceAccountToken: false on the ServiceAccount, and no Pod-level override to true |
| No default token volume | New Pod has no kube-api-access-* volume |
| Explicit token projected | Projected volume with a serviceAccountToken source and the intended path |
| Mount is read-only | readOnly: true in the spec and ro in /proc/mounts |
Cleanup: kubectl delete namespace prepium-tutorial. References: Configure Service Accounts for Pods, Projected Volumes, Managing Service Accounts. Next, try switching a workload's ServiceAccount or immutable containers.
What this tests
Apply Pod Security Standards, securityContext, and mTLS, and protect secrets at rest. On the CKS exam, Minimize Microservice Vulnerabilities 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.