Skip to content

Disable Kubernetes service account token automount

Severity: highApplies to: Kubernetes 1.29+Applies to: Kubernetes 1.34
The fix
# On the pod (or its ServiceAccount): don't mount a token unless needed
apiVersion: v1
kind: Pod
spec:
automountServiceAccountToken: false
# ...
# Or default it off for a whole ServiceAccount:
apiVersion: v1
kind: ServiceAccount
metadata:
name: default
namespace: orders
automountServiceAccountToken: false

By default, every pod gets a service account token mounted into it at /var/run/secrets/kubernetes.io/serviceaccount/token. That token authenticates to the API server. Most application pods never use it — they talk to a database and serve HTTP, not the Kubernetes API — but it’s mounted anyway.

That mounted token is a credential sitting inside your workload. If the pod is compromised — an RCE in your app, a malicious dependency, an SSRF that reaches the filesystem — the attacker reads the token and can now query the API server as that service account. What they can do next depends entirely on what the service account’s RBAC grants, and if it’s the default service account with more than it should have, that’s a foothold into the cluster from a single compromised container.

Turning off automount removes the credential from pods that don’t need it. There’s nothing for the attacker to steal, and the pod loses no functionality it was actually using.

The default service account is the specific trap

Section titled “The default service account is the specific trap”

Every namespace has a default service account, and every pod that doesn’t specify one uses it. So the default SA is mounted into a lot of pods — which means:

  • Don’t grant the default service account any permissions. Anything you give it is given to every pod in the namespace that didn’t ask for a specific identity. Keep it empty, and give workloads that need API access their own named service account.
  • Set automountServiceAccountToken: false on the default SA in every namespace, so the common case — a pod that never named a service account — gets no token at all.

A workload that genuinely needs API access then opts in: its own service account, its own scoped role, and automount left on for that one.

The setting can go in two places, and the pod spec wins:

  • On the ServiceAccount — the default for pods using it.
  • On the Pod — overrides the service account’s setting for that pod.

The robust pattern is off-by-default on the service account, on-by-exception on the specific pods that call the API. That’s the same opt-in-to-privilege shape as the rest of this cluster.