Infra Notes

GitHub Actions OIDC to AWS: fix AssumeRoleWithWebIdentity AccessDenied

Diagnose AWS AssumeRoleWithWebIdentity AccessDenied in GitHub Actions by checking token permissions, audience, role ARN, and IAM trust-policy subject claims.

Published

CI/CDGitHub Actions OIDCAWS IAMAssumeRoleWithWebIdentityAccessDenied

Problem

A GitHub Actions workflow using AWS OIDC fails with Not authorized to perform sts:AssumeRoleWithWebIdentity or AccessDenied. The failure usually occurs before AWS permission policies are evaluated: AWS does not trust the identity represented by the workflow token.

Quick answer

Check four boundaries in order:

  1. The job can request an ID token.
  2. The workflow uses the intended AWS role ARN and Region.
  3. The AWS OIDC provider has the correct issuer and audience.
  4. The role trust policy matches the token’s sub claim for the repository, branch, tag, pull request, or environment.

The workflow needs:

yaml

permissions:
  contents: read
  id-token: write

steps:
  - uses: aws-actions/configure-aws-credentials@<pinned-version>
    with:
      role-to-assume: arn:aws:iam::<account-id>:role/<role-name>
      aws-region: ap-southeast-1

Pin third-party actions according to your supply-chain policy, preferably to a reviewed commit SHA.

Check the trust policy

For GitHub’s official AWS credentials flow, the provider URL is https://token.actions.githubusercontent.com and the audience is sts.amazonaws.com. Restrict the subject instead of trusting every repository:

json

{
  "Effect": "Allow",
  "Principal": {
    "Federated": "arn:aws:iam::<account-id>:oidc-provider/token.actions.githubusercontent.com"
  },
  "Action": "sts:AssumeRoleWithWebIdentity",
  "Condition": {
    "StringEquals": {
      "token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
      "token.actions.githubusercontent.com:sub": "repo:owner/repository:ref:refs/heads/main"
    }
  }
}

Repository and branch names are case-sensitive in the resulting claim. A workflow using a GitHub Environment produces a different subject form, such as repo:owner/repository:environment:production. Match the actual workflow context and keep the condition as narrow as operationally possible.

Separate trust from role permissions

If configure-aws-credentials cannot obtain credentials, debug the OIDC provider and trust policy. If credentials are issued but a later aws command is denied, debug the role’s identity policy, permission boundary, session policy, or organization SCP instead.

Verify the assumed identity immediately after authentication:

bash

aws sts get-caller-identity

This prevents a later deployment failure from being incorrectly attributed to OIDC.

Common mismatches

  • id-token: write is missing or overridden by job-level permissions.
  • The role exists in a different AWS account than the ARN used by the workflow.
  • The audience does not match sts.amazonaws.com.
  • The trust policy allows main, but the workflow runs from a tag, pull request, or environment.
  • The reusable workflow’s repository context differs from the caller assumptions.
  • The IAM provider or role was recently changed but the workflow still references an old ARN.

Do not solve this by changing the subject condition to a global wildcard. Broader trust converts a deployment error into a cross-repository privilege risk.

For local identity confusion, use AWS SSO login and profile verification. For pipeline design, see the Infrastructure as Code platform blueprint.

References