CKA — ServiceAccounts

5 minute read

CKA Exam Domain

Cluster Architecture, Installation & Configuration — 25%

ServiceAccounts are how Pods authenticate to the Kubernetes API. Every Pod runs as a ServiceAccount, and you can use RBAC to control what that Pod is allowed to do. This is essential for CKA — you’ll need to create ServiceAccounts, assign them to Pods, and bind Roles to them.

What Is a ServiceAccount?

A ServiceAccount (SA) provides an identity for processes running in a Pod. When a Pod makes API calls to the Kubernetes API server, it authenticates using its ServiceAccount’s token.

Key facts:

  • Every namespace automatically gets a default ServiceAccount
  • Every Pod runs as a ServiceAccount (the default SA if you don’t specify one)
  • ServiceAccounts are namespaced — they belong to a specific namespace
  • They are the subject in RBAC bindings for Pod permissions
# Every namespace has a default SA
kubectl get serviceaccounts -n default
# NAME      SECRETS   AGE
# default   0         30d

Default ServiceAccount

When you create a Pod without specifying a ServiceAccount, it runs as the default SA in that namespace.

The default ServiceAccount:

  • Has no special permissions by default (RBAC denies everything unless explicitly granted)
  • Gets a token automatically mounted into the Pod at /var/run/secrets/kubernetes.io/serviceaccount/
  • Includes the token, CA certificate, and namespace file
# Check what's mounted in a Pod
kubectl exec my-pod -- ls /var/run/secrets/kubernetes.io/serviceaccount/
# ca.crt
# namespace
# token

Security concern: Auto-mounting a token means every Pod can attempt API calls. If the default SA has been granted broad permissions (a misconfiguration), all Pods in that namespace inherit those permissions.

Best practice: Don’t grant permissions to the default ServiceAccount. Create dedicated SAs for Pods that need API access.

Creating ServiceAccounts

Imperative

kubectl create serviceaccount my-sa -n dev

Declarative

apiVersion: v1
kind: ServiceAccount
metadata:
  name: my-sa
  namespace: dev
automountServiceAccountToken: false  # Optional: disable auto-mounting

You can also add labels and annotations:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: monitoring-sa
  namespace: monitoring
  labels:
    app: prometheus
  annotations:
    description: "SA for Prometheus pods"

Assigning ServiceAccounts to Pods

Use spec.serviceAccountName in your Pod spec:

apiVersion: v1
kind: Pod
metadata:
  name: my-app
  namespace: dev
spec:
  serviceAccountName: my-sa
  containers:
  - name: app
    image: nginx

For Deployments, the ServiceAccount goes in the Pod template:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  namespace: dev
spec:
  replicas: 2
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      serviceAccountName: my-sa
      containers:
      - name: app
        image: nginx

Exam tip: If a question says “the Pod should use ServiceAccount X,” put serviceAccountName: X under spec — not under containers.

Token Projection

Projected Volumes (Modern Approach)

Kubernetes 1.20+ uses projected service account tokens by default:

  • Tokens are time-bound (expire and auto-rotate)
  • Tokens are audience-bound (specific to an API server)
  • Tokens are mounted via a projected volume, not a Secret

This happens automatically — you don’t need to configure it.

Legacy Token Secrets

In older Kubernetes versions, a long-lived token was stored in a Secret:

# Legacy: SA token stored as a Secret
kubectl get secrets -n dev | grep my-sa

In Kubernetes 1.24+, long-lived Secret-based tokens are no longer auto-created. You can still create them manually if needed:

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

Disabling Auto-Mount

If a Pod doesn’t need API access, disable token mounting for security:

At the ServiceAccount level (affects all Pods using this SA):

apiVersion: v1
kind: ServiceAccount
metadata:
  name: no-api-sa
  namespace: dev
automountServiceAccountToken: false

At the Pod level (overrides the SA setting):

apiVersion: v1
kind: Pod
metadata:
  name: secure-pod
  namespace: dev
spec:
  serviceAccountName: no-api-sa
  automountServiceAccountToken: false
  containers:
  - name: app
    image: nginx

CKA relevance: You may be asked to create a Pod that does NOT mount the ServiceAccount token. Set automountServiceAccountToken: false at the Pod spec level.

ServiceAccount RBAC Patterns

The most common pattern on the CKA exam: create a ServiceAccount, give it specific permissions, and assign it to a Pod.

Here’s the complete 4-step workflow:

Step 1: Create the ServiceAccount

apiVersion: v1
kind: ServiceAccount
metadata:
  name: pod-monitor
  namespace: dev

Step 2: Create the Role

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: pod-reader
  namespace: dev
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "list", "watch"]

Step 3: Create the RoleBinding

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: pod-monitor-binding
  namespace: dev
subjects:
- kind: ServiceAccount
  name: pod-monitor
  namespace: dev
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

Step 4: Create the Pod with the ServiceAccount

apiVersion: v1
kind: Pod
metadata:
  name: monitor-app
  namespace: dev
spec:
  serviceAccountName: pod-monitor
  containers:
  - name: monitor
    image: bitnami/kubectl
    command: ["sleep", "3600"]

All-in-One YAML

You can put all four resources in one file separated by ---:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: pod-monitor
  namespace: dev
---
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-monitor-binding
  namespace: dev
subjects:
- kind: ServiceAccount
  name: pod-monitor
  namespace: dev
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io
---
apiVersion: v1
kind: Pod
metadata:
  name: monitor-app
  namespace: dev
spec:
  serviceAccountName: pod-monitor
  containers:
  - name: monitor
    image: bitnami/kubectl
    command: ["sleep", "3600"]

kubectl Commands

# Create a ServiceAccount
kubectl create serviceaccount my-sa -n dev

# List ServiceAccounts
kubectl get serviceaccounts -n dev

# Describe a ServiceAccount
kubectl describe serviceaccount my-sa -n dev

# Check which SA a Pod is using
kubectl get pod my-pod -n dev -o jsonpath='{.spec.serviceAccountName}'

# Test permissions of a ServiceAccount
kubectl auth can-i list pods --as system:serviceaccount:dev:my-sa -n dev

# Create a RoleBinding for a ServiceAccount
kubectl create rolebinding sa-binding --role=pod-reader --serviceaccount=dev:my-sa -n dev

Practice Questions

Q1. Create a ServiceAccount named log-reader in the logging namespace.

Show Answer
kubectl create namespace logging
kubectl create serviceaccount log-reader -n logging

Q2. Create a Pod named log-app in the logging namespace that uses the log-reader ServiceAccount and does NOT auto-mount the token.

Show Answer
apiVersion: v1
kind: Pod
metadata:
  name: log-app
  namespace: logging
spec:
  serviceAccountName: log-reader
  automountServiceAccountToken: false
  containers:
  - name: app
    image: nginx

Q3. How do you check which ServiceAccount a running Pod is using?

Show Answer
kubectl get pod <pod-name> -n <namespace> -o jsonpath='{.spec.serviceAccountName}'

Or:

kubectl describe pod <pod-name> -n <namespace> | grep "Service Account"

Q4. Create the complete RBAC setup: ServiceAccount deployer in namespace ci, Role deploy-role granting create/get/list on Deployments, and a RoleBinding connecting them.

Show Answer
kubectl create namespace ci
kubectl create serviceaccount deployer -n ci
kubectl create role deploy-role --verb=create,get,list --resource=deployments -n ci
kubectl create rolebinding deploy-binding --role=deploy-role --serviceaccount=ci:deployer -n ci

Verify:

kubectl auth can-i create deployments --as system:serviceaccount:ci:deployer -n ci
# yes

Q5. What happens if you don’t specify a serviceAccountName in a Pod spec?

Show Answer

The Pod uses the default ServiceAccount in its namespace. This SA:

  • Exists automatically in every namespace
  • Has no RBAC permissions by default
  • Still gets a token mounted into the Pod (unless auto-mount is disabled)

For security, always create dedicated ServiceAccounts for Pods that need specific API permissions, rather than granting permissions to default.

Updated: