Article
Complete Guide: Secure GitHub Actions & AWS Integration with OIDC

Complete Guide: Secure GitHub Actions & AWS Integration with OIDC
What We're Building
Instead of storing AWS secrets in GitHub (which is risky), we'll set up a secure trust relationship where GitHub Actions can directly assume an AWS role and get temporary credentials automatically.
The Magic: No secrets stored anywhere, yet GitHub Actions gets full AWS administrator access!
Understanding the Key Concepts First
What is OIDC?
OpenID Connect (OIDC) is like a digital passport system for applications.
Think of it this way:
- You have a GitHub Actions workflow (the traveler)
- AWS is like a country you want to visit
- OIDC is the passport verification system
- Instead of carrying a physical passport (secrets), you get a temporary visa (token) that proves who you are
What is an Identity Provider?
An Identity Provider is like a trusted government that issues passports.
In our case:
- GitHub is the Identity Provider (issues tokens)
- AWS trusts GitHub to verify identities
- When GitHub says "this workflow is legitimate," AWS believes it
What is IAM Role?
An IAM Role is like a job position with specific permissions.
Instead of giving a person direct access, you create a role (like "Administrator") and let people temporarily "wear that hat" when they need those permissions.
Step-by-Step Implementation
Step 1: Create OIDC Identity Provider in AWS
This step tells AWS: "I trust GitHub Actions to send me identity tokens."
Navigate to AWS Console
- Go to AWS Console → IAM
Add Identity Provider
- Click "Identity providers" in the left sidebar
- Click "Add provider"
Configure Provider
Provider Type: OpenID Connect Provider URL: https://token.actions.githubusercontent.com Audience: sts.amazonaws.comWhy these values?
Provider URL: This is GitHub's official OIDC endpointAudience: This tells AWS that the tokens are meant for AWS STS (Security Token Service)
Click "Add provider"
Step 2: Create IAM Role for GitHub Actions
This creates the "job position" that GitHub Actions will assume.
Start Role Creation
- Go to IAM → Roles → Create Role
Choose Trust Type
- Select "Web identity" (because GitHub Actions is a web service)
Configure Web Identity
- Identity provider: Select the GitHub OIDC provider you just created
- Audience:
sts.amazonaws.com
What's happening here?
- We're telling AWS: "Only tokens from GitHub's OIDC provider can use this role"
- The audience ensures the token was meant for AWS
Step 3: Attach Administrator Permissions
This gives the role full AWS access (be careful with this in production!).
Attach Policy
- Search for
AdministratorAccess - Select it and click Next
- Search for
Name Your Role
- Role name:
GitHubActionsAdminRole(you can give any name) - Add description: "Role for GitHub Actions with admin access"
- Role name:
Create Role
Step 4: Fine-tune the Trust Policy (Important!)
The default trust policy might be too broad. Let's make it more secure.
Edit Trust Policy
- Go to your new role → Trust relationships → Edit trust policy
Replace with this secure version:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Federated": "arn:aws:iam::YOUR_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:YOUR_GITHUB_USERNAME/YOUR_REPO_NAME:*" } } } ] }Replace placeholders:
YOUR_ACCOUNT_ID: Your AWS account ID (find it in top-right corner)YOUR_GITHUB_USERNAME: Your GitHub usernameYOUR_REPO_NAME: Your repository name
Why this trust policy?
Federated: Points to our OIDC providerStringEquals: Ensures token is for AWSStringLike: Only allows your specific repository to use this role
GitHub Actions Workflow Configuration
Now let's create the workflow that uses this setup.
Create the Workflow File
Select any of your repo.
Create
.github/workflows/deploy-ec2.yml:
name: Deploy EC2 via GitHub Actions with OIDC
# When should this workflow run?
on:
workflow_dispatch: # Allows manual trigger from GitHub UI
# Define the job
jobs:
deploy:
runs-on: ubuntu-latest # Use Ubuntu virtual machine
# CRITICAL: These permissions are required for OIDC
permissions:
id-token: write # Allows requesting OIDC token
contents: read # Allows reading repository contents
steps:
# Step 1: Get the code
- name: Checkout code
uses: actions/checkout@v4
# Step 2: Get AWS credentials using OIDC (THE MAGIC HAPPENS HERE)
- name: Configure AWS credentials using OIDC
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::<Account-id>:role/<Role-Name>
aws-region: us-east-1
# Step 3: Use AWS CLI with the temporary credentials
- name: Launch EC2 instance
run: |
echo "Launching EC2 instance..."
aws ec2 run-instances \
--image-id ami-0c02fb55956c7d316 \
--count 1 \
--instance-type t2.micro \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=GitHubOIDCTest}]' \
--key-name <key-pair-name> \
--security-groups default
Understanding Each Line
Workflow Trigger
on:
workflow_dispatch:
workflow_dispatch: Allows you to manually run this workflow from GitHub's web interface- You could also use
push,pull_request, or schedule triggers
Job Configuration
jobs:
deploy:
runs-on: ubuntu-latest
jobs: A workflow can have multiple jobsdeploy: Name of our job (you can choose any name)runs-on: Specifies the virtual machine type
Critical Permissions
permissions:
id-token: write
contents: read
This is crucial for OIDC to work!
id-token: write: Allows GitHub to generate and send OIDC tokenscontents: read: Allows reading files from your repository
Steps Breakdown
Step 1: Checkout Code
- name: Checkout code
uses: actions/checkout@v4
- Downloads your repository code to the virtual machine
@v4: Version of the checkout action
Step 2: OIDC Authentication (The Magic)
- name: Configure AWS credentials using OIDC
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::<Account-id>:role/<Role-Name>
aws-region: us-east-1
Step 3: Use AWS CLI
- name: Launch EC2 instance
run: |
echo "Launching EC2 instance..."
aws ec2 run-instances \
--image-id ami-0c02fb55956c7d316 \
--count 1 \
--instance-type t2.micro \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=GitHubOIDCTest}]' \
--key-name <key-pair-name> \
--security-groups default
Breaking down the EC2 command:
aws ec2 run-instances: Launch EC2 instances--image-id: The AMI (Amazon Machine Image) to use--count 1: Launch 1 instance--instance-type t2.micro: Size of the instance--tag-specifications: Add tags to identify the instance--key-name <key-pair-name>: SSH key pair for connecting to instance--security-groups default: Security group (firewall rules)
Replace these placeholders
Replace the following placeholders in your GitHub Actions workflow file:
| Placeholder | Replace with |
|---|---|
<Account-id> |
Your AWS Account ID (e.g. 123456789012) |
<Role-Name> |
Name of the IAM Role you created (e.g. GitHubActionsAdminRole) |
key-pair-name |
Name of an EC2 Key Pair already created in AWS |
ami-0c02fb55956c7d316 |
Amazon Linux 2 AMI for us-east-1 (can be used as-is if your region matches) |
How to Find These
🔹 AWS Account ID
- Sign in to AWS Console
- Click your account name (top-right) → Account
- Copy the 12-digit AWS Account ID
🔹 IAM Role Name
- Go to AWS Console → IAM → Roles
- Find the role you created for GitHub OIDC
- Copy the role name
🔹 Key Pair Name
- Go to AWS Console → EC2 → Key Pairs
- Use an existing key pair name or create a new one
- Remember to download the
.pemfile if you create a new one
🔹 AMI ID
- The default
ami-0c02fb55956c7d316is for Amazon Linux 2 inus-east-1 - If using another region, you can find a suitable AMI in the EC2 Launch Wizard or AWS AMI catalog
What happens behind the scenes:
- GitHub Actions requests an OIDC token from GitHub
- The token contains information about the workflow, repository, and run
- This action sends the token to AWS
- AWS verifies the token against the trust policy
- AWS returns temporary credentials (valid for ~1 hour)
- These credentials are automatically available to subsequent steps
How It All Works Together
The Flow
- You trigger the workflow (manually or via push/PR)
- GitHub Actions starts a virtual machine
- GitHub generates an OIDC token containing workflow metadata
- AWS receives the token and verifies it against the trust policy
- AWS provides temporary credentials to the workflow
- Your workflow uses these credentials to perform AWS operations
- Credentials automatically expire after ~1 hour
Security Benefits
- ✅ No secrets stored anywhere
- ✅ Credentials are temporary (auto-expire)
- ✅ Specific to your repository (trust policy restriction)
- ✅ Full audit trail (CloudTrail logs all actions)
Customization Options
Modify for Your Repository
Update the role ARN in the workflow file:
role-to-assume: arn:aws:iam::YOUR_ACCOUNT_ID:role/GitHubActionsAdminRoleUpdate the trust policy with your repository details:
"token.actions.githubusercontent.com:sub": "repo:YOUR_USERNAME/YOUR_REPO:*"
Different Trigger Options
# Trigger on push to main branch
on:
push:
branches: [ main ]
# Trigger on pull request
on:
pull_request:
branches: [ main ]
# Trigger on schedule (daily at 9 AM)
on:
schedule:
- cron: '0 9 * * *'
Different AWS Operations
Replace the EC2 launch command with any AWS CLI command:
# Deploy to S3
- name: Deploy to S3
run: |
aws s3 cp ./dist s3://my-bucket/ --recursive
# Update Lambda function
- name: Update Lambda
run: |
aws lambda update-function-code \
--function-name my-function \
--zip-file fileb://function.zip
Troubleshooting Common Issues
Error: "Unable to assume role"
- Check: Role ARN is correct in workflow file
- Check: Trust policy has correct repository name
- Check: OIDC provider is properly configured
Error: "Token validation failed"
- Check:
permissions.id-token: writeis set in workflow - Check: Audience is
sts.amazonaws.comin both places
Error: "Access denied"
- Check: Role has necessary permissions (AdministratorAccess or whatever you are working/need for)
- Check: Trust policy conditions are met
Conclusion
You've successfully set up a secure, secret-free integration between GitHub Actions and AWS! This approach is:
- More secure than storing secrets
- Easier to manage (no credential rotation)
- More auditable (full CloudTrail logs)
- Scalable (works across multiple repositories)
The key insight is that instead of storing long-lived secrets, we're using short-lived, dynamically generated tokens that prove the identity of our GitHub Actions workflow to AWS.
📚 Additional Resources
Official Documentation
Security Best Practices
- AWS Security Best Practices for GitHub Actions
- GitHub Actions Security Hardening
- AWS IAM Best Practices
Advanced Topics
- Multi-Account AWS Deployment Strategies
- AWS CDK with GitHub Actions OIDC
- Terraform Cloud Integration
🌟 Explore More AWS Content
📖 Related Reading
Loved this secure integration guide? Take your AWS skills to the next level with cost monitoring and automation:
💰 How to Build an Automated AWS Resource Monitor
Build a smart system that tracks your AWS resources and sends hourly notifications to prevent surprise bills
✨ What you'll learn:
- 🔔 Automated email alerts for running resources
- 📊 Cost optimization strategies
- ⚡ Lambda-powered monitoring system


