What is a ServiceAccount, and how do pods use them to authenticate to the API server?

6 minintermediateserviceaccountrbacauthentication

Quick Answer

A ServiceAccount is an identity for processes running inside Pods to use when talking to the Kubernetes API server — distinct from a human User account, which Kubernetes doesn't manage as an object at all (it's handled by an external authentication mechanism). Every Pod runs with a ServiceAccount (defaulting to a namespace's `default` ServiceAccount if none is specified), and Kubernetes automatically mounts that ServiceAccount's credentials (a token) into the Pod, letting any code inside the Pod authenticate to the API server as that identity, subject to whatever RBAC permissions are bound to it.

Detailed Answer

Why Pods need their own identity

Some applications running inside a Pod need to talk to the Kubernetes API server themselves — a custom controller watching for changes to a Custom Resource, a CI/CD tool creating new Deployments, or simply an application that needs to look up its own Pod's metadata. This requires an identity to authenticate as, distinct from any human user's own credentials — that's exactly what a ServiceAccount provides.

Creating and using a ServiceAccount

apiVersion: v1
kind: ServiceAccount
metadata:
  name: pod-manager
  namespace: production
apiVersion: v1
kind: Pod
metadata:
  name: my-controller
spec:
  serviceAccountName: pod-manager   # explicitly assign this ServiceAccount
  containers:
    - name: controller
      image: my-controller:1.0

If serviceAccountName isn't specified, the Pod automatically uses that namespace's default ServiceAccount — a detail worth knowing, since it means every Pod always authenticates as some identity, even if you never explicitly thought about which one.

How the credential actually gets into the Pod

Kubernetes automatically mounts a projected volume into every Pod at /var/run/secrets/kubernetes.io/serviceaccount/, containing a short-lived, auto-rotating bound service account token (a JWT), along with the cluster's CA certificate and the current namespace — any code inside the container can read this token and present it as a bearer token when calling the API server directly.

# Inside a Pod, this is how application code (or a Kubernetes client library)
# authenticates to the API server as the Pod's ServiceAccount:
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
curl -H "Authorization: Bearer $TOKEN" \
     --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt \
     https://kubernetes.default.svc/api/v1/namespaces/production/pods

Most Kubernetes client libraries (used when building custom controllers/Operators — see the extensibility topic) handle this automatically via "in-cluster config" detection, so application code rarely constructs these requests by hand.

Binding permissions to a ServiceAccount

A bare ServiceAccount has no permissions by default — it must be granted permissions the same way any other RBAC subject is, via a RoleBinding or ClusterRoleBinding:

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: pod-manager-binding
  namespace: production
subjects:
  - kind: ServiceAccount
    name: pod-manager
    namespace: production
roleRef:
  kind: Role
  name: pod-editor
  apiGroup: rbac.authorization.k8s.io

Why the default ServiceAccount should almost never be granted broad permissions

Because every Pod that doesn't explicitly specify a ServiceAccount silently uses default, granting broad permissions to a namespace's default ServiceAccount effectively grants those permissions to every Pod in that namespace, including ones that never intended to need API access at all — a common, easy-to-introduce security misconfiguration. Best practice is to leave default unprivileged, and create dedicated, narrowly-scoped ServiceAccounts (with correspondingly narrow RoleBindings) for the specific Pods that genuinely need API access.

disabling auto-mounting when not needed

spec:
  automountServiceAccountToken: false

For Pods that don't need to talk to the API server at all (the majority of ordinary application workloads), explicitly disabling the automatic token mount removes an unnecessary credential from the Pod's filesystem entirely — a small but meaningful hardening step, reducing what an attacker could exfiltrate from a compromised container that had no legitimate need for API access in the first place.