Deploying from GitHub Actions to AWS with OIDC (No Stored Keys)
Storing cloud access keys as GitHub secrets works, but those keys live forever and can leak. With OpenID Connect (OIDC), GitHub gives each workflow run a signed token, and your cloud exchanges it for temporary credentials. There are no keys to steal or rotate.
1. Trust GitHub in AWS
In IAM, add an identity provider for token.actions.githubusercontent.com with audience sts.amazonaws.com. Then create a role whose trust policy only accepts tokens from your repository and branch:
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": { "Federated": "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com" },
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
"token.actions.githubusercontent.com:sub": "repo:acme/shop:ref:refs/heads/main"
}
}
}]
}
The sub condition is critical: without it, any repository on GitHub could assume your role.
2. Use it in the workflow
name: Deploy
on:
push:
branches: [main]
permissions:
id-token: write # allow the job to request an OIDC token
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/github-deploy-shop
aws-region: ap-south-1
- run: aws s3 sync ./dist s3://shop-static --delete
- run: aws ecs update-service --cluster prod --service shop --force-new-deployment
Good practice
- Give the role only the permissions the deployment needs.
- Use separate roles for staging and production, with
subconditions on the matching environment (repo:acme/shop:environment:production). - Delete the old access keys from secrets once OIDC works.
Google Cloud (Workload Identity Federation), Azure and many other platforms support the same OIDC flow.
Was this article helpful?
Comments
No comments yet. Have a question or a tip? Be the first to share it.