Building and publishing artifacts is often a crucial step in the CI/CD pipeline, and automating the process is key to rapid software development. The steps below show how to use GitHub Actions to automatically build Docker images whenever a series of commits are pushed to GitHub and then publish those images to a repository in AWS's Elastic Container Registry (ECR).

Step 1: Set up authorization

Follow the first two steps from the post on GitHub Actions for AWS. Save the created role's ARN to use in the steps below.

Step 2: Update the AWS role permissions

Create a policy that gives the minimal necessary permissions for GitHub to log into an ECR repo and push/pull images from it. Attach this policy to the role created earlier.

The below policy works for a private ECR repo:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ecr:BatchCheckLayerAvailability",
                "ecr:BatchGetImage",
                "ecr:CompleteLayerUpload",
                "ecr:GetAuthorizationToken",
                "ecr:GetDownloadUrlForLayer",
                "ecr:InitiateLayerUpload",
                "ecr:UploadLayerPart",
                "ecr:PutImage"
            ],
            "Resource": "*"
        }
    ]
}

For a public ECR repo, follow the official instructions.

Step 3: Create a GitHub Actions workflow

Create a YAML file inside the .github/workflows directory of the GitHub repo. In the file, include steps to configure AWS credentials for the runner, log into ECR, setup Docker Buildx, extract tags to apply to the Docker image, and finally build and publish the image to ECR. A workflow file that accomplishes all these tasks is shown below:

name: Build and publish

env:
  AWS_ACCOUNT: <AWS_ACCOUNT_NUMBER>
  AWS_REGION: <AWS_REGION>
  AWS_ROLE: <AWS_ROLE_ARN>
  ECR_REPO: <ECR_REPO_NAME>

jobs:
  build-and-publish:
    name: Build and publish Docker image
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read
    steps:
    - 
      name: Checkout code
      uses: actions/checkout@v3
    - 
      name: Configure AWS credentials
      uses: aws-actions/configure-aws-credentials@v1-node16
      with:
        role-to-assume: ${{ env.AWS_ROLE }}
        aws-region: ${{ env.AWS_REGION }}
    - 
      name: Log in to AWS ECR
      uses: aws-actions/amazon-ecr-login@v1
    - 
      name: Setup Docker Buildx
      uses: docker/setup-buildx-action@v2
    - 
      name: Extract Docker tags
      id: metadata
      uses: docker/metadata-action@v4
      with:
        images: |
          ${{ AWS_ACCOUNT }}.dkr.ecr.${{ env.AWS_REGION }}.amazonaws.com/${{ env.ECR_REPO }}
        tags: |
          type=raw,value=latest
          type=sha
    - 
      name: Build and publish Docker image
      uses: docker/build-push-action@v4
      with:
        context: .
        push: true
        tags: ${{ steps.metadata.outputs.tags }}
        cache-from: type=gha
        cache-to: type=gha,mode=max

Step 4: Profit!

Push new code up to the remote repository and check out the Actions tab on GitHub to see the new workflow get kicked off!