Introduction

IAM Roles for Service Accounts (IRSA) lets Kubernetes pods assume AWS IAM roles. When IRSA fails, pods can't access AWS services like S3, DynamoDB, or Secrets Manager despite having the correct service account annotation.

Symptoms

Pod can't access AWS services:

```bash $ kubectl logs my-pod

botocore.exceptions.ClientError: An error occurred (AccessDenied) when calling the GetObject operation ```

AWS SDK not finding credentials:

```bash $ kubectl exec -it my-pod -- env | grep AWS

AWS_ROLE_ARN=arn:aws:iam::123456789:role/my-role AWS_WEB_IDENTITY_TOKEN_FILE=/var/run/secrets/eks.amazonaws.com/serviceaccount/token # Token file exists but AWS still returns AccessDenied ```

Service account annotation missing:

```bash $ kubectl get sa my-service-account -o yaml

# No eks.amazonaws.com/role-arn annotation ```

Common Causes

  1. 1.OIDC provider not configured - Cluster doesn't have OIDC identity provider
  2. 2.Wrong trust policy - Role doesn't trust the correct OIDC provider
  3. 3.Service account not annotated - Missing role ARN annotation
  4. 4.Incorrect subject in trust policy - Wrong service account name or namespace
  5. 5.AWS SDK version issue - Old SDK doesn't support web identity
  6. 6.Token file missing - Pod doesn't have projected service account token

Step-by-Step Fix

  1. 1.Check logs for specific error messages
  2. 2.Verify configuration settings
  3. 3.Test network connectivity
  4. 4.Review recent changes
  5. 5.Apply corrective action
  6. 6.Verify the fix

Step 1: Check OIDC Provider Exists

```bash # Get cluster OIDC issuer URL aws eks describe-cluster --name my-cluster \ --query 'cluster.identity.oidc.issuer'

# Example: https://oidc.eks.region.amazonaws.com/id/EXAMPLED539D18

# Check if IAM OIDC provider exists aws iam list-open-id-connect-providers \ --query 'OpenIDConnectProviderList[*].Arn'

# If missing, create it eksctl utils associate-iam-oidc-provider --cluster my-cluster --approve

# Or manually: OIDC_ID=$(aws eks describe-cluster --name my-cluster \ --query 'cluster.identity.oidc.issuer' --output text | cut -d'/' -f5)

aws iam create-open-id-connect-provider \ --url https://oidc.eks.region.amazonaws.com/id/$OIDC_ID \ --client-id-list sts.amazonaws.com \ --thumbprint-list 9e99a48a9960b14926bb7f3b02e22da2b0ab7280 ```

Step 2: Verify Service Account Annotation

```bash # Check service account annotation kubectl get sa my-service-account -n my-namespace -o yaml

# Should have annotation: metadata: annotations: eks.amazonaws.com/role-arn: arn:aws:iam::ACCOUNT:role/my-role

# Add annotation if missing kubectl annotate sa my-service-account -n my-namespace \ eks.amazonaws.com/role-arn=arn:aws:iam::ACCOUNT:role/my-role

# Restart pods to pick up new annotation kubectl rollout restart deployment/my-deployment -n my-namespace ```

Step 3: Check IAM Role Trust Policy

```bash # Get role trust policy aws iam get-role --role-name my-role \ --query 'Role.AssumeRolePolicyDocument'

# Must trust the OIDC provider with correct subject: { "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:my-namespace:my-service-account" } } } ] } ```

Step 4: Fix Trust Policy Subject

The subject must match exactly: system:serviceaccount:NAMESPACE:SERVICE_ACCOUNT_NAME

```bash # Create role with correct trust policy cat > trust-policy.json << EOF { "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:my-namespace:my-service-account" } } } ] } EOF

aws iam update-assume-role-policy \ --role-name my-role \ --policy-document file://trust-policy.json ```

Step 5: Verify Pod Has Token File

```bash # Check if pod has token mounted kubectl exec -it my-pod -n my-namespace -- ls -la /var/run/secrets/eks.amazonaws.com/serviceaccount/

# Should show: # token # aws_iam_role

# Check token content kubectl exec -it my-pod -n my-namespace -- cat /var/run/secrets/eks.amazonaws.com/serviceaccount/token

# Decode JWT to verify claims kubectl exec -it my-pod -n my-namespace -- cat /var/run/secrets/eks.amazonaws.com/serviceaccount/token | cut -d'.' -f2 | base64 -d | jq ```

Step 6: Check IAM Role Permissions

```bash # Verify role has the needed permissions aws iam list-attached-role-policies --role-name my-role

# Test if role can be assumed aws sts assume-role-with-web-identity \ --role-arn arn:aws:iam::ACCOUNT:role/my-role \ --role-session-name test-session \ --web-identity-token TOKEN_VALUE ```

Add permissions if missing:

bash
aws iam attach-role-policy \
  --role-name my-role \
  --policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess

Step 7: Debug with AWS CLI in Pod

```bash # Run test pod with AWS CLI kubectl run aws-cli --image=amazon/aws-cli --rm -it --restart=Never \ --serviceaccount=my-service-account \ -- aws s3 ls

# Should list S3 buckets if IRSA working

# Check environment variables kubectl exec -it my-pod -- env | grep AWS

# Should show: # AWS_ROLE_ARN=arn:aws:iam::... # AWS_WEB_IDENTITY_TOKEN_FILE=/var/run/seeks/eks.amazonaws.com/serviceaccount/token ```

Step 8: Check for Multiple Service Accounts

```bash # If pod uses multiple service accounts, only first one is used kubectl get pod my-pod -o jsonpath='{.spec.serviceAccountName}'

# Ensure the annotated service account is the one used by the pod ```

Step 9: Verify AWS SDK Version

```bash # AWS SDK must support web identity # Python boto3 >= 1.9.0 # Java SDK >= 1.11.704 # Node.js SDK >= 2.425.0 # Go SDK >= 1.23.0

# Check SDK version in application logs or dependencies # For Python: kubectl exec -it my-pod -- python -c "import boto3; print(boto3.__version__)"

# For Node.js: kubectl exec -it my-pod -- npm list aws-sdk ```

Step 10: Test with Minimal Example

```bash # Create test deployment kubectl apply -f - <<EOF apiVersion: v1 kind: ServiceAccount metadata: name: test-sa annotations: eks.amazonaws.com/role-arn: arn:aws:iam::ACCOUNT:role/test-role --- apiVersion: apps/v1 kind: Deployment metadata: name: test-irsa spec: selector: matchLabels: app: test-irsa template: metadata: labels: app: test-irsa spec: serviceAccountName: test-sa containers: - name: aws-cli image: amazon/aws-cli command: ["sleep", "3600"] EOF

# Test S3 access kubectl exec -it deployment/test-irsa -- aws s3 ls ```

IRSA Troubleshooting Checklist

  • [ ] OIDC provider exists in IAM
  • [ ] Service account has role-arn annotation
  • [ ] Role trust policy references correct OIDC provider
  • [ ] Subject matches system:serviceaccount:NAMESPACE:SA_NAME
  • [ ] Pod uses correct service account
  • [ ] AWS SDK version supports web identity
  • [ ] Role has necessary AWS permissions

Verification

```bash # Test AWS service access from pod kubectl exec -it my-pod -n my-namespace -- aws s3 ls

# Should list buckets without AccessDenied

# Check CloudTrail for AssumeRoleWithWebIdentity aws cloudtrail lookup-events \ --lookup-attributes AttributeKey=EventName,AttributeValue=AssumeRoleWithWebIdentity \ --max-items 5 ```

  • [Fix AWS EKS Node Not Joining](/articles/fix-aws-eks-node-not-joining)
  • [Fix AWS EKS Pod Networking Failed](/articles/fix-aws-eks-pod-networking-failed)
  • [Fix AWS S3 Bucket Policy Denied](/articles/fix-aws-s3-bucket-policy-denied)
  • [AWS troubleshooting: Fix IAM Permission Denied - Complete Tro](fix-iam-permission-denied)
  • [AWS cloud troubleshooting: AWS ACM Certificate Pending Validation Because the](aws-acm-certificate-pending-validation-wrong-route53-zone)
  • [AWS cloud troubleshooting: AWS ALB Returns 502 Because the Target Closed the ](aws-alb-502-target-closed-connection-keepalive-timeout-mismatch)
  • [AWS cloud troubleshooting: Fix AWS ALB CreateListener TargetGroupNotFound Err](aws-alb-createlistener-targetgroupnotfound)
  • [AWS cloud troubleshooting: Fix Aws Alb Lambda 502 Bad Gateway Issue in AWS](aws-alb-lambda-502-bad-gateway)

<script type="application/ld+json"> { "@context": "https://schema.org", "@type": "TechArticle", "headline": "Fix AWS EKS IAM Role for Service Account (IRSA) Not Working", "description": "Troubleshoot EKS IRSA issues. Fix OIDC provider, IAM roles, trust policies, and service account annotations.", "url": "https://www.fixwikihub.com/fix-aws-eks-iam-role-for-service-account", "publisher": { "@type": "Organization", "name": "FixWikiHub", "url": "https://www.fixwikihub.com" }, "author": { "@type": "Person", "name": "FixWikiHub Editorial Team" }, "datePublished": "2026-04-01T22:41:02.146Z", "dateModified": "2026-04-01T22:41:02.146Z" } </script>