CKA — ServiceAccounts
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
defaultServiceAccount - Every Pod runs as a ServiceAccount (the
defaultSA 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.