DEV Community

DevOps Start
DevOps Start

Posted on • Originally published at devopsstart.com

Fix sts:AssumeRoleWithWebIdentity Error in EKS

I originally published this deep-dive on troubleshooting the 'Not authorized to perform sts:AssumeRoleWithWebIdentity' error in EKS over at DevOpsStart. It walks through the three most common root causes — OIDC provider mismatch, trust policy conditions, and audience misalignment — and shows you how to fix each one in minutes.

Introduction

When a pod in Amazon EKS tries to assume an IAM role using a service account annotation and fails with "Not authorized to perform sts:AssumeRoleWithWebIdentity", the root cause is almost always a mismatch between the role's trust policy and the pod's actual web identity token. This error stops your application from accessing any AWS resource. The fix is systematic: validate the OIDC provider, inspect the trust policy, and align the conditions with the token's claims. Following these steps resolves the issue within a few minutes.

Problem

The error message looks like this:

$ aws sts get-caller-identity
An error occurred (AccessDenied) when calling the AssumeRoleWithWebIdentity operation: Not authorized to perform sts:AssumeRoleWithWebIdentity
Enter fullscreen mode Exit fullscreen mode

Your pod is annotated with eks.amazonaws.com/role-arn, which triggers the EKS Pod Identity Webhook to inject environment variables (AWS_ROLE_ARN, AWS_WEB_IDENTITY_TOKEN_FILE). The AWS SDK in the pod then calls sts:AssumeRoleWithWebIdentity with a JWT token from the filesystem. If the token's claims (issuer, subject, audience) don't match the role's trust policy conditions, AWS rejects the request.

Root Causes

Three main things cause this error:

  1. OIDC provider mismatch – The IAM OIDC identity provider for your cluster is missing, or its ARN differs from the one in the trust policy. After a cluster upgrade or OIDC provider rotation, the issuer URL can change.
  2. Trust policy condition mismatch – The "Condition" block in the trust policy must specify "sub" as system:serviceaccount:<namespace>:<service-account-name> and "aud" as sts.amazonaws.com. A typo in the namespace or service account name, or a missing condition, causes denial.
  3. Audience mismatch – The AWS SDK expects the audience claim to be sts.amazonaws.com. If you set a custom audience in your OIDC provider or in the pod's annotation, the token's aud claim will differ and the trust policy condition will fail.

Solution

Step 1: Verify the OIDC provider exists

Run these commands to get your cluster's OIDC issuer URL and check the corresponding IAM provider.

$ aws eks describe-cluster --name <your-cluster-name> --query "cluster.identity.oidc.issuer" --output text
https://oidc.eks.us-east-1.amazonaws.com/id/EXAMPLED1234567890ABC
Enter fullscreen mode Exit fullscreen mode
$ aws iam list-open-id-connect-providers --query "OpenIDConnectProviderList[*].Arn"
Enter fullscreen mode Exit fullscreen mode

The ARN should end with the same ID (EXAMPLED1234567890ABC). If the provider is missing, create it (official documentation).

Step 2: Inspect the current trust policy

$ aws iam get-role --role-name <your-role-name> --query "Role.AssumeRolePolicyDocument"
Enter fullscreen mode Exit fullscreen mode

Compare it to the correct template. The "Action" must be "sts:AssumeRoleWithWebIdentity", and the "Condition" block must look like this:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::<account-id>:oidc-provider/oidc.eks.<region>.amazonaws.com/id/<id>"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "oidc.eks.<region>.amazonaws.com/id/<id>:sub": "system:serviceaccount:<namespace>:<service-account-name>",
          "oidc.eks.<region>.amazonaws.com/id/<id>:aud": "sts.amazonaws.com"
        }
      }
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Step 3: Fix the trust policy

If the Principal.Federated ARN or the condition values are wrong, update the policy:

$ aws iam update-assume-role-policy --role-name <your-role-name> --policy-document file://fixed-trust-policy.json
Enter fullscreen mode Exit fullscreen mode

Step 4: Verify inside the pod

Deploy a debug pod that uses the same service account and run:

$ kubectl run debug --image=amazon/aws-cli -n <namespace> --overrides='{"spec":{"serviceAccountName":"<sa-name>"}}' --rm -it -- sh
Enter fullscreen mode Exit fullscreen mode

Inside the pod:

$ cat /var/run/secrets/eks.amazonaws.com/serviceaccount/token | cut -d. -f2 | base64 -d | jq
Enter fullscreen mode Exit fullscreen mode

The output shows the "iss", "sub", and "aud" claims. The aud must be "sts.amazonaws.com" and sub must be "system:serviceaccount:<namespace>:<sa-name>". Then run:

$ aws sts get-caller-identity
Enter fullscreen mode Exit fullscreen mode

If it returns the assumed role ARN, the fix works.

Prevention

To avoid this error in the future:

  • Use eksctl create iamserviceaccount to create both the IAM role and the service account in one command. This automatically generates the correct trust policy.
  • After a cluster upgrade, verify the OIDC provider ARN hasn't changed. Compare the cluster's issuer URL with the provider ARN.
  • For multi-namespace scenarios, use a wildcard in the sub condition: "stringLike": { "oidc.eks.*:sub": "system:serviceaccount:*:<sa-name>" }.

For a deeper dive into EKS cluster setup, see our tutorial on Deploy an EKS Cluster with Terraform. If you encounter other pod startup issues, check our guide on How to Debug OOMKilled Pods in Kubernetes.

Top comments (0)