Module #45 · intermediate Article
ServiceAccounts vs. User Accounts: Identity, Token Auth, and Pod Authorization
ServiceAccounts are identities for pods and processes running inside Kubernetes; user accounts are for humans accessing the cluster from outside — ServiceAcc...
4 min read+15 XPPublished 2026-05-19
Quick Answer: ServiceAccounts are identities for pods and processes running inside Kubernetes; user accounts are for humans accessing the cluster from outside — ServiceAccounts are K8s objects, user accounts are external (OIDC, certs, IAM).
Detailed Answer:
# ServiceAccount — identity for a pod/process
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-app-sa
namespace: production
annotations:
# IRSA on EKS — bind to IAM role (no static credentials needed)
eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/my-app-role
automountServiceAccountToken: false # Disable auto-mount if app doesn't call K8s API
# Best practice: disable by default, enable explicitly
# Using a ServiceAccount in a Pod
spec:
serviceAccountName: my-app-sa # Assign the SA to the pod
automountServiceAccountToken: true # Override SA-level setting if needed
containers:
- name: app
image: myapp:v1
# The SA token is automatically mounted at:
# /var/run/secrets/kubernetes.io/serviceaccount/token
# /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
# /var/run/secrets/kubernetes.io/serviceaccount/namespace
How Pods Use ServiceAccount Tokens:
# Inside a pod — access K8s API using mounted SA token
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
CACERT=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
NAMESPACE=$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace)
# Call K8s API from inside pod (e.g., list configmaps in own namespace)
curl -s --cacert $CACERT \
-H "Authorization: Bearer $TOKEN" \
https://kubernetes.default.svc/api/v1/namespaces/$NAMESPACE/configmaps
# This is how operators, controllers, and monitoring tools
# interact with the K8s API from inside the cluster
IRSA — The Right Way to Access AWS from Pods on EKS:
# Without IRSA — dangerous anti-pattern:
# Hardcode AWS credentials as environment variables or secrets
# Credentials can be stolen from etcd, logs, or pod introspection
# With IRSA — the correct pattern:
# 1. Create IAM role with trust policy for the ServiceAccount
# 2. Annotate ServiceAccount with IAM role ARN
# 3. Pod automatically gets temporary credentials via OIDC token exchange
# Step 1: Create IAM role trust policy
aws iam create-role \
--role-name my-app-role \
--assume-role-policy-document '{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::123456789012:oidc-provider/oidc.eks.us-east-1.amazonaws.com/id/EXAMPLED539D4633E53DE1B716D3041E"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"oidc.eks.us-east-1.amazonaws.com/id/EXAMPLED539D4633E53DE1B716D3041E:sub":
"system:serviceaccount:production:my-app-sa"
}
}
}]
}'
# Step 2: Attach permissions to IAM role
aws iam attach-role-policy \
--role-name my-app-role \
--policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess
# Step 3: Annotate ServiceAccount (Terraform equivalent shown below)
kubectl annotate serviceaccount my-app-sa \
-n production \
eks.amazonaws.com/role-arn=arn:aws:iam::123456789012:role/my-app-role
# Verify IRSA is working from inside pod
kubectl exec -it my-pod -- \
aws sts get-caller-identity
# Should show the IAM role ARN, not EC2 instance role
# Terraform — create IRSA role and annotate SA
module "my_app_irsa" {
source = "terraform-aws-modules/iam/aws//modules/iam-role-for-service-accounts-eks"
version = "~> 5.0"
role_name = "my-app-production"
role_policy_arns = {
s3_read = "arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess"
}
oidc_providers = {
main = {
provider_arn = module.eks.oidc_provider_arn
namespace_service_accounts = ["production:my-app-sa"]
}
}
}
resource "kubernetes_service_account" "my_app" {
metadata {
name = "my-app-sa"
namespace = "production"
annotations = {
"eks.amazonaws.com/role-arn" = module.my_app_irsa.iam_role_arn
}
}
automount_service_account_token = false
}
Key Takeaway: Every pod should have a dedicated ServiceAccount with only the permissions it needs — never use the default ServiceAccount in production, and use IRSA on EKS instead of static AWS credentials.
🔴 ADVANCED LEVEL — Questions 41–80 (mapped to Q151–250 in original plan)
Production Readiness & Enterprise Patterns
Finished reading?
Mark as complete to claim your +15 XP and track progress.
