Overview
OpenID Connect (OIDC) allows your GitHub Actions workflows to access resources in Amazon Web Services (AWS) without storing long-lived AWS credentials as GitHub secrets. Whether you're deploying Lambda functions, updating S3 buckets, managing EC2 instances, or using any AWS service, this guide shows you how to transition from using AWS access keys to OIDC authentication.
Why OIDC Instead of Access Keys?
Access Keys (Traditional Method):
- ❌ Long-lived credentials that never expire
- ❌ Must be rotated manually
- ❌ If leaked, remain valid until manually revoked
- ❌ Stored as GitHub secrets
OIDC (Modern Method):
- ✅ Short-lived tokens that expire automatically
- ✅ No credentials to rotate
- ✅ Tokens are automatically invalidated after use
- ✅ Fine-grained access control with trust policies
Prerequisites
Before proceeding, ensure you have:
- An AWS account with IAM permissions
- A GitHub repository
- Basic understanding of IAM roles and policies
Step 1: Add GitHub OIDC Provider to AWS
- Navigate to the IAM Console in AWS
- Go to Identity providers → Add provider
- Select OpenID Connect
- Configure the provider:
-
Provider URL:
https://token.actions.githubusercontent.com -
Audience:
sts.amazonaws.com
-
Provider URL:
- Click Add provider
Step 2: Create IAM Role with Trust Policy
Navigate to IAM → Roles → Create role to begin.
Step 1: Select Trusted Entity
- Select Web identity as the trusted entity type
- Configure the identity provider using the dropdowns:
-
Identity provider: Select
token.actions.githubusercontent.comfrom the dropdown -
Audience: Select
sts.amazonaws.comfrom the dropdown -
GitHub organization: Enter your organization or personal username (e.g.,
AliZgheib) -
GitHub repository (optional): Enter
*to allow all repositories, or specify a specific repo name -
GitHub branch (optional): Enter
*to allow all branches, or specify a specific branch likemain
-
Identity provider: Select
- Click Next
Tip: Using
*for repository and branch gives you flexibility, but for better security, specify exact repository and branch names in production.
Step 2: Add Permissions
Attach the necessary permissions for your deployment based on what AWS services you're using:
Common AWS Services:
-
Lambda & API Gateway:
AWSLambdaFullAccess,AmazonAPIGatewayAdministrator -
S3:
AmazonS3FullAccess -
EC2:
AmazonEC2FullAccess -
ECS/Fargate:
AmazonECS_FullAccess -
CloudFormation/CDK/Terraform:
CloudFormationFullAccess -
General deployments:
IAMFullAccess(or more restricted custom policy)
Note: In production, create a custom policy with least-privilege permissions specific to your needs.
Click Next to continue.
Step 3: Name, Review, and Create
-
Name the role: Enter a descriptive name (e.g.,
GitHubToAWSOIDC) - Description (optional): Add a description like "Role for GitHub Actions to deploy to AWS via OIDC"
-
Review:
- Step 1: Select trusted entities: Verify your GitHub org/repo settings
- Step 2: Add permissions: Verify the policies you attached
- Step 3: Add tags (optional): Add tags if needed for organization
- Click Create role
Copy the Role ARN
After the role is created successfully, find and copy the Role ARN (e.g., arn:aws:iam::123456789012:role/GitHubToAWSOIDC). You'll need this for the next step.
Understanding the Trust Policy (Reference)
AWS automatically generates a trust policy based on your selections. Here's what it looks like:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "sts:AssumeRoleWithWebIdentity",
"Principal": {
"Federated": "arn:aws:iam::YOUR_ACCOUNT_ID:oidc-provider/token.actions.githubusercontent.com"
},
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:aud": [
"sts.amazonaws.com"
]
},
"StringLike": {
"token.actions.githubusercontent.com:sub": [
"repo:YOUR_ORG/*"
]
}
}
}
]
}
Key elements:
-
token.actions.githubusercontent.com:aud: Ensures the token is intended for AWS STS -
token.actions.githubusercontent.com:sub: Restricts access based on your GitHub org/repo/branch selections-
repo:YOUR_ORG/*means any repository under your organization, any branch
-
Note: For most use cases, the trust policy generated by AWS from the UI is sufficient. You can manually edit it later if you need more specific control (e.g., specific repository, branch, or environment restrictions).
Step 3: Add GitHub Repository Secret
- Go to your GitHub repository
- Navigate to Settings → Secrets and variables → Actions
- Add a new repository secret:
-
Name:
AWS_ROLE_ARN -
Value: Your IAM role ARN (e.g.,
arn:aws:iam::123456789012:role/GitHubToAWSOIDC)
-
Name:
Step 4: Update GitHub Actions Workflow
Update your .github/workflows/deploy.yml to use OIDC instead of access keys:
Before (Access Keys):
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Configure AWS Credentials (Access Keys)
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-1
After (OIDC):
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
id-token: write # Required for requesting the JWT
contents: read # Required for actions/checkout
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Configure AWS Credentials (OIDC)
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
aws-region: us-east-1
Key Changes:
-
Added
permissionsblock:-
id-token: writeallows GitHub to create a JWT token -
contents: readallows checking out the repository
-
-
Replaced credentials:
- Removed
aws-access-key-idandaws-secret-access-key - Added
role-to-assumewith the IAM role ARN
- Removed
Updated step name: Changed from "Access Keys" to "OIDC" for clarity
Step 5: Clean Up Old Secrets (Optional)
After confirming OIDC works successfully, remove the old access key secrets:
- Go to Settings → Secrets and variables → Actions
- Delete
AWS_ACCESS_KEY_ID - Delete
AWS_SECRET_ACCESS_KEY
Important: Delete these secrets only after verifying OIDC authentication works!
Complete Workflow Example
Here's a complete workflow example deploying to AWS (this example uses Serverless Framework, but the OIDC configuration works with any deployment tool):
name: Deploy Lambda to AWS
on:
push:
branches:
- main
workflow_dispatch:
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22'
- name: Configure AWS Credentials (OIDC)
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
aws-region: us-east-1
- name: Install dependencies
run: npm install
- name: Deploy to AWS
run: npx serverless deploy --verbose
Testing the Setup
- Commit and push your changes to the
mainbranch - Navigate to Actions tab in your GitHub repository
- Monitor the workflow run
- Verify the "Configure AWS Credentials (OIDC)" step succeeds
Troubleshooting
If your deployment fails, the most common issue is insufficient permissions. Ensure your IAM role has all the necessary permissions for the AWS services you're deploying to. If you're using granular (least-privilege) permissions instead of the full access policies, you may need to add specific permissions based on the error messages in your GitHub Actions logs.
Security Best Practices
- Use specific conditions: Restrict the trust policy to specific branches or environments
- Least privilege permissions: Attach only the minimum required permissions to the IAM role
- Monitor usage: Enable AWS CloudTrail to audit role assumptions
- Regular reviews: Periodically review and update trust policies
- Use environments: For production deployments, use GitHub environments with protection rules
Comparison Summary
| Feature | Access Keys | OIDC |
|---|---|---|
| Credential lifetime | Permanent | Temporary |
| Rotation required | Yes | No |
| Secrets to manage | 2 per AWS account | 1 per IAM role |
| Security risk if leaked | High | Low |
| Setup complexity | Simple | Moderate |
Conclusion
By switching from AWS access keys to OIDC, you've improved your deployment security by:
- Eliminating long-lived credentials
- Reducing secret management overhead
- Implementing fine-grained access control
- Following AWS and GitHub security best practices
The initial setup requires more configuration, but the long-term security and maintenance benefits make OIDC the recommended approach for production deployments.
Additional Resources
Have you made the switch to OIDC? Share your experience in the comments below! 👇
Top comments (0)