GitHub Actions Tutorial — Deploy to AWS
Deploy to AWS
GitHub Actions integrates with AWS through OIDC (recommended) or static credentials. OIDC eliminates long-lived secrets — GitHub mints a short-lived token that AWS trusts directly.
Authentication — OIDC (Recommended)
1. Create an IAM OIDC Provider
In AWS Console → IAM → Identity providers → Add provider:
Provider URL: https://token.actions.githubusercontent.com
Audience: sts.amazonaws.com
2. Create an IAM Role
Trust policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::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:my-org/my-repo:*"
}
}
}
]
}
3. Use in Workflow
permissions:
id-token: write
contents: read
steps:
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::ACCOUNT_ID:role/github-actions-role
aws-region: us-east-1
No secrets needed — OIDC handles authentication.
Deploy to S3
name: Deploy to S3
on:
push:
branches: [main]
permissions:
id-token: write
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: ${{ secrets.AWS_ROLE_ARN }}
aws-region: us-east-1
- name: Build
run: npm ci && npm run build
- name: Sync to S3
run: aws s3 sync ./dist s3://${{ secrets.S3_BUCKET }} --delete
- name: Invalidate CloudFront
run: |
aws cloudfront create-invalidation \
--distribution-id ${{ secrets.CF_DISTRIBUTION_ID }} \
--paths "/*"
Deploy to ECS
name: Deploy to ECS
on:
push:
branches: [main]
permissions:
id-token: write
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: ${{ secrets.AWS_ROLE_ARN }}
aws-region: us-east-1
- uses: aws-actions/amazon-ecr-login@v2
id: ecr
- name: Build and push image
env:
ECR_REGISTRY: ${{ steps.ecr.outputs.registry }}
IMAGE_TAG: ${{ github.sha }}
run: |
docker build -t $ECR_REGISTRY/my-app:$IMAGE_TAG .
docker push $ECR_REGISTRY/my-app:$IMAGE_TAG
- name: Update ECS task definition
id: task-def
uses: aws-actions/amazon-ecs-render-task-definition@v1
with:
task-definition: task-definition.json
container-name: my-app
image: ${{ steps.ecr.outputs.registry }}/my-app:${{ github.sha }}
- name: Deploy to ECS
uses: aws-actions/amazon-ecs-deploy-task-definition@v2
with:
task-definition: ${{ steps.task-def.outputs.task-definition }}
service: my-app-service
cluster: my-cluster
wait-for-service-stability: true
Deploy Lambda Function
name: Deploy Lambda
on:
push:
branches: [main]
permissions:
id-token: write
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
aws-region: us-east-1
- name: Package and deploy
run: |
zip -r function.zip src/
aws lambda update-function-code \
--function-name my-function \
--zip-file fileb://function.zip
Common Mistakes
| Mistake | Fix |
|---|---|
id-token: write permission missing |
Required for OIDC — add at job or workflow level |
| OIDC trust policy too broad | Restrict sub claim to specific repos and branches |
| Secrets in logs | AWS CLI masks credentials, but avoid echo $SECRET |
Old aws-actions versions |
Use @v4 for configure-credentials, @v2 for ECR/ECS |
Quick Reference
| Target | Key Action |
|---|---|
| Auth (OIDC) | aws-actions/configure-aws-credentials@v4 |
| ECR | aws-actions/amazon-ecr-login@v2 |
| ECS | aws-actions/amazon-ecs-deploy-task-definition@v2 |
| S3 | aws s3 sync CLI command |
| Lambda | aws lambda update-function-code CLI command |
← Back to: Chapter 13: Deployments
Next: Deploy to Azure →