GitHub Actions Deploy to AWS ECS Workflow

Generate an ECS deploy workflow with ECR push and task definition update

Build a GitHub Actions workflow that logs into Amazon ECR, builds and pushes a Docker image, renders a new ECS task definition, and deploys to ECS Fargate using OIDC role assumption — no long-lived AWS keys required. It runs free in your browser on Gera Tools, with nothing uploaded.

Last updated Source: Gera Tools

Why use OIDC instead of access keys?

OIDC lets GitHub Actions assume an IAM role using short-lived credentials minted per run, so there are no long-lived AWS access keys stored in secrets to leak. It is AWS's recommended approach for CI and limits the blast radius of a compromise.

Deploying a container to AWS ECS Fargate from CI involves several precise steps: authenticating to ECR, building and tagging an image, pushing it, and registering a new task definition revision. This generator produces a complete GitHub Actions workflow that does all of that using OIDC role assumption, so no static AWS keys live in your repository.

How it works

The workflow uses the official AWS actions in a fixed order:

  1. aws-actions/configure-aws-credentials assumes your IAM role via GitHub’s OIDC token — short-lived credentials, no stored keys.
  2. aws-actions/amazon-ecr-login authenticates Docker to your private ECR registry.
  3. docker build and docker push create and upload the image tagged with the commit SHA.
  4. aws-actions/amazon-ecs-render-task-definition injects the new image into your task definition JSON.
  5. aws-actions/amazon-ecs-deploy-task-definition registers the revision and updates the service, waiting for stability.

Why OIDC instead of access keys

Static AWS access keys stored in GitHub Secrets are a persistent security risk: they do not expire, they apply as long as the IAM user exists, and if they leak (through a log line, a public fork, or a compromised runner) they give access until you manually rotate them.

GitHub Actions OIDC works differently. GitHub mints a short-lived JWT for each workflow run, and AWS’s OIDC provider validates it against a trust policy you configure on an IAM role. The credentials are valid only for that run and expire automatically — there are no long-lived keys to manage, rotate, or worry about leaking.

Setting it up requires two things:

  1. An IAM Identity Provider in your AWS account pointing at token.actions.githubusercontent.com.
  2. An IAM role with a trust policy that allows GitHub to assume it, typically scoped to your org and repo.

Deploying and rolling back with commit-SHA tags

Every image the workflow builds is tagged with the full commit SHA (for example 123abc4). This creates a direct mapping between code and container: you can always trace which exact commit is running in production by looking at the task definition’s image tag.

Rolling back is then straightforward: create a new task definition revision that points at the SHA of the last known-good image, and ECS deploys that container without a new build. No re-building, no re-testing — just a pointer change.

The task definition file

The workflow requires a base task definition JSON file in your repository (typically task-definition.json). The render action reads this file, replaces the image URI for the named container, and outputs a new file with the updated image tag that gets registered as the new revision.

Keep this file in version control so you can see how the task definition changes over time.

Tips and notes

  • Grant the IAM role only ecr:* on the repository plus the ECS and IAM PassRole permissions it needs — least privilege.
  • Tagging by commit SHA makes rollbacks trivial: re-deploy a prior task definition revision pointing at the old SHA.
  • Set wait-for-service-stability: true so the job fails if the new tasks never reach a healthy steady state.
  • Keep a base task definition JSON file in your repo so the render step has something to patch.
  • Run this deploy workflow only after a successful CI workflow using workflow_run or needs: to prevent deploying broken code.