Deploying to AWS from GitHub Actions
A clean AWS deploy is OIDC auth, an image push, and a service update.
AWS deployments from GitHub Actions follow a repeatable shape: assume a role with OIDC, build and push a container to ECR, then update the running service. This lesson assembles a working ECS workflow you can adapt to other AWS targets.
The deploy shape
- Assume an IAM role via OIDC (no stored keys).
- Log in to Amazon ECR and push the built image.
- Update the ECS service (or Lambda, Beanstalk, etc.) to the new image.
- Wait for the service to stabilize before marking the deploy done.
A working ECS workflow
This job authenticates, pushes to ECR, and rolls the ECS service to the new image tag:
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
- uses: aws-actions/amazon-ecr-login@v2
id: ecr
- run: |
IMAGE=${{ steps.ecr.outputs.registry }}/app:${{ github.sha }}
docker build -t $IMAGE .
docker push $IMAGE
- run: aws ecs update-service --cluster prod --service app --force-new-deploymentLeast-privilege roles
The assumed role should grant only what the deploy needs: push to one ECR repo, update one ECS service. Avoid broad administrator roles. Scope the OIDC trust policy to the specific repository and the production branch or environment.
Confirm the rollout
Do not treat the API call as success. Wait for ECS to report the service stable, so a failed task does not silently leave the old version running:
aws ecs wait services-stable --cluster prod --services appKey takeaways
- Authenticate to AWS with OIDC instead of storing access keys.
- Build and push to ECR, then force a new ECS service deployment.
- Wait for the service to stabilize so failed rollouts are caught.