KubernetesLX · ServiceAccountsServiceAccounts
Default bindings and automountServiceAccountToken
What you'll learn
- Explain what the `default` ServiceAccount is and why it is the most dangerous SA in production
- Configure `automountServiceAccountToken: false` to prevent token mounting on Pods that do not need it
- Identify the production patterns for minimum-surface default SAs
- Recognise the failure modes of over-broad defaults and unmounted tokens
Prerequisites
Verified against Kubernetes 1.34.x · kubeadm 1.34.x · kubectl 1.34.x · etcd 3.6.x · CoreDNS 1.11.x · containerd 1.7.x / 2.x · 2026-08-16
The default ServiceAccount in every namespace is the
most exposed SA in production. Every Pod that does not
specify serviceAccountName uses it; its token is
auto-mounted into every such Pod. A default SA with
broad RBAC, or with automountServiceAccountToken: true and no use case for the API, is a Critical
finding. This lesson covers the defaults, the
auto-mount flag, and the production patterns.
The default SA
Every namespace has a default SA, auto-created by
the namespace controller when the namespace is created:
kubectl get sa -A | grep default
# NAMESPACE NAME SECRETS AGE
# default default 0 30d
# kube-public default 0 30d
# prod default 0 30d
The SA’s metadata is minimal:
apiVersion: v1
kind: ServiceAccount
metadata:
name: default
namespace: prod
No RBAC bindings, no image pull secrets, no labels. A
Pod without spec.serviceAccountName uses this SA.
automountServiceAccountToken
The automountServiceAccountToken flag controls
whether the kubelet mounts the projected token volume:
# On the SA (applies to every Pod using the SA)
apiVersion: v1
kind: ServiceAccount
metadata:
name: api-sa
namespace: prod
automountServiceAccountToken: false # no token mounted
# On the Pod (overrides the SA's flag for this Pod)
apiVersion: v1
kind: Pod
metadata:
name: api
spec:
serviceAccountName: api-sa
automountServiceAccountToken: false
When the flag is false:
- The kubelet does not call TokenRequest for the SA.
- The projected token volume is not added to the Pod spec.
/var/run/secrets/kubernetes.io/serviceaccount/tokendoes not exist.- The workload cannot authenticate to the API server using the SA’s token (because there is none).
A workload that does not call the API server should
have this flag set to false. The flag is the single
highest-leverage SA hardening control.
flowchart LR
A[Pod spec.automountServiceAccountToken] --> B{false?}
B -->|yes| C[No token mounted]
B -->|no| D[SA's flag]
D --> E{false?}
E -->|yes| C
E -->|no| F[Token mounted]
Production patterns
Three patterns:
- Default SA with no RBAC and no automount. The
defaultSA in every namespace is bound to nothing, andautomountServiceAccountTokenis set tofalse.
apiVersion: v1
kind: ServiceAccount
metadata:
name: default
namespace: prod
automountServiceAccountToken: false
- Every workload specifies its own SA. No Pod
relies on
default. The workload’s SA has the minimum RBAC it needs.
apiVersion: v1
kind: Pod
metadata:
name: api
spec:
serviceAccountName: api-sa
containers:
- name: api
image: myapp:v1.0
- Disable token automount on workloads that don’t call the API. A logging sidecar, a metrics exporter, a pure network service — none of these need the API.
spec:
serviceAccountName: log-shipper-sa
automountServiceAccountToken: false
Verifying the defaults
# Check the default SA in every namespace
for ns in $(kubectl get ns -o name | cut -d/ -f2); do
echo "=== $ns ==="
kubectl get sa default -n "$ns" -o jsonpath='{.automountServiceAccountToken}'
echo
done
# Check what the default SA can do
for ns in $(kubectl get ns -o name | cut -d/ -f2); do
echo "=== $ns ==="
kubectl auth can-i --list -n "$ns" \
--as=system:serviceaccount:$ns:default
done
A default SA with any non-empty --list output is a
finding.
Disabling the default SA
A team that wants to forbid the default SA entirely
can:
- Set
automountServiceAccountToken: falseon thedefaultSA in every namespace. - Use a ValidatingAdmissionPolicy to require
spec.serviceAccountNameon every Pod. - Bind the
defaultSA to nothing.
# ValidatingAdmissionPolicy
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
name: require-sa
spec:
failurePolicy: Fail
rules:
- operations: ["CREATE", "UPDATE"]
apiGroups: [""]
apiVersions: ["v1"]
resources: ["pods"]
validations:
- expression: "object.spec.serviceAccountName != '' && object.spec.serviceAccountName != 'default'"
message: "Pods must specify a serviceAccountName other than 'default'"
The policy rejects any Pod that does not specify a SA
or that uses default. Every Pod has an explicit SA.
Production failure modes
- Default SA bound to
editorview. Every Pod in the namespace has read or write access to every object. The fix is to remove the binding. - Default SA with
automountServiceAccountToken: true. Every Pod has a token mounted even when not needed. The fix is to set it tofalse. - Workload needs the API but uses
default. A workload was deployed without a SA and usesdefault. Ifdefaulthas no RBAC, the workload fails. The fix is to specify the workload’s own SA with the minimum RBAC. - ValidatingAdmissionPolicy too strict. A policy
that rejects every Pod without a SA breaks
workloads that legitimately use
default. The fix is to scope the policy to non-kube-systemnamespaces.
Cross-course references
- The Observability course covers the audit log
entries for
defaultSA usage. - The Linux course covers the file permissions for the token mount path.
Quiz
Knowledge check · 4 questions
Q1. What is the operational effect of setting `automountServiceAccountToken: false` on a ServiceAccount?
Q2. If the `default` ServiceAccount in a namespace has an RBAC binding to a Role, every Pod in the namespace that does not specify a `serviceAccountName` inherits the binding.
Q3. Your workload in `prod` calls the API server to read a ConfigMap. You set `automountServiceAccountToken: false` on the SA. The workload reports `Unauthorized: no token`. What went wrong, and how do you fix it?
The SA `api-sa` has `automountServiceAccountToken: false`. The Pod uses `api-sa`. The workload tries to read a ConfigMap from the API server. The token file at `/var/run/secrets/kubernetes.io/serviceaccount/` is empty. The workload has no token.
Q4. Name three production patterns for hardening the `default` ServiceAccount in a namespace.
Passing score: 75%. Answers are checked in this browser.
Production discipline
The default ServiceAccount is the highest-leverage
target for SA hardening. Bind it to nothing, set
automountServiceAccountToken: false, and require
every Pod to specify a SA. A cluster whose default
SA is inert and whose workloads use minimum-surface
SAs has a workload identity programme that is
defensible. A cluster whose default SA has broad
RBAC and automountServiceAccountToken: true has a
workload identity programme that is not — the audit
log will surface the over-broad bindings, the
ValidatingAdmissionPolicy will catch new violations,
and the discipline is to enforce the policy at every
admission.