K8s by Example: Service Accounts

ServiceAccounts provide identity for Pods. Pods use them to authenticate to the Kubernetes API and external services (via OIDC/IRSA). Each namespace has a default SA. Token is automatically projected into the Pod.

serviceaccount.yaml

ServiceAccount is a namespaced resource. Create dedicated ServiceAccounts for different workloads instead of using the default. Token is mounted at /var/run/secrets/kubernetes.io/serviceaccount/.

apiVersion: v1
kind: ServiceAccount
metadata:
  name: my-app
  namespace: default
pod-serviceaccount.yaml

Assign a ServiceAccount to Pods with serviceAccountName. If not specified, Pods use the default ServiceAccount. Always create dedicated ServiceAccounts for different workloads.

spec:
  serviceAccountName: my-app
  containers:
    - name: app
      image: my-app:v1
serviceaccount-notoken.yaml

Disable auto-mounting of API token if not needed. Reduces attack surface for Pods that don’t use the API. Can set on ServiceAccount or Pod level.

apiVersion: v1
kind: ServiceAccount
metadata:
  name: my-app
automountServiceAccountToken: false
---
spec:
  serviceAccountName: my-app
  automountServiceAccountToken: false
  containers:
    - name: app
      image: my-app:v1
serviceaccount-projected.yaml

Projected service account tokens are time-limited and audience-bound. More secure than legacy tokens. Kubernetes 1.22+ uses projected tokens by default with 1-hour expiry (auto-rotated by kubelet).

spec:
  serviceAccountName: my-app
  containers:
    - name: app
      volumeMounts:
        - name: token
          mountPath: /var/run/secrets/tokens
  volumes:
    - name: token
      projected:
        sources:
          - serviceAccountToken:
              path: token
              expirationSeconds: 3600
              audience: api
serviceaccount-irsa.yaml

AWS IRSA (EKS) lets Pods assume IAM roles using OIDC federation. Annotate ServiceAccount with role ARN. Pod gets AWS credentials automatically without access keys.

apiVersion: v1
kind: ServiceAccount
metadata:
  name: my-app
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::123456789:role/my-app-role
serviceaccount-gcp.yaml

GCP Workload Identity binds Kubernetes ServiceAccounts to Google Cloud service accounts. Similar to IRSA, no keys needed. Annotate the ServiceAccount and create IAM binding.

apiVersion: v1
kind: ServiceAccount
metadata:
  name: my-app
  annotations:
    iam.gke.io/gcp-service-account: my-app@project.iam.gserviceaccount.com
serviceaccount-pull-secrets.yaml

Image pull secrets can be attached to ServiceAccounts. All Pods using that ServiceAccount automatically get the pull secrets. Useful for private registries.

apiVersion: v1
kind: ServiceAccount
metadata:
  name: my-app
imagePullSecrets:
  - name: registry-credentials
---
spec:
  serviceAccountName: my-app
  containers:
    - name: app
      image: private-registry.example.com/my-app:v1
terminal

Debug ServiceAccount issues by checking token mounts and RBAC. Token must be present and valid. RBAC must grant required permissions to the ServiceAccount.

$ kubectl exec my-pod -- \
    ls /var/run/secrets/kubernetes.io/serviceaccount/
ca.crt
namespace
token

$ kubectl exec my-pod -- \
    cat /var/run/secrets/kubernetes.io/serviceaccount/token
eyJhbGciOiJSUzI1NiIsImtpZCI6...

$ kubectl auth can-i get pods \
    --as=system:serviceaccount:default:my-app
yes

$ kubectl auth can-i list secrets \
    --as=system:serviceaccount:default:my-app
no

$ kubectl get serviceaccount my-app -o yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: my-app
  namespace: default

Index | GitHub | Use arrow keys to navigate |