OIDC Provider

Complete reference for the GitHub Actions OIDC provider CloudFormation template.


Overview

The OIDC provider template creates the infrastructure needed for GitHub Actions to authenticate with AWS using OpenID Connect (OIDC). This eliminates the need for long-lived AWS access keys, providing a more secure authentication method for CI/CD pipelines.

The template creates:

  • OIDC Provider — Establishes trust between AWS IAM and GitHub Actions
  • IAM Role — Service role that GitHub Actions assumes during workflow execution
  • Trust Policy — Controls which repositories and branches can assume the role

Template location

The template is located at templates/oidc-provider.yml in the starter kit repository.

Parameters

GithubActionsThumbprint

Type: CommaDelimitedList
Default: 6938fd4d98bab03faadb97b34396831e3780aea1

Thumbprint for GitHub Actions OIDC tokens. This validates the TLS certificate of GitHub's OIDC provider.

Default value: 6938fd4d98bab03faadb97b34396831e3780aea1 (current GitHub Actions thumbprint)

When to change: Only if GitHub updates their OIDC provider certificate (rare).

AudienceList

Type: CommaDelimitedList
Default: sts.amazonaws.com

Allowed audiences for OIDC tokens. The audience claim in the token must match this value.

Default value: sts.amazonaws.com (standard for AWS STS)

When to change: Only if you have specific token validation requirements.

SubjectClaimFilters

Type: CommaDelimitedList
Required: Yes

Most important parameter. Controls which repositories and branches can assume the IAM role.

Format patterns:

# Allow entire repository (any branch, any environment)
SubjectClaimFilters: repo:owner/repository:*

# Allow only main branch
SubjectClaimFilters: repo:owner/repository:ref:refs/heads/main

# Allow specific branch
SubjectClaimFilters: repo:owner/repository:ref:refs/heads/develop

# Allow any release branch
SubjectClaimFilters: repo:owner/repository:ref:refs/heads/release/*

# Allow pull requests
SubjectClaimFilters: repo:owner/repository:pull_request

# Allow GitHub Environment-specific deployments
SubjectClaimFilters: repo:owner/repository:environment:production

# Multiple filters (comma-separated)
SubjectClaimFilters:
  - repo:owner/repository:ref:refs/heads/main
  - repo:owner/repository:ref:refs/heads/develop

Security best practice: Use the most restrictive filter that meets your needs. For production environments, limit to specific branches.

Example for test environment:

# parameters/test/oidc-provider.yml
SubjectClaimFilters: repo:towardsthecloud/my-repo:ref:refs/heads/main

Path

Type: String
Default: /

IAM path for the service role. Useful for organizing roles in large organizations.

Examples:

  • / (default, root path)
  • /github-actions/
  • /ci-cd/cloudformation/

ManagedPolicyARNs

Type: CommaDelimitedList
Default: arn:aws:iam::aws:policy/AdministratorAccess

AWS managed policies to attach to the service role. Controls what the GitHub Actions workflow can do in your AWS account.

Default: AdministratorAccess (full access - suitable for infrastructure deployment)

Alternative options:

# PowerUserAccess (everything except IAM)
ManagedPolicyARNs: arn:aws:iam::aws:policy/PowerUserAccess

# CloudFormation-only access
ManagedPolicyARNs: arn:aws:iam::aws:policy/AWSCloudFormationFullAccess

# Multiple policies
ManagedPolicyARNs:
  - arn:aws:iam::aws:policy/AWSCloudFormationFullAccess
  - arn:aws:iam::aws:policy/AmazonS3FullAccess
  - arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess

# Custom policy (create separately and reference)
ManagedPolicyARNs: arn:aws:iam::123456789012:policy/GitHubActionsCustomPolicy

Security consideration: For production environments, consider using least-privilege custom policies instead of AdministratorAccess.

Resources

GitHubIdentityProvider

Creates an IAM OIDC identity provider that establishes trust with GitHub Actions.

Type: AWS::IAM::OIDCProvider
Properties:
  Url: https://token.actions.githubusercontent.com
  ThumbprintList: !Ref GithubActionsThumbprint
  ClientIdList: !Ref AudienceList

Key properties:

  • Url — GitHub Actions OIDC endpoint
  • ThumbprintList — Validates GitHub's TLS certificate
  • ClientIdList — Allowed audiences for tokens

GitHubActionsServiceRole

Creates the IAM role that GitHub Actions workflows assume.

Type: AWS::IAM::Role
Properties:
  RoleName: GitHubActionsServiceRole
  AssumeRolePolicyDocument:
    Statement:
      - Effect: Allow
        Principal:
          Federated: !GetAtt GitHubIdentityProvider.Arn
        Action: sts:AssumeRoleWithWebIdentity
        Condition:
          StringEquals:
            "token.actions.githubusercontent.com:aud": !Ref AudienceList
          StringLike:
            "token.actions.githubusercontent.com:sub": !Ref SubjectClaimFilters

Trust policy conditions:

  • StringEquals on aud — Token audience must match AudienceList
  • StringLike on sub — Token subject must match SubjectClaimFilters

These conditions ensure only authorized repositories/branches can assume the role.

Outputs

ServiceRoleARN

Value: !GetAtt GitHubActionsServiceRole.Arn

Returns the ARN of the created service role. Use this value in your GitHub Actions workflow:

- name: Configure AWS credentials
  uses: aws-actions/configure-aws-credentials@v4
  with:
    role-to-assume: arn:aws:iam::123456789012:role/GitHubActionsServiceRole
    aws-region: us-east-1

Parameter file examples

Single repository, main branch only

# parameters/production/oidc-provider.yml
SubjectClaimFilters: repo:towardsthecloud/infrastructure:ref:refs/heads/main
ManagedPolicyARNs: arn:aws:iam::aws:policy/AdministratorAccess

Multiple branches

# parameters/test/oidc-provider.yml
SubjectClaimFilters:
  - repo:towardsthecloud/infrastructure:ref:refs/heads/main
  - repo:towardsthecloud/infrastructure:ref:refs/heads/develop
ManagedPolicyARNs: arn:aws:iam::aws:policy/AdministratorAccess

Multiple repositories (shared infrastructure account)

# parameters/shared/oidc-provider.yml
SubjectClaimFilters:
  - repo:towardsthecloud/app1:ref:refs/heads/main
  - repo:towardsthecloud/app2:ref:refs/heads/main
  - repo:towardsthecloud/infrastructure:ref:refs/heads/main
ManagedPolicyARNs: arn:aws:iam::aws:policy/PowerUserAccess

Custom policy with least privilege

# parameters/production/oidc-provider.yml
SubjectClaimFilters: repo:towardsthecloud/infrastructure:ref:refs/heads/main
ManagedPolicyARNs: arn:aws:iam::123456789012:policy/GitHubActionsCloudFormationPolicy
Path: /github-actions/

Deployment

Initial deployment

Deploy the OIDC provider template first, before any other infrastructure:

# Deploy to test environment
rain deploy templates/oidc-provider.yml --config parameters/test/oidc-provider.yml

# Deploy to production environment
rain deploy templates/oidc-provider.yml --config parameters/production/oidc-provider.yml

Verification

After deployment, verify the stack was created:

# Check stack status
aws cloudformation describe-stacks --stack-name oidc-provider

# Get the service role ARN
aws cloudformation describe-stacks \
  --stack-name oidc-provider \
  --query 'Stacks[0].Outputs[?OutputKey==`ServiceRoleARN`].OutputValue' \
  --output text

Testing the role

Test that GitHub Actions can assume the role:

# .github/workflows/test-oidc.yml
name: Test OIDC Authentication

on: workflow_dispatch

permissions:
  id-token: write
  contents: read

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::${{ vars.TEST_AWS_ACCOUNT_ID }}:role/GitHubActionsServiceRole
          aws-region: ${{ vars.AWS_REGION }}

      - name: Test AWS access
        run: |
          aws sts get-caller-identity
          aws cloudformation list-stacks

Security best practices

1. Use restrictive SubjectClaimFilters

# Good: Specific branch
SubjectClaimFilters: repo:owner/repo:ref:refs/heads/main

# Bad: Too permissive
SubjectClaimFilters: repo:owner/repo:*

2. Separate roles per environment

Create different OIDC stacks for each environment:

parameters/
├── test/
│   └── oidc-provider.yml          # GitHubActionsServiceRole-Test
├── staging/
│   └── oidc-provider.yml          # GitHubActionsServiceRole-Staging
└── production/
    └── oidc-provider.yml          # GitHubActionsServiceRole-Production

Modify the template to include environment in the role name:

RoleName: !Sub GitHubActionsServiceRole-${Environment}

3. Use least-privilege policies

Instead of AdministratorAccess, create custom policies:

# Custom policy with only required permissions
ManagedPolicyARNs: arn:aws:iam::123456789012:policy/GitHubActionsMinimalPolicy

Example minimal policy for CloudFormation deployment:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "cloudformation:*",
        "s3:*",
        "iam:GetRole",
        "iam:PassRole"
      ],
      "Resource": "*"
    }
  ]
}

4. Enable CloudTrail logging

Monitor all actions taken by the GitHub Actions role:

# View recent API calls made by the role
aws cloudtrail lookup-events \
  --lookup-attributes AttributeKey=Username,AttributeValue=GitHubActionsServiceRole \
  --max-results 50

5. Rotate credentials regularly

Although OIDC doesn't use long-lived credentials, periodically review:

  • SubjectClaimFilters (ensure only authorized repos/branches)
  • Attached policies (remove unnecessary permissions)
  • Role usage (check CloudTrail for suspicious activity)

Troubleshooting

Error: "Not authorized to perform sts:AssumeRoleWithWebIdentity"

Cause: SubjectClaimFilters doesn't match the GitHub Actions context.

Solution: Check your filter matches the repository and branch:

# In GitHub Actions, print the token subject claim
- name: Debug OIDC token
  run: |
    echo "Repository: ${{ github.repository }}"
    echo "Ref: ${{ github.ref }}"

Update your SubjectClaimFilters to match.

Error: "OpenIDConnect provider not found"

Cause: OIDC provider stack not deployed or deployed to wrong account.

Solution: Verify the stack exists:

aws cloudformation describe-stacks --stack-name oidc-provider

If not found, deploy the template.

Error: "Role does not have sufficient permissions"

Cause: Attached policies don't include required permissions.

Solution: Update ManagedPolicyARNs or add custom inline policies:

ManagedPolicyARNs:
  - arn:aws:iam::aws:policy/AdministratorAccess

OIDC thumbprint is outdated

Symptom: Authentication suddenly stops working.

Cause: GitHub updated their OIDC provider certificate.

Solution: Update the thumbprint and redeploy:

# Get current GitHub OIDC thumbprint
openssl s_client -servername token.actions.githubusercontent.com \
  -connect token.actions.githubusercontent.com:443 < /dev/null 2>/dev/null | \
  openssl x509 -fingerprint -noout | \
  cut -d'=' -f2 | \
  tr -d ':' | \
  tr '[:upper:]' '[:lower:]'