Kubernetes Service Account

ServiceAccounts provide identity for in-cluster processes that need to interact with the Kubernetes API server. Every Pod runs as a ServiceAccount; by default this is the default ServiceAccount in its Namespace, which carries minimal permissions. Understanding ServiceAccount creation, token lifecycle, and RBAC binding is essential for the CKA exam and production security. Source: CKA Day 25

What Is a ServiceAccount?

A ServiceAccount is a namespace-scoped Kubernetes object (v1/ServiceAccount) that represents an identity for workloads running inside Pods. While human operators authenticate via client certificates or OIDC tokens stored in kubeconfig, in-cluster applications authenticate via ServiceAccount tokens mounted into their Pods.

Key characteristics:

  • Namespace-scoped: A ServiceAccount only exists within one Namespace
  • Auto-mounted tokens: Kubernetes projects a token volume into every Pod at /var/run/secrets/kubernetes.io/serviceaccount/
  • RBAC-bound: A ServiceAccount has no API permissions until a Role or ClusterRole is bound to it via a RoleBinding or ClusterRoleBinding
  • Non-human identity: Designed for automation, controllers, CI/CD runners, and application SDK clients

The Default ServiceAccount

Every Namespace automatically contains a ServiceAccount named default. If a Pod spec omits serviceAccountName, Kubernetes assigns default.

Security Warning: The default ServiceAccount typically has no permissions beyond cluster defaults. Relying on it for application API access without explicit RBAC grants results in Forbidden errors. For production, always create dedicated ServiceAccounts with least-privilege Roles. Source: CKA Day 25

Creating and Using ServiceAccounts

Imperative Creation

kubectl create serviceaccount my-sa --namespace dev

Declarative (YAML)

apiVersion: v1
kind: ServiceAccount
metadata:
  name: my-sa
  namespace: dev

Assigning to a Pod

apiVersion: v1
kind: Pod
metadata:
  name: api-client
  namespace: dev
spec:
  serviceAccountName: my-sa   # Overrides the default ServiceAccount
  containers:
  - name: app
    image: myapp:v1

Exam Trap: serviceAccountName is set at the Pod spec level, not inside the container definition. It affects all containers in the Pod.

ServiceAccount Tokens

Token Lifecycle

When you create a ServiceAccount, Kubernetes does not automatically create a token Secret in modern clusters (1.24+). Instead, tokens are typically obtained via:

  1. Projected volume tokens (default for Pods) — short-lived, automatically rotated by the kubelet
  2. Manual Secret creation — create a Secret of type kubernetes.io/service-account-token and annotate it with the ServiceAccount name
  3. kubectl create token command — generates a short-lived token for external use

Manual Token Secret (for CI/CD or external clients)

apiVersion: v1
kind: Secret
metadata:
  name: my-sa-token
  annotations:
    kubernetes.io/service-account.name: my-sa
type: kubernetes.io/service-account-token

This Secret will be populated with:

  • token — JWT bearer token
  • ca.crt — Cluster CA certificate
  • namespace — The ServiceAccount’s namespace

Token Mounting in Pods

Every Pod with a ServiceAccount receives a projected volume mount at:

/var/run/secrets/kubernetes.io/serviceaccount/
FilePurpose
tokenJWT bearer token for API authentication
ca.crtCA bundle to verify the API server’s TLS certificate
namespaceThe Namespace name, for constructing API paths

Inside the container, applications read these files to call the API server:

TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
curl -k -H "Authorization: Bearer $TOKEN" \
  https://kubernetes.default.svc.cluster.local/api/v1/namespaces/default/pods

Best Practice: Never copy token files out of Pods or commit them to source control. For external automation, use kubectl create token or projected volume tokens with short expiry. Source: CKA Day 25

RBAC Binding for ServiceAccounts

A ServiceAccount is useless without permissions. The standard workflow:

  1. Create the ServiceAccount
  2. Create a Role (or ClusterRole) defining allowed resources and verbs
  3. Create a RoleBinding (or ClusterRoleBinding) attaching the Role to the ServiceAccount

Example: Grant Pod Read Access

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: pod-reader
  namespace: dev
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: pod-reader-binding
  namespace: dev
subjects:
- kind: ServiceAccount
  name: my-sa
  namespace: dev          # Required even if same namespace
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

Critical: The subjects block must explicitly specify the ServiceAccount’s namespace. The API server will reject bindings that omit this field. Source: CKA Day 25

Testing ServiceAccount Permissions

Use kubectl auth can-i with --as to impersonate a ServiceAccount:

# Full impersonation format
kubectl auth can-i get pods \
  --as system:serviceaccount:dev:my-sa \
  --namespace dev
 
# List all permissions for the ServiceAccount
kubectl auth can-i --list \
  --as system:serviceaccount:dev:my-sa \
  --namespace dev

This is the fastest way to debug RBAC without deploying a Pod.

ImagePullSecrets

ServiceAccounts can store references to docker-registry Secrets, eliminating the need to repeat imagePullSecrets in every Pod spec:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: my-sa
imagePullSecrets:
- name: regcred

Any Pod using my-sa automatically inherits the regcred Secret, enabling private registry image pulls. This is especially useful when teams share a single private registry and want to centralize credential management. Source: CKA Day 25

ServiceAccount vs. User

AspectUserServiceAccount
RepresentsHuman operators, adminsIn-cluster workloads, automation
AuthenticationClient certificates, OIDC, basic authBearer token mounted in Pod
ScopeCan be cluster-wide or namespaceAlways namespace-scoped
StorageExternal (kubeconfig, identity provider)Kubernetes object + token Secret
Typical Usekubectl from a developer laptopController, operator, CI/CD pipeline
RBAC Subjectkind: Userkind: ServiceAccount

Security Best Practices

PracticeRationale
Create dedicated ServiceAccountsAvoid using default for application workloads; it makes permission auditing harder
Apply least privilegeGrant only the verbs and resources the workload actually needs
Use short-lived tokensPrefer projected volume tokens over long-lived static Secrets
Rotate tokens regularlyDelete and recreate token Secrets; restart Pods to pick up new mounts
Restrict Secret accessDo not grant broad get/list on Secrets; attackers can extract ServiceAccount tokens
Disable auto-mount if unusedSet automountServiceAccountToken: false on Pods that do not need API access

CKA Exam Patterns

  • Create ServiceAccount + Role + RoleBinding: Common 3-step task. Use imperative commands for speed:
    kubectl create sa my-sa
    kubectl create role pod-reader --verb=get,list --resource=pods
    kubectl create rolebinding rb --role=pod-reader --serviceaccount=default:my-sa
  • Impersonate with --as: Test without running inside a Pod
    kubectl auth can-i create deployments --as system:serviceaccount:dev:my-sa -n dev
  • Token mount path: Know /var/run/secrets/kubernetes.io/serviceaccount/ and the three files inside
  • ServiceAccount namespace trap: RoleBinding subjects must include namespace for ServiceAccounts

Tags: kubernetes serviceaccount rbac security authentication cka devops token imagepullsecrets