TechLead
Lesson 14 of 25
5 min read
Cloud & Kubernetes

Service Accounts

Understand Kubernetes Service Accounts, token management, workload identity, and how to securely authenticate applications within the cluster

What are Service Accounts?

A Service Account provides an identity for processes running in a Pod. While user accounts are for humans interacting with the cluster via kubectl, service accounts are for Pods and workloads that need to interact with the Kubernetes API or external services. Every namespace has a default service account, but production workloads should use dedicated service accounts with minimal permissions.

Service Account Use Cases

  • API Access: Pods that need to query the Kubernetes API (operators, controllers)
  • CI/CD: Automated deployment tools that manage resources
  • Cloud IAM: Mapping K8s identities to cloud provider IAM roles (workload identity)
  • External Services: Authenticating with external services using projected tokens

Creating Service Accounts

# service-account.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: app-service-account
  namespace: production
  labels:
    app: my-application
  annotations:
    # AWS EKS: Map to an IAM role for S3 access
    eks.amazonaws.com/role-arn: "arn:aws:iam::123456789012:role/my-app-role"
    # GKE: Map to a Google Cloud service account
    # iam.gke.io/gcp-service-account: my-app@my-project.iam.gserviceaccount.com
automountServiceAccountToken: false  # Disable auto-mounting for security
# Create service account imperatively
kubectl create serviceaccount app-service-account -n production

# List service accounts
kubectl get serviceaccounts -n production

# Describe a service account
kubectl describe serviceaccount app-service-account -n production

# Create a long-lived token (for external systems)
kubectl create token app-service-account -n production --duration=8760h

Using Service Accounts in Pods

# pod-with-service-account.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-application
  namespace: production
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-application
  template:
    metadata:
      labels:
        app: my-application
    spec:
      serviceAccountName: app-service-account
      automountServiceAccountToken: true  # Override the SA default for this pod
      containers:
      - name: app
        image: myapp:1.0
        ports:
        - containerPort: 3000
        volumeMounts:
        - name: token
          mountPath: /var/run/secrets/tokens
          readOnly: true
      volumes:
      - name: token
        projected:
          sources:
          - serviceAccountToken:
              path: api-token
              expirationSeconds: 3600  # 1 hour
              audience: "https://api.example.com"

Workload Identity (Cloud Integration)

Workload Identity allows Kubernetes service accounts to act as cloud IAM identities, eliminating the need to store and manage cloud credentials as Kubernetes Secrets. This is the recommended approach for giving Pods access to cloud resources.

AWS EKS Workload Identity (IRSA)

# Create an IAM policy
aws iam create-policy --policy-name S3ReadPolicy --policy-document '{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Action": ["s3:GetObject", "s3:ListBucket"],
    "Resource": ["arn:aws:s3:::my-bucket", "arn:aws:s3:::my-bucket/*"]
  }]
}'

# Create an IAM role with trust policy for the EKS OIDC provider
eksctl create iamserviceaccount \
  --name app-service-account \
  --namespace production \
  --cluster my-cluster \
  --attach-policy-arn arn:aws:iam::123456789012:policy/S3ReadPolicy \
  --approve

GKE Workload Identity

# Create a Google Cloud service account
gcloud iam service-accounts create my-app-gsa --display-name="My App SA"

# Grant permissions to the GCP service account
gcloud projects add-iam-policy-binding my-project \
  --member="serviceAccount:my-app-gsa@my-project.iam.gserviceaccount.com" \
  --role="roles/storage.objectViewer"

# Bind the K8s SA to the GCP SA
gcloud iam service-accounts add-iam-policy-binding \
  my-app-gsa@my-project.iam.gserviceaccount.com \
  --role="roles/iam.workloadIdentityUser" \
  --member="serviceAccount:my-project.svc.id.goog[production/app-service-account]"

# Annotate the K8s service account
kubectl annotate serviceaccount app-service-account \
  --namespace production \
  iam.gke.io/gcp-service-account=my-app-gsa@my-project.iam.gserviceaccount.com

RBAC for Service Accounts

# sa-rbac.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: pod-reader
  namespace: production
rules:
- apiGroups: [""]
  resources: ["pods", "pods/log"]
  verbs: ["get", "list", "watch"]
- apiGroups: [""]
  resources: ["configmaps"]
  verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: app-pod-reader
  namespace: production
subjects:
- kind: ServiceAccount
  name: app-service-account
  namespace: production
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

Key Takeaways

  • Every Pod gets a service account — create dedicated ones instead of using the default
  • Set automountServiceAccountToken to false unless the Pod needs API access
  • Use Workload Identity (IRSA on EKS, Workload Identity on GKE) instead of static cloud credentials
  • Projected service account tokens are time-limited and audience-bound for better security
  • Combine service accounts with RBAC Roles to implement least-privilege access

Continue Learning