Terraform Automation with GitHub Actions & AWS OIDC
Using AWS IAM OpenID Connect (OIDC) allows GitHub Actions workflows to assume IAM roles securely without storing long-lived AWS Access Keys or Secrets in GitHub repository settings.
Architecture
sequenceDiagram
participant GH as GitHub Actions Workflow
participant OIDC as GitHub OIDC Provider (token.actions.githubusercontent.com)
participant STS as AWS STS (AssumeRoleWithWebIdentity)
participant AWS as AWS IAM Role (Terraform Deployer)
GH->>OIDC: Request JWT Token for Workflow Run
OIDC-->>GH: Signed JSON Web Token (OIDC Token)
GH->>STS: AssumeRoleWithWebIdentity (passes JWT)
STS->>AWS: Validate Subject (repo:org/repo:ref) & Audience (sts.amazonaws.com)
STS-->>GH: Temporary short-lived AWS Credentials (1 hour)
Step 1. Configure GitHub OIDC Provider in AWS IAM
- In the AWS Console → IAM → Identity Providers → Add Provider.
- Select OpenID Connect.
- Provider URL:
https://token.actions.githubusercontent.com - Audience:
sts.amazonaws.com - Click Get Thumbprint and Add Provider.
Step 2. Create IAM Role with OIDC Trust Policy
Create an IAM role with a trust policy restricting access to your specific GitHub repository and branch:
github-oidc-trust-policy.json
{
"Version": "2012-10-17",
"Statement": [
{
"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"
},
"StringLike": {
"token.actions.githubusercontent.com:sub": "repo:<GITHUB_ORG>/<GITHUB_REPO>:*"
}
}
}
]
}
Attach policies granting permissions for Terraform state management (S3 bucket and DynamoDB lock table) and targeted infrastructure provisioning.
Step 3. GitHub Actions Workflow
Create .github/workflows/terraform.yml:
name: "Terraform Automation"
on:
push:
branches:
- main
pull_request:
branches:
- main
permissions:
id-token: write # Required for requesting the OIDC JWT
contents: read
pull-requests: write
jobs:
terraform:
name: "Terraform Plan & Apply"
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Configure AWS Credentials (OIDC)
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::<ACCOUNT_ID>:role/github-actions-terraform-role
role-session-name: githubactions-tf-${{ github.run_id }}
aws-region: eu-west-1
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
- name: Terraform Format Check
run: terraform fmt -check
- name: Terraform Init
run: terraform init
- name: Terraform Validate
run: terraform validate -no-color
- name: Terraform Plan
id: plan
run: terraform plan -no-color
if: github.event_name == 'pull_request'
- name: Terraform Apply
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
run: terraform apply -auto-approve -input=false