Step-by-Step Guide to Setting OIDC for GitHub Actions Workflows with AWS Using Terraform
Are you still using AWS access keys and secrets to authenticate your GitHub Actions with AWS in 2025?
Please don’t. Unless you want to wake up someday with 1000 GPU machines mining Bitcoin in your account at your expense, footing a million-dollar bill.
Your GitHub Actions Secrets Are the Weakest Link in Your AWS Security Chain
Using long-term secrets can be a security nightmare that could expose your cloud account to a possible security incident nightmare. You might be just one exposed GitHub secret away from an AWS billing catastrophe.
Then what should you do?
You should use OpenID Connect (OIDC), a modern, more secure way to authenticate your GitHub Actions workflows with AWS without storing long-lived credentials.
You can configure the OIDC to work with certain GitHub org and GitHub repos, or you can go more granular and allow it with certain branches, tag formats, etc.
What the heck is OIDC?
OIDC enables token-based authentication between GitHub Actions and AWS, eliminating the need for storing long-lived access keys. By establishing a trust relationship with temporary credentials, it significantly enhances security while simplifying the authentication process.
The better way to authenticate GitHub Action with AWS is with OpenID Connect (OIDC).
Setting up OIDC for your AWS account is very simple,
- Step 1: Create an OIDC Identity Provider in AWS
- Step 2: Create an IAM Role for GitHub Actions
- Step 3: Attach Permissions your CICD workflow needs to the Role
- Step 4: Update Your GitHub Actions Workflow to use the Identity provider arn instead of access keys and secrets
You can configure it from the AWS console, with AWS CLI commands or use Terraform to configure it.
I will use AWS CLI to configure the OIDC first and later with Terraform(with more flexible options).
Real-time implementation
Scenario
I have a 3-tier application running on an EKS cluster. I want to build and deploy new versions of applications using the GitHub Action workflow. For simplicity, I will run kubectl
commands from the workflow to deploy the new version of the application.
Workflow
- Look for the change in frontend/backend code and only build the images upon the code change and push them to their respective ECR repos.
- Configure the
kubectl
and authenticate to the EKS cluster - Use the newly built images (for backend/frontend) and deploy them to the frontend/backend service.
Setting Up OIDC Between GitHub Actions and AWS: A Step-by-Step Guide
Create the file structure below

Run the below command to create the directory structure
touch configure-oidc-github.sh eks-policy.json trust-policy.json
Copy the code to their respective files.
trust-policy.json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::$AWS_ACCOUNT_ID:oidc-provider/$OIDC_PROVIDER"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringLike": {
"$OIDC_PROVIDER:sub": "repo:$GITHUB_ORG/$GITHUB_REPO:*"
}
}
}
]
}
eks-policy.json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"eks:DescribeCluster",
"eks:ListClusters"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"ecr:GetAuthorizationToken",
"ecr:BatchCheckLayerAvailability",
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage",
"ecr:InitiateLayerUpload",
"ecr:UploadLayerPart",
"ecr:CompleteLayerUpload",
"ecr:PutImage"
],
"Resource": "*"
}
]
}
configure-oidc-github.sh
#!/bin/bash
set -e
export OIDC_PROVIDER="token.actions.githubusercontent.com"
export AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query "Account" --output text)
export GITHUB_ORG="akhileshmishrabiz" # GitHub Org/Owner
export GITHUB_REPO="DevOpsDojo" # Repo you want to allow to use OIDC with AWS
# Create the OIDC provider
aws iam create-open-id-connect-provider \
--url https://$OIDC_PROVIDER \
--client-id-list sts.amazonaws.com \
--thumbprint-list "6938fd4d98bab03faadb97b34396831e3780aea1"
aws iam create-role \
--role-name GitHubActionsEKSDeployRole \
--assume-role-policy-document file://trust-policy.json
aws iam create-policy \
--policy-name GitHubActionsEKSPolicy \
--policy-document file://eks-policy.json
# Attach the policy to the role
aws iam attach-role-policy \
--role-name GitHubActionsEKSDeployRole \
--policy-arn arn:aws:iam::$AWS_ACCOUNT_ID:policy/GitHubActionsEKSPolicy
This script will configure the OIDC to allow my GitHub workflows in the repo https://github.com/akhileshmishrabiz/DevOpsDojo
to use OIDC to authenticate with AWS. Let me explain the steps.
- Setting the environment variable
export OIDC_PROVIDER=”token.actions.githubusercontent.com”
export AWS_ACCOUNT_ID=$(aws sts get-caller-identity — query “Account” — output text)
export GITHUB_ORG=”akhileshmishrabiz”
export GITHUB_REPO=”DevOpsDojo”
- Creating the OIDC IAM provider
aws iam create-open-id-connect-provider \
--url https://$OIDC_PROVIDER \
--client-id-list sts.amazonaws.com \
--thumbprint-list "6938fd4d98bab03faadb97b34396831e3780aea1"
- Creating an IAM Role for GitHub Actions
aws iam create-role \
--role-name GitHubActionsEKSDeployRole \
--assume-role-policy-document file://trust-policy.json
- Creating an IAM policy for the GitHub Action role
aws iam create-policy \
--policy-name GitHubActionsEKSPolicy \
--policy-document file://eks-policy.json
- Attaching IAM policy with the role
aws iam attach-role-policy \
--role-name GitHubActionsEKSDeployRole \
--policy-arn arn:aws:iam::$AWS_ACCOUNT_ID:policy/GitHubActionsEKSPolicy
Configuring the OIDC provider for GitHub Action with AWS CLI.
- Install the AWS CLI if you haven’t already done
curl "https://awscli.amazonaws.com/AWSCLIV2.pkg" -o "AWSCLIV2.pkg"
sudo installer -pkg AWSCLIV2.pkg -target /
- Configure the AWS credentials — with Access key and security key
aws configure
# This will as you access and secret key
- Run the script to
chmod u+ x configure-oidc-github.sh
./configure-oidc-github.sh
Note: You can find the entire code for OIDC with AWS CLI here.
This will allow us to use the role arn:aws:iam::366140438193:role/GitHubActionsEKSDeployRole
to authenticate with the GitHub repo https://github.com/akhileshmishrabiz/DevOpsDojo
Terraform implementation
In a production environment, we mostly use Terraform to deploy the OIDC provider for GitHub Action.
Let me show how you can set up the OIDC provider with the help of Terraform and how to allow more than one repository.
- Create a
providers.tf
file and paste the below code into it. This will configure the Terraform version and AWS provider. - Create the files,
variables.tf,
output.tf,
main.tf, iam.tf
and paste the below code into them. - Create a
terraform.tfvars
file to create a map of repositories and branches. - Deploy the Terraform code, it will return the Role ARN that we can use with GitHub Action to authenticate with AWS.
- This will create an IAM role to use with GitHub Action, IAM policies with permission you want your GitHub Action workflow to have, and attach them to the role. IAM roles’s trust policy will allow the particular repositories and branches to use this role to authenticate with AWS.
providers.tf
terraform {
required_version = "1.8.1"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "ap-south-1"
}
variables.tf
# Variables
variable "aws_region" {
description = "AWS region"
type = string
default = "ap-south-1"
}
variable "github_repositories" {
description = "List of GitHub repositories to grant access to"
type = list(object({
org = string
repo = string
branch = optional(string, "*")
}))
default = [
{
org = "akhileshmishrabiz"
repo = "DevOpsDojo"
branch = "*"
}
]
}
main.tf
# OIDC Provider
resource "aws_iam_openid_connect_provider" "github_actions" {
url = "https://token.actions.githubusercontent.com"
client_id_list = [
"sts.amazonaws.com"
]
thumbprint_list = [
"6938fd4d98bab03faadb97b34396831e3780aea1"
]
tags = {
Name = "GitHub-Actions-OIDC-Provider"
}
}
# IAM Role
resource "aws_iam_role" "github_actions_eks_deploy_role" {
name = "GitHubActionsEKSDeployRole"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Principal = {
Federated = aws_iam_openid_connect_provider.github_actions.arn
}
Action = "sts:AssumeRoleWithWebIdentity"
Condition = {
StringLike = {
"token.actions.githubusercontent.com:sub" = [
for repo in var.github_repositories :
"repo:${repo.org}/${repo.repo}:${repo.branch}"
]
}
}
}
]
})
tags = {
Name = "GitHub-Actions-EKS-Deploy-Role"
}
}
iam.tf
# IAM Policy
resource "aws_iam_policy" "github_actions_eks_policy" {
name = "GitHubActionsEKSPolicy"
description = "Policy for GitHub Actions to access EKS and ECR"
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"eks:DescribeCluster",
"eks:ListClusters"
]
Resource = "*"
},
{
Effect = "Allow"
Action = [
"ecr:GetAuthorizationToken",
"ecr:BatchCheckLayerAvailability",
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage",
"ecr:InitiateLayerUpload",
"ecr:UploadLayerPart",
"ecr:CompleteLayerUpload",
"ecr:PutImage"
]
Resource = "*"
}
]
})
tags = {
Name = "GitHub-Actions-EKS-Policy"
}
}
# Policy Attachment
resource "aws_iam_role_policy_attachment" "github_actions_eks_policy_attachment" {
role = aws_iam_role.github_actions_eks_deploy_role.name
policy_arn = aws_iam_policy.github_actions_eks_policy.arn
}
terraform.tfvars
github_repositories = [
{
org = "akhileshmishrabiz"
repo = "DevOpsDojo"
branch = "*" # All branches
},
{
org = "akhileshmishrabiz"
repo = "Devops-zero-to-hero"
branch = "main" # Only main branch
}
]
You can find the Terraform code to set up OIDC for Github Action here.
Apply the Terraform
This example uses the Terraform version 1.8.1
, make sure you have the same Terraform version installed. If you have some other version of Terraform installed, then update the providers.tf
If you want to use multiple versions of Terrafor,m then use tfenv
CLI.
terraform init
terraform apply

This will allow us to use the role arn:aws:iam::366140438193:role/GitHubActionsEKSDeployRole
to authenticate with the GitHub repo https://github.com/akhileshmishrabiz/DevOpsDojo
on all branches. and https://github.com/akhileshmishrabiz/Devops-zero-to-hero
on the main branch.
Let’s use this OIDC provider in our GitHub Action workflow
Using the OIDC provider to authenticate GitHub Action workflow with AWS to push the docker images to ECR repositories.
For this example, I will use my public GitHub Repo https://github.com/akhileshmishrabiz/DevOpsDojo
This repo has a 3-tier app:
– Flask backend
– React frontend
– RDS Postgres database
I will use GitHub Action to build the backend and frontend images and push them to AWS ECR repositories. GitHub Action will use OIDC to authenticate with AWS.
Let me create 2 ECR repositories
# Create ECR repositories for frontend and backend
aws ecr create-repository --repository-name devopsdozo/frontend
aws ecr create-repository --repository-name devopsdozo/backend

I want to use the workflow to build the backend and frontend docker images and push them to ECR repositories.
If you look at the below GitHub Action workflow, you can see that I have used GitHubActionsEKSDeployRole
instead of access and secret keys.role-to-assume:arn:aws:iam::366140438193:role/GitHubActionsEKSDeployRole
instead of AWS access and security keys.
When GitHub sends an auth request to AWS, it verifies the trust policy attached to the role to check if it is allowed to authenticate the workflow for the specific GitHub repo, and branch. If it finds the conditions to be true, it will generate a short-term token that GH workflow uses to authenticate with AWS.
name: Build and Push Docker Images
on:
push:
branches: [ main ]
workflow_dispatch: # Enable manual triggering
env:
AWS_REGION: ap-south-1
ECR_REPOSITORY_FRONTEND: devopsdozo/frontend
ECR_REPOSITORY_BACKEND: devopsdozo/backend
IMAGE_TAG: latest
jobs:
build-and-push:
name: Build and Push Images
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v3
with:
aws-region: ${{ env.AWS_REGION }}
role-to-assume: arn:aws:iam::366140438193:role/GitHubActionsEKSDeployRole
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v1
- name: Build, tag, and push frontend image to Amazon ECR
working-directory: ./frontend
env:
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
run: |
docker build -t $ECR_REGISTRY/$ECR_REPOSITORY_FRONTEND:$IMAGE_TAG \
--platform=linux/amd64 .
docker push $ECR_REGISTRY/$ECR_REPOSITORY_FRONTEND:$IMAGE_TAG
echo "Frontend image pushed to ECR: $ECR_REGISTRY/$ECR_REPOSITORY_FRONTEND:$IMAGE_TAG"
- name: Build, tag, and push backend image to Amazon ECR
working-directory: ./backend
env:
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
run: |
docker build -t $ECR_REGISTRY/$ECR_REPOSITORY_BACKEND:$IMAGE_TAG \
--platform=linux/amd64 .
docker push $ECR_REGISTRY/$ECR_REPOSITORY_BACKEND:$IMAGE_TAG
echo "Backend image pushed to ECR: $ECR_REGISTRY/$ECR_REPOSITORY_BACKEND:$IMAGE_TAG"
- name: Summary
run: |
echo "### Docker Images Built and Pushed" >> $GITHUB_STEP_SUMMARY
echo "✅ Frontend: ${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY_FRONTEND }}:${{ env.IMAGE_TAG }}" >> $GITHUB_STEP_SUMMARY
echo "✅ Backend: ${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY_BACKEND }}:${{ env.IMAGE_TAG }}" >> $GITHUB_STEP_SUMMARY
Note: You can find a better version of this workflow here.

You can see from the screenshot above that GH workflows authenticated with AWS using the OIDC, built the docker images, and pushed to ECR.