Tools · Containers and Kubernetes security · 03 / 20
Kubernetes service account tokens: automount, projected tokens, and least privilege
See how pods receive API credentials, why most pods should not get one, and how bound projected tokens differ from legacy long-lived Secret tokens.
How a pod gets a token
Every namespace has a default service account. Unless told otherwise, each pod runs as that account and gets a token mounted at /var/run/secrets/kubernetes.io/serviceaccount/token. Since Kubernetes 1.24, the token is a projected, audience-bound, time-limited token that the kubelet refreshes, not a long-lived Secret.
Anyone who can read that file inside the container can call the API server as the service account. If the account has broad RBAC, a single application bug becomes a cluster problem.
Reducing exposure
Most application pods never talk to the Kubernetes API. Set automountServiceAccountToken: false on the service account or the pod spec. Create a dedicated service account per workload that does need API access, and grant it only the verbs it uses. Avoid creating legacy token Secrets of type kubernetes.io/service-account-token; use kubectl create token for short-lived tokens when a human needs one.
apiVersion: v1 kind: ServiceAccount metadata: name: web namespace: shop automountServiceAccountToken: false
Lab: look inside a pod
Run a test pod with the default settings and read the mounted token’s claims by decoding the middle part of the JWT. Note the expiry and audience. Then recreate the pod with automount disabled and confirm the directory is gone.
kubectl run probe --image=busybox:1.36 --restart=Never -- sleep 3600
kubectl exec probe -- cat /var/run/secrets/kubernetes.io/serviceaccount/token | cut -d. -f2 | base64 -d 2>/dev/null; echo
kubectl delete pod probe
kubectl run probe --image=busybox:1.36 --restart=Never \
--overrides='{"spec":{"automountServiceAccountToken":false}}' -- sleep 3600
kubectl exec probe -- ls /var/run/secrets/kubernetes.io/serviceaccountAuditing
List service accounts bound to powerful roles and list Secrets of the legacy token type, which do not expire. Cloud-managed clusters also map service accounts to cloud identities (IRSA or EKS Pod Identity, Azure Workload Identity, GKE Workload Identity), so a pod token can lead to cloud permissions as well.
Diagram
Legacy token Secret versus projected token
Short-lived and bound is the default for a reason.
Lifetime. No expiry
Audience. Any
Stored. As a Secret in etcd
Lifetime. Time-limited, rotated by kubelet
Audience. Bound to the API server or a set audience
Stored. Only in the pod’s volume
Check yourself
1. Which field stops a token from being mounted into pods that use a service account?
2. How do projected service account tokens differ from legacy token Secrets?
3. What can someone with the pod’s token file do?