IAM Roles for Service Accounts (IRSA)
Bind fine-grained IAM roles to Kubernetes service accounts with IRSA so pods can access AWS services without node-level permissions.
IAM Roles for Service Accounts (IRSA) is a free AWS Solutions Architect lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the AWS Solutions Architect learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
The Pod IAM Problem
When a pod running in EKS needs to call an AWS API — for example, read from S3 or write to DynamoDB — it needs AWS credentials. The naive approach is to create an IAM user and hard-code its access keys as environment variables. This is insecure and violates the principle of least privilege because all pods on the same node share credentials. IAM Roles for Service Accounts (IRSA) solves this by binding fine-grained IAM roles directly to Kubernetes service accounts.
How IRSA Works: OIDC Federation
IRSA works through OpenID Connect (OIDC) federation. EKS creates an OIDC provider for your cluster. When a pod references a service account annotated with an IAM role ARN, EKS injects a signed projected service account token into the pod. The AWS SDK in the pod exchanges this token for temporary AWS credentials using AWS STS's AssumeRoleWithWebIdentity API — no long-lived keys required.
# View the OIDC issuer URL for your cluster
aws eks describe-cluster \
--name my-cluster \
--query 'cluster.identity.oidc.issuer' \
--output text
# Example output:
# https://oidc.eks.us-east-1.amazonaws.com/id/EXAMPLEIDSTRINGStep 1: Associate OIDC Provider
Before using IRSA, you must associate the EKS OIDC issuer as a trusted identity provider in your AWS account. This creates an IAM OIDC provider resource that AWS STS will recognise. The eksctl command handles this automatically. Once created, you can verify it in the IAM console under Identity Providers.
# Associate the OIDC provider using eksctl (simplest method)
eksctl utils associate-iam-oidc-provider \
--region us-east-1 \
--cluster my-cluster \
--approve
# Verify the provider was created
aws iam list-open-id-connect-providers \
--query 'OpenIDConnectProviderList[].Arn'Step 2: Create the IAM Role
The IAM role for IRSA must have a trust policy that allows the OIDC provider to assume it, scoped to a specific Kubernetes namespace and service account. The condition uses the sub claim in the OIDC token, which is set to system:serviceaccount:NAMESPACE:SERVICE_ACCOUNT_NAME. This ensures only pods using that specific service account can assume the role — not any pod in the cluster.
# Trust policy for the IRSA role (JSON)
# {
# "Version": "2012-10-17",
# "Statement": [{
# "Effect": "Allow",
# "Principal": {
# "Federated": "arn:aws:iam::111122223333:oidc-provider/oidc.eks.us-east-1.amazonaws.com/id/EXAMPLEID"
# },
# "Action": "sts:AssumeRoleWithWebIdentity",
# "Condition": {
# "StringEquals": {
# "oidc.eks.us-east-1.amazonaws.com/id/EXAMPLEID:sub":
# "system:serviceaccount:production:s3-reader"
# }
# }
# }]
# }Step 3: Annotate the Service Account
Create a Kubernetes ServiceAccount in the target namespace and annotate it with the IAM role ARN. When a pod references this service account, EKS injects the OIDC token and two environment variables (AWS_WEB_IDENTITY_TOKEN_FILE and AWS_ROLE_ARN) automatically. The AWS SDK automatically detects these and calls STS to obtain temporary credentials — no code changes required in your application.
# Create and annotate the Kubernetes service account
kubectl create serviceaccount s3-reader -n production
kubectl annotate serviceaccount s3-reader \
-n production \
eks.amazonaws.com/role-arn=arn:aws:iam::111122223333:role/S3ReaderRole
# Verify the annotation
kubectl describe serviceaccount s3-reader -n productionStep 4: Reference the Service Account in Pods
In your pod or deployment spec, set serviceAccountName to the annotated service account. When EKS schedules the pod, it automatically mounts the OIDC token at /var/run/secrets/eks.amazonaws.com/serviceaccount/token and sets the required environment variables. Any AWS SDK call inside the pod will transparently use the mapped IAM role credentials without any explicit credential configuration.
# Pod spec using IRSA service account
apiVersion: v1
kind: Pod
metadata:
name: s3-app
namespace: production
spec:
serviceAccountName: s3-reader
containers:
- name: app
image: 111122223333.dkr.ecr.us-east-1.amazonaws.com/my-app:latest
# AWS SDK auto-detects IRSA — no credential config needed
# AWS_WEB_IDENTITY_TOKEN_FILE and AWS_ROLE_ARN are injectedIRSA vs Node IAM Role: Key Differences
With a node IAM role, every pod on a node inherits the same permissions — a compromised pod can access all AWS services the node is allowed to access. With IRSA, each pod (via its service account) assumes only the role it needs. This follows the principle of least privilege at the pod level and limits the blast radius of any security incident. AWS recommends IRSA over node-level roles for all new EKS deployments.
Using eksctl to Create IRSA Roles
eksctl can create the OIDC association, IAM role, trust policy, and Kubernetes ServiceAccount annotation in a single command using create iamserviceaccount. This is the simplest way to set up IRSA without manually writing trust policy JSON. You specify the namespace, service account name, and the IAM policy ARN to attach, and eksctl handles the rest.
# Create everything needed for IRSA in one command
eksctl create iamserviceaccount \
--name s3-reader \
--namespace production \
--cluster my-cluster \
--attach-policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess \
--approve \
--override-existing-serviceaccountsIRSA for AWS Add-Ons
Many EKS add-ons and controllers require IRSA to function: Cluster Autoscaler needs permission to call the EC2 Auto Scaling API, the AWS Load Balancer Controller needs permission to create and manage ELB resources, external-dns needs Route 53 write access, and the EBS CSI driver needs permission to create and attach EBS volumes. Always use IRSA for these system components — never grant the permissions at the node IAM role level.
# Create IRSA for the EBS CSI driver
eksctl create iamserviceaccount \
--name ebs-csi-controller-sa \
--namespace kube-system \
--cluster my-cluster \
--attach-policy-arn arn:aws:iam::aws:policy/service-role/AmazonEBSCSIDriverPolicy \
--approve \
--role-name AmazonEKS_EBS_CSI_DriverRoleToken Refresh and Credential Rotation
IRSA tokens are short-lived and automatically rotated by the Kubernetes token projection controller before they expire. The default token audience is sts.amazonaws.com and the expiry is 24 hours, but the controller refreshes them at 80% of their lifetime. AWS STS credentials obtained via IRSA are also temporary (typically 1 hour). This automatic rotation eliminates the credential-rotation burden that comes with long-lived IAM access keys.
# Inspect the projected service account token inside a pod
kubectl exec -n production s3-app -- \
cat /var/run/secrets/eks.amazonaws.com/serviceaccount/token
# Decode the JWT header and payload to see expiry and audience
# jwt.io or: base64 -d <<< "PAYLOAD_SECTION"Auditing IRSA Usage with CloudTrail
Every time a pod assumes an IAM role via IRSA, AWS CloudTrail records an AssumeRoleWithWebIdentity event. The event includes the assumed role ARN, the OIDC token subject (system:serviceaccount:NAMESPACE:SERVICE_ACCOUNT), and the source IP. This provides a complete audit trail of which pods accessed which AWS services and when — critical for compliance and incident investigation in regulated environments.
# Search CloudTrail for IRSA calls
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=EventName,AttributeValue=AssumeRoleWithWebIdentity \
--start-time '2024-01-01T00:00:00Z' \
--query 'Events[].{Time:EventTime,Role:CloudTrailEvent}' \
--output tableQuick Check
Test your understanding of AWS Solutions Architect (SAA-C03) concepts from this lesson.
Lesson Recap
In this lesson you learned: IRSA uses OIDC federation to exchange Kubernetes service account tokens for temporary AWS credentials, IAM role trust policies scope access to a specific namespace and service account, and IRSA provides per-pod least-privilege far superior to node-level IAM roles. Next up we explore CloudWatch Metrics, Namespaces, and Dimensions for observing your AWS resources.
Frequently asked questions
Is the “IAM Roles for Service Accounts (IRSA)” lesson free?
Yes — the full text of “IAM Roles for Service Accounts (IRSA)” is free to read here on the web, and the AWS Solutions Architect course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the AWS Solutions Architect course, upgrade to CoddyKit PRO.
What will I learn in “IAM Roles for Service Accounts (IRSA)”?
Bind fine-grained IAM roles to Kubernetes service accounts with IRSA so pods can access AWS services without node-level permissions. You practise AWS Solutions Architect with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start AWS Solutions Architect?
No prior experience is required. AWS Solutions Architect on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “IAM Roles for Service Accounts (IRSA)” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this AWS Solutions Architect lesson?
Yes. Every AWS Solutions Architect lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- EKS Control Plane and Worker Nodes
- Fargate Profiles for Serverless Pods
- EKS Networking: VPC CNI and Load Balancing
- IAM Roles for Service Accounts (IRSA)