← Back

IRSA on EKS

IAM Roles for Service Accounts · OIDC trust · Token exchange · All interactive

What is IRSA and why does it exist? click each option
Your pod needs to call an AWS service (DynamoDB, S3, SES…). How does it prove to AWS who it is? Pick an approach below to see why it's good or bad.
How bad is the shared node role? before vs after
Click a pod to see what AWS services it can reach. Before IRSA, every pod on the node shared the EC2 instance role — one breach meant full access to everything. IRSA gives each pod its own scoped IAM role.
❌ Before IRSA — shared EC2 instance role
EC2 Node (single IAM role for everything)
💳 billing-svc
🖥 frontend
📊 analytics
← click a pod to see its access
✅ With IRSA — each pod gets its own role
EKS Node (pod-level IAM via OIDC)
💳 billing-svc
🖥 frontend
📊 analytics
← click a pod to see its access
The core problem IRSA solves: In the pre-IRSA world, pods called the EC2 Instance Metadata Service (IMDS) to get temporary credentials — but those credentials belonged to the node's IAM role, shared by all pods. A single vulnerable pod could read S3 buckets, DynamoDB tables, or Secrets Manager entries it had no business touching. IRSA introduces pod-level identity: each ServiceAccount maps to its own IAM role via OIDC, so a compromised pod can only reach what its specific role allows.
Scenario:
1. ServiceAccount & IAM Role setup interactive
Edit the inputs — the YAML manifest and eksctl command update live. Click "Apply to cluster" to see the resources appear.
Challenge: Build a SA + Role for a billing service in the payments namespace using DynamoDB read access.
eksctl one-liner
Manual YAML

What this does in one shot: creates the IAM role · attaches the policy · configures the trust policy with your cluster's OIDC provider · creates the K8s ServiceAccount with the eks.amazonaws.com/role-arn annotation.

Manual mode: you create the IAM role + trust policy via Terraform/CLI, then apply this YAML. The annotation tells the EKS Pod Identity Webhook to inject the projected token at pod startup.

🔑
OIDC Provider
🎭
IAM Role
📛
ServiceAccount
2. Configuration validation chain live validation
Four pieces must agree for IRSA to work: OIDC ProviderIAM Trust PolicyServiceAccountPod. Edit any field — links turn green/red instantly, and you'll see the AWS error if broken.
Checking...
Click any link to highlight the related fields.
IAM Trust Policy
OIDC registered
Federated·
Condition
sub
aud
ServiceAccount & Pod
SA namespace
SA name
role-arn anno·
Pod uses SA
Pod namespace
AWS error
✓ Configuration valid
The pod's SDK will be able to call sts:AssumeRoleWithWebIdentity and receive temporary credentials. DynamoDB calls will work using the role's permissions.
3. Token exchange flow — AssumeRoleWithWebIdentity step-by-step
Watch the request travel from the pod to DynamoDB. Each step shows what AWS actually sees in the API call. Try the failure presets above — different scenarios fail at different steps.
Pod / Cluster
1
Pod scheduled
webhook injects env vars + projected token volume
2
SDK reads env
AWS_ROLE_ARN, AWS_WEB_IDENTITY_TOKEN_FILE
3
Token loaded
/var/run/secrets/eks.amazonaws.com/.../token
AWS STS
4
AssumeRoleWithWebIdentity
POST sts.amazonaws.com
5
Verify JWT signature
fetch JWKS from OIDC issuer
6
Check trust policy
match sub, aud against conditions
DynamoDB call
7
Receive temp creds
AccessKeyId, SecretKey, SessionToken
8
Sign API call
SigV4 with temp credentials
9
DynamoDB GetItem
TableName: Users · Key: { id: 42 }
# Press "Auto-play" or "Step ▶" to start the token exchange
4. JWT token inspector live decode
The projected service account token is a real JWT. Edit the claims on the left, see the trust policy match on the right.
Predict-then-verify: change a single character in the namespace — does the policy still match?
Projected SA token
iss·
sub·
aud·
exp·
iat·
kubernetes.io/ namespace·
IAM Trust Policy
5. Pitfall diagnostic lab game mode
Each scenario presents a real production symptom. Inspect the panels, then pick the root cause from the choices.
No second chances — read carefully before clicking.

Reference — commands, manifests, and gotchas

Trust policy template (the canonical IRSA trust policy)
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": {
      "Federated": "arn:aws:iam::<ACCOUNT>:oidc-provider/oidc.eks.<REGION>.amazonaws.com/id/<OIDC_ID>"
    },
    "Action": "sts:AssumeRoleWithWebIdentity",
    "Condition": {
      "StringEquals": {
        "oidc.eks.<REGION>.amazonaws.com/id/<OIDC_ID>:sub": "system:serviceaccount:<NS>:<SA>",
        "oidc.eks.<REGION>.amazonaws.com/id/<OIDC_ID>:aud": "sts.amazonaws.com"
      }
    }
  }]
}

Critical: use StringEquals, not StringLike. StringLike with wildcards is the #1 IRSA security gap — it lets any SA in the cluster assume the role.

Pod Identity Webhook — what it injects

When a pod is created using a SA with the eks.amazonaws.com/role-arn annotation, the mutating webhook injects:

You can verify with: kubectl get mutatingwebhookconfiguration pod-identity-webhook -o yaml

Token rotation — why projected tokens, not regular SA tokens

Old K8s SA tokens were long-lived and stored in Secrets. Projected tokens have:

The AWS SDK re-reads the token file before each STS call, so rotation is transparent to the application.

Common AWS errors and what they actually mean
Debugging IRSA — kubectl & AWS CLI commands
# 1. Verify SA has the annotation
kubectl get sa <name> -n <ns> -o yaml | grep role-arn

# 2. Check that webhook injected env vars
kubectl exec <pod> -- env | grep AWS_

# 3. Verify projected token exists
kubectl exec <pod> -- ls -la /var/run/secrets/eks.amazonaws.com/serviceaccount/

# 4. Decode the JWT to see claims (paste at jwt.io)
kubectl exec <pod> -- cat /var/run/secrets/eks.amazonaws.com/serviceaccount/token

# 5. List OIDC providers registered in IAM
aws iam list-open-id-connect-providers

# 6. Inspect the role's trust policy
aws iam get-role --role-name <name> --query 'Role.AssumeRolePolicyDocument'

# 7. Test from inside the pod
kubectl exec <pod> -- aws sts get-caller-identity
EKS Pod Identity (the 2023 alternative)

AWS introduced EKS Pod Identity as a simpler alternative — no OIDC provider, no trust policy with cluster IDs. Instead, an EKS Pod Identity Agent DaemonSet acts like the EC2 IMDS for pods.

IRSA still has its place: cross-account roles, EKS Anywhere, self-managed Kubernetes, or any time you need OIDC federation. Most existing fleets are still IRSA.