GitHub Actions to AWS OIDC Integration Setup

GitHub Actions to AWS OIDC Integration Setup
Securely deploy to AWS from GitHub Actions using OpenID Connect (OIDC), eliminating the need for long-lived AWS credentials.
✅ Step 1: Create IAM Role for GitHub (via AWS CLI)
Run the following AWS CLI commands to manually bootstrap the IAM role and OIDC provider:
aws iam create-open-id-connect-provider \
--url https://token.actions.githubusercontent.com \
--client-id-list sts.amazonaws.com \
--thumbprint-list 6938fd4d98bab03faadb97b34396831e3780aea1
aws iam create-role \
--role-name github-oidc-role \
--assume-role-policy-document file://trust-policy.json
aws iam attach-role-policy \
--role-name github-oidc-role \
--policy-arn arn:aws:iam::aws:policy/AdministratorAccess
Note: Replace
AdministratorAccess
with a least-privilege policy if possible.
✅ Step 2: Folder Structure (Bootstrap Setup)
Minimal layout for bootstrapping (no remote backend):
my-terraform-project/
├── .github/
│ └── workflows/
│ └── deploy.yml
├── main.tf
├── .gitignore
└── README.md
Example
.gitignore
:.terraform/
Note: This is a bootstrap setup and does not use a remote backend. For production, it's recommended to configure a remote backend such as an S3 bucket.
✅ Step 3: Minimal Terraform Configuration (main.tf)
This main.tf
contains only a minimal resource for testing. Terraform is not responsible for creating the IAM role in this bootstrap scenario.
provider "aws" {
region = var.aws_region
}
variable "aws_region" {
description = "AWS region"
default = "ap-southeast-2"
}
variable "aws_account_id" {
description = "AWS Account ID"
}
variable "github_owner" {
description = "GitHub organization or username"
}
variable "repo_name" {
description = "GitHub repository name"
}
# Minimal test resource
data "aws_caller_identity" "current" {}
resource "aws_s3_bucket" "test_bucket" {
bucket = "test-bucket-${data.aws_caller_identity.current.account_id}"
acl = "private"
tags = {
Name = "Test Bucket"
Env = "Bootstrap"
}
}
✅ Step 4: Configure GitHub Secrets and Variables
Go to Repo → Settings → Secrets and variables → Actions, and set:
- Secrets:
AWS_ACCOUNT_ID
: Your 12-digit AWS account ID (e.g.123456789012
)
Variables:
AWS_REGION
: AWS region to deploy resources (e.g.ap-southeast-2
)TERRAFORM_VERSION
: Terraform version to use (e.g.1.7.5
)OIDC_ROLE_NAME
: IAM role name that GitHub Actions will assume (must match the name inmain.tf
, e.g.github-oidc-role
)
✅ Step 5: GitHub Actions Workflows
🔹 plan.yml
– for Terraform Plan (on PR)
name: Terraform Plan
permissions:
id-token: write
contents: read
concurrency:
group: terraform-plan-${{ github.head_ref || github.ref }}
cancel-in-progress: true
on:
pull_request:
branches: [main]
env:
AWS_ACCOUNT_ID: ${{ secrets.AWS_ACCOUNT_ID }}
AWS_REGION: ${{ vars.AWS_REGION }}
TERRAFORM_VERSION: ${{ vars.TERRAFORM_VERSION }}
OIDC_ROLE_NAME: ${{ vars.OIDC_ROLE_NAME }}
jobs:
terraform:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Configure AWS credentials via OIDC
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ env.AWS_ACCOUNT_ID }}:role/${{ env.OIDC_ROLE_NAME }}
aws-region: ${{ env.AWS_REGION }}
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: ${{ env.TERRAFORM_VERSION }}
- name: Terraform Init
run: terraform init
- name: Terraform Format
run: terraform fmt -check
continue-on-error: true
- name: Terraform Validate
run: terraform validate
- name: Terraform Plan
run: terraform plan
🔹 deploy.yml
– for Terraform Apply
name: Terraform Apply
permissions:
id-token: write
contents: write
concurrency:
group: terraform-apply-${{ github.head_ref || github.ref }}
cancel-in-progress: true
on:
push:
branches: [main]
env:
AWS_ACCOUNT_ID: ${{ secrets.AWS_ACCOUNT_ID }}
AWS_REGION: ${{ vars.AWS_REGION }}
TERRAFORM_VERSION: ${{ vars.TERRAFORM_VERSION }}
OIDC_ROLE_NAME: ${{ vars.OIDC_ROLE_NAME }}
jobs:
terraform:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Configure AWS credentials via OIDC
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ env.AWS_ACCOUNT_ID }}:role/${{ env.OIDC_ROLE_NAME }}
aws-region: ${{ env.AWS_REGION }}
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: ${{ env.TERRAFORM_VERSION }}
- name: Terraform Init
run: terraform init
- name: Terraform Format
run: terraform fmt -check
continue-on-error: true
- name: Terraform Validate
run: terraform validate
- name: Terraform Plan
run: terraform plan
- name: Terraform Apply
id: apply
run: terraform apply -auto-approve
continue-on-error: true
- name: Commit and force push if changed
if: always()
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
if ! git diff --quiet || ! git diff --staged --quiet; then
git add .
git commit -m "Update terraform state and lock file"
git push --force
fi
- name: Fail if Terraform Apply errored
if: steps.apply.outcome == 'failure'
run: exit 1
✅ Summary
Component | Status | Notes |
OIDC Provider | ✅ | One-time setup per AWS account |
IAM Role | ✅ | Defined inline in main.tf |
Policy Permissions | ✅ | Start with AdministratorAccess , scope down later |
GitHub Workflow | ✅ | Uses configure-aws-credentials for OIDC login |
No Secrets Required | ✅ | Secure, short-lived tokens – no static credentials |
You’re now ready to securely run terraform apply
from GitHub Actions using short-lived OIDC credentials with a minimal bootstrap setup.
Subscribe to my newsletter
Read articles from John Ajera directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
