How does IRSA let Kubernetes pods access AWS services without hardcoded credentials?
Quick Answer
IRSA (IAM Roles for Service Accounts) uses an OIDC identity provider to authenticate Kubernetes service account tokens with AWS IAM. The pod receives a projected service account token, presents it to AWS STS, and receives short-lived credentials scoped to a specific IAM role. No access keys are stored in secrets or environment variables.
Detailed Answer
Think of a hotel key card system. Instead of giving every guest a master key (hardcoded credentials), the front desk verifies your identity (OIDC provider), issues a card (short-lived token) that only opens your specific room (IAM role), and the card expires at checkout. If someone steals the card, it stops working soon and only ever opened one room. IRSA works the same way for pods accessing AWS services.
Without IRSA, teams typically use one of three insecure patterns: storing AWS access keys in Kubernetes Secrets (which can leak through RBAC, etcd backups, or misconfigured pod access), assigning an IAM instance profile to the entire node (which gives every pod on that node the same permissions), or using tools like kube2iam that intercept the metadata endpoint (which adds complexity and latency). IRSA eliminates all three by giving each pod its own identity that AWS trusts directly.
The mechanism works through several coordinated components. First, the EKS cluster has an OIDC provider registered with AWS IAM. This tells AWS to trust tokens issued by the Kubernetes API server. Second, an IAM role is created with a trust policy that specifies which Kubernetes service account in which namespace can assume it. The trust policy condition checks the OIDC issuer, the audience, and the subject (system:serviceaccount:namespace:sa-name). Third, the Kubernetes ServiceAccount is annotated with eks.amazonaws.com/role-arn pointing to the IAM role. Fourth, when a pod using that ServiceAccount starts, the EKS pod identity webhook injects a projected service account token volume and sets AWS_ROLE_ARN and AWS_WEB_IDENTITY_TOKEN_FILE environment variables. The AWS SDK in the application reads these, calls STS AssumeRoleWithWebIdentity, and receives temporary credentials.
In production, IRSA provides least-privilege access at the pod level. The payments-api can access only the S3 bucket it needs and the SQS queue it consumes from, while the checkout-worker in the same namespace can access DynamoDB but not S3. If one pod is compromised, the blast radius is limited to its specific IAM role permissions. Tokens are automatically rotated (default expiry is 12 hours, configurable down to 15 minutes), and credential theft is detectable through CloudTrail.
The non-obvious gotcha is that IRSA requires the application to use an AWS SDK version that supports web identity token authentication (SDK v2 or AWS SDK for Go v1.25+, Python boto3 1.9.220+). Legacy applications that only read from environment variables for static keys will not work without code changes. Another common issue is trust policy misconfiguration: if the namespace or service account name in the condition does not match exactly, AssumeRole fails silently and the pod falls back to node-level permissions or gets AccessDenied. EKS Pod Identity is the newer alternative that simplifies the trust policy setup but requires the EKS Pod Identity Agent DaemonSet.