This guide walks through automating container publishing to Amazon Elastic Container Registry (ECR) using GitHub Actions and OpenID Connect (OIDC) for secure authentication — without relying on long-lived AWS credentials.

Goal
Automate the build and deployment of a Docker image to Amazon ECR directly from a GitHub Actions workflow triggered by a branch push.
Prerequisites
Before proceeding, ensure you have:
- An active AWS Account with permissions to create IAM resources.
- A GitHub repository with a valid OIDC trust relationship to AWS.
- A Dockerfile defining your container image.
Process Overview
The complete process involves:
- Creating an IAM Policy & Role with permissions to push images to ECR.
- Setting up OIDC-based authentication for GitHub Actions.
- Configuring GitHub Secrets and Variables to provide AWS access details.
- Defining a GitHub Actions workflow to build, tag, and push the container image.
- (Optional) Adding an automated Release step to publish a GitHub release with the image URI.
IAM Policy & Role
The IAM Policy grants permissions to upload and manage images in your ECR repository, as well as limited access to AWS Secrets Manager for sensitive data like keystore credentials.
Attach this policy to a Role that your GitHub Action will assume via OIDC authentication.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PushImageToECR",
"Effect": "Allow",
"Action": [
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage",
"ecr:CompleteLayerUpload",
"ecr:DescribeImageReplicationStatus",
"ecr:TagResource",
"ecr:DescribeRepositories",
"ecr:ListTagsForResource",
"ecr:UploadLayerPart",
"ecr:GetImageCopyStatus",
"ecr:ListImages",
"ecr:InitiateLayerUpload",
"ecr:PutImage"
],
"Resource": "arn:aws:ecr:*:<ACCOUNT ID>:repository/*"
},
{
"Sid": "AccessECR",
"Effect": "Allow",
"Action": [
"ecr:BatchCheckLayerAvailability",
"ecr:DescribeRegistry",
"ecr:GetAuthorizationToken"
],
"Resource": "*"
},
{
"Sid": "SecretsManagerAccess",
"Effect": "Allow",
"Action": [
"secretsmanager:CreateSecret",
"secretsmanager:PutSecretValue",
"secretsmanager:UpdateSecret",
"secretsmanager:GetSecretValue"
],
"Resource": "arn:aws:secretsmanager:*:<ACCOUNT ID>:secret:users-api-keystore-passphrase*"
}
]
}
you can do so via the Console UI, or using the aws CLI:
aws iam create-policy \
--policy-name ECRPublishPolicy \
--policy-document file://ecr-policy.json
Next, define a Role that can be assumed by GitHub’s OIDC provider.
This enables short-lived credentials for your workflow without using static access keys.
{
"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:alertavert/*",
"repo:alertavert/*"
]
}
}
}
]
}
the Role ARN (arn:aws:iam::<ACCOUNT ID>:role/github-actions) will be used in the role-to-assume parameter for the configure-aws-credentials action later.
Setup GitHub Action to Access AWS
Create the OIDC identity provider in AWS IAM for GitHub, which enables trust between your GitHub workflows and AWS.
In the AWS Console, navigate to IAM → Identity Providers → Add provider, then select:
- Provider type:
OpenID Connect - Provider URL:
https://token.actions.githubusercontent.com - Audience:
sts.amazonaws.com
Alternatively, use the AWS CLI as described in the AWS IAM OIDC guide.
Once configured, store your Role ARN (created earlier) as a GitHub Repository Secret (AWS_ROLE_ARN), and your region (e.g. us-west-2) as a Repository Variable (AWS_REGION).
Create the GitHub Action to Build and Push Image to ECR
This workflow builds and tags your Docker image, authenticates with ECR using OIDC, and pushes the resulting image to your AWS registry whenever changes are pushed to the release branch.
# Upon pushing to the release branch a new tag will be created
# in preparation for the release.
#
# Copyright (c) 2023 AlertAvert.com. All rights reserved.
# Author: Marco Massenzio (marco@alertavert.com)
#
name: Release
on:
push:
branches:
- release
env:
AUTHOR: ${{ github.event.pusher.name }}
EMAIL: ${{ github.event.pusher.email }}
permissions:
id-token: write # This is required for requesting the JWT (OIDC auth for AWS)
contents: write # This is required for actions/checkout & to update the tag
jobs:
release:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
fetch-tags: true
- name: Create a Release Tag
run: |
git config user.name "$AUTHOR"
git config user.email "<$EMAIL>"
TAG=$(./scripts/version)
echo "Preparing to create release tag: ${TAG}"
# Ensure we have up-to-date tags from origin
git fetch --tags --prune origin
# Check if the tag already exists in the remote repository
if git ls-remote --exit-code --tags origin "refs/tags/${TAG}" >/dev/null 2>&1; then
echo "::error title="Duplicate tag"::Tag ${TAG} already exists." \
"Aborting release to avoid duplicate tags." >&2
exit 1
fi
# Create annotated tag and push just this tag
git tag -a "${TAG}" -m "Release ${TAG}"
git push origin "refs/tags/${TAG}"
echo TAG=${TAG} >> "$GITHUB_ENV"
echo -e "## New Tag\nCreated release tag: ${TAG} :tada:" >> $GITHUB_STEP_SUMMARY
# ---- Configure AWS credentials via OIDC ----
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
aws-region: ${{ vars.AWS_REGION }}
# ---- Login to ECR ----
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v2
- name: Build and Push Docker image to ECR
env:
REGISTRY: ${{ steps.login-ecr.outputs.registry }}
REPOSITORY: alertavert/users-api
run: |
if [[ -z "${REGISTRY}" ]]; then
echo "::error title="Missing Registry"::Should have been set by the login-ecr step."
exit 1
fi
set -euo pipefail
echo "Publishing Image to Amazon ECR: ${REGISTRY}"
./scripts/build-image "${REGISTRY}"
export WORKDIR=$(pwd)
source ./scripts/common.sh # For the image_name function
IMAGE_TAG="${REGISTRY}/$(image_name)"
echo "Pushing ${IMAGE_TAG}"
docker push "${IMAGE_TAG}"
echo "🚀 Container image published: ${IMAGE_TAG}" >> release_notes.txt
echo -e "## ECR Image\nPushed new Image to\n\n\`${IMAGE_TAG}\` :white_check_mark:" >> $GITHUB_STEP_SUMMARY
This workflow uses GitHub’s native OIDC token exchange to authenticate to AWS, securely assuming the role without credentials stored in GitHub.
Create a Release (Optional)
Optionally, the workflow can generate a GitHub Release once the image has been successfully pushed.
This is useful for tagging published artifacts and linking them to release notes.
# Creates a new release in GitHub, with auto-generated content.
- uses: ncipollo/release-action@v1
with:
tag: "${{ env.TAG }}"
bodyFile: "release_notes.txt"
- name: Release Summary
run: |
echo -e "## Release Summary\nReleased version: ${TAG} :rocket:" >> $GITHUB_STEP_SUMMARY
Note: The
bodyFileoption is incompatible withgenerateReleaseNotes: true.
To include custom release content such as the ECR image URI, usebodyFileexclusively.
References
- Configuring OpenID Connect in Amazon Web Services – GitHub Docs
- Create an OpenID Connect (OIDC) Identity Provider in IAM – AWS Docs
- AWS ECR Actions – GitHub Marketplace
- Configure AWS Credentials Action – GitHub Marketplace
- Using Secrets in GitHub Actions – GitHub Docs
- How OpenID Connect Works – OpenID Foundation




Leave a comment