AWS

This integration guide is for accepting workload identity that has already been published through oidc.pub. Configure AWS IAM to trust the oidc.pub discovery endpoint as an OpenID Connect identity provider, then allow workloads to assume IAM roles using sts:AssumeRoleWithWebIdentity without static credentials.

AWS: Creating OpenID Connect identity providers

1. Create the OIDC identity provider

Register your oidc.pub subdomain as an OpenID Connect identity provider in AWS IAM. Replace myservice.oidc.pub with your actual subdomain.

# Terraform
resource "aws_iam_openid_connect_provider" "oidcpub" {
  url             = "https://myservice.oidc.pub"
  client_id_list  = ["sts.amazonaws.com"]
  thumbprint_list = [] # AWS fetches this automatically for public CAs
}

The client_id_list must include the aud claim that your tokens carry. Most setups use sts.amazonaws.com, but the value depends on the provider — with GitLab CI, for instance, you set the audience explicitly in the job's id_tokens config (commonly the issuer URL itself).

2. Create the IAM role

Create an IAM role with a trust policy that allows sts:AssumeRoleWithWebIdentity from your OIDC provider. The Condition block restricts which identities can assume the role by matching the sub and aud claims in the token.

# Terraform
resource "aws_iam_role" "workload_role" {
  name = "oidcpub-workload-role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect = "Allow"
      Principal = {
        Federated = aws_iam_openid_connect_provider.oidcpub.arn
      }
      Action = "sts:AssumeRoleWithWebIdentity"
      Condition = {
        StringEquals = {
          "myservice.oidc.pub:aud" = "sts.amazonaws.com"
          "myservice.oidc.pub:sub" = "your-subject-claim"
        }
      }
    }]
  })
}

The sub condition depends on your OIDC provider — see the provider-specific examples below for the correct values.

Limited claim support: AWS IAM trust policies can only match sub, aud, and amr claims from the OIDC token — custom claims are not supported as condition keys. You can use StringLike with wildcards (*, ?) for pattern matching on these claims. AWS: Available keys for IAM web identity federation

3. Assume the role

From your workload, call sts:AssumeRoleWithWebIdentity with your OIDC token. Most AWS SDKs handle this automatically when AWS_WEB_IDENTITY_TOKEN_FILE and AWS_ROLE_ARN are set.

aws sts assume-role-with-web-identity \
  --role-arn arn:aws:iam::123456789012:role/oidcpub-workload-role \
  --role-session-name my-session \
  --web-identity-token "$OIDC_TOKEN"

Provider-specific examples

Each OIDC provider uses different sub and aud claims. Use the examples below to adapt the general setup to your provider.

Kubernetes (IRSA)

Kubernetes service account tokens use sts.amazonaws.com as the audience and the service account identifier as the subject. See the Kubernetes guide for full setup instructions.

// Trust policy condition
"Condition": {
  "StringEquals": {
    "k8s-prod.oidc.pub:aud": "sts.amazonaws.com",
    "k8s-prod.oidc.pub:sub": "system:serviceaccount:default:my-app"
  }
}

Add a projected volume to your Pod spec with the correct audience, and set the AWS_WEB_IDENTITY_TOKEN_FILE and AWS_ROLE_ARN environment variables so the AWS SDK picks them up automatically.

# Pod spec
apiVersion: v1
kind: Pod
metadata:
  name: my-app
spec:
  serviceAccountName: my-app
  containers:
    - name: app
      image: my-app:latest
      env:
        - name: AWS_WEB_IDENTITY_TOKEN_FILE
          value: /var/run/secrets/oidc/token
        - name: AWS_ROLE_ARN
          value: arn:aws:iam::123456789012:role/k8s-pod-role
      volumeMounts:
        - name: oidc-token
          mountPath: /var/run/secrets/oidc
          readOnly: true
  volumes:
    - name: oidc-token
      projected:
        sources:
          - serviceAccountToken:
              audience: sts.amazonaws.com
              expirationSeconds: 3600
              path: token

HashiCorp Vault

Vault's OIDC identity tokens do not include an sts.amazonaws.com audience by default — you need to configure it on the OIDC role. See the Vault guide for full setup instructions.

# Vault OIDC role
vault write identity/oidc/role/aws-workload \
  key=my-key \
  client_id="sts.amazonaws.com" \
  ttl=1h
# Obtain a token
OIDC_TOKEN=$(vault read -field=token identity/oidc/token/aws-workload)
// Trust policy condition
"Condition": {
  "StringEquals": {
    "vault.oidc.pub:aud": "sts.amazonaws.com",
    "vault.oidc.pub:sub": "vault-entity-id"
  }
}

GitLab CI

GitLab CI ID tokens carry whatever audience you set in the job's id_tokens configuration — it must be specified explicitly (here, the issuer URL). The subject encodes the project path and ref. See the GitLab CI guide for full setup instructions.

// Trust policy condition
"Condition": {
  "StringEquals": {
    "gitlab.oidc.pub:aud": "https://gitlab.oidc.pub"
  },
  "StringLike": {
    "gitlab.oidc.pub:sub": "project_path:mygroup/myproject:ref_type:branch:ref:main"
  }
}
# .gitlab-ci.yml
deploy:
  id_tokens:
    OIDC_TOKEN:
      aud: https://gitlab.oidc.pub
  script:
    - >
      CREDENTIALS=$(aws sts assume-role-with-web-identity
      --role-arn arn:aws:iam::123456789012:role/gitlab-deploy
      --role-session-name gitlab-ci
      --web-identity-token "$OIDC_TOKEN")
    - export AWS_ACCESS_KEY_ID=$(echo $CREDENTIALS | jq -r .Credentials.AccessKeyId)
    - export AWS_SECRET_ACCESS_KEY=$(echo $CREDENTIALS | jq -r .Credentials.SecretAccessKey)
    - export AWS_SESSION_TOKEN=$(echo $CREDENTIALS | jq -r .Credentials.SessionToken)
    - aws s3 ls

GitLab: Configure OpenID Connect in AWS

Terraform Enterprise

Terraform Enterprise workload identity tokens use aws.workload.identity as the audience for AWS dynamic credentials. The subject encodes the organization, project, workspace, and run phase. If you expose OIDC through an oidc.pub secondary hostname, use that hostname in the IAM condition keys. See the Terraform Enterprise guide for the publishing setup.

// Trust policy condition
"Condition": {
  "StringEquals": {
    "tfe.oidc.pub:aud": "aws.workload.identity",
    "tfe.oidc.pub:sub": "organization:my-org:project:Default Project:workspace:networking:run_phase:apply"
  }
}

Terraform Enterprise: AWS dynamic credentials