I am trying to setup a Github Actions workflow that automatically builds a docker image from my repo and pushes it to Amazon ECR.
Here is my code for aws.yml, which is based on this tutorial by github here.
name: Deploy to Amazon ECS
on:
push:
branches: [ "main" ]
env:
AWS_REGION: ap-southeast-2 # set this to your preferred AWS region, e.g. us-west-1
ECR_REPOSITORY: z-coord-repo/api-service # set this to your Amazon ECR repository name
ECS_SERVICE: z-coord # set this to your Amazon ECS service name
ECS_CLUSTER: z-coord-cluster # set this to your Amazon ECS cluster name
ECS_TASK_DEFINITION: .aws/task-definition.json # set this to the path to your Amazon ECS task definition
# file, e.g. .aws/task-definition.json
permissions:
contents: read
jobs:
deploy:
name: Deploy
runs-on: ubuntu-latest
environment: production
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ env.AWS_REGION }}
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v1
- name: Build, tag, and push image to Amazon ECR
id: build-image
env:
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
IMAGE_TAG: ${{ github.sha }}
working-directory: ./api-service
run: |
# Build a docker container and
# push it to ECR so that it can
# be deployed to ECS.
docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
echo "image=$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" >> $GITHUB_OUTPUT
However, this workflow keeps failing, giving the error The security token included in the request is invalid.
. After some googling, I learned that a workaround is to include the IAM session token as a secret, and add it to the "Configure AWS Credentials" action. The new action is like so:
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ env.AWS_REGION }}
aws-session-token: ${{ secrets.AWS_SESSION_TOKEN }}
This modified workflow runs and works as expected, however the session token expires after some time. Sure enough, when I tried it again the next day I got an error saying that the token had expired. In order to get it to run again, I would need to manually copy-paste the new session token into the github secret every day.
Is this expected behaviour? If so, why does the tutorial not mention this? I feel like I’m missing something.
EDIT 1:
So I might have simply made a noob mistake. I assumed I had to use the IAM credentials from the AWS access portal:
And I’ve noticed that all 3 get changed automatically after some time anyway. I think this means we’re not supposed to use these credentials here. I think the actual credentials required are the ones described here. I will ask my administrator for this and update this post in time.
EDIT 2
Both my admin and I are new to AWS. We tried for a while to follow the instructions here, but I was not able to choose the "Security credentials" button as described in step 2 as it never appeared for me, no matter how many permissions the admin gave me.
I am thinking this is because my account was created in the IAM Identity Center instead of IAM. I’m not sure but it seems these are two different types of users?
Please correct me if my understanding is wrong. We will experiment with creating an IAM user instead. I will update this post in time.
2
Answers
My issue was that I had misunderstood what access keys I was supposed to use. Initially, I thought that I had to use the access keys from the AWS Access Portal (see screenshot in EDIT1), but those keys are temporary and are supposed to be used for logging in to AWS from the terminal.
Instead, I am supposed to create an IAM user within my own account using the IAM dashboard (not the IAM Identity Center), and grant it the relevant permissions for pushing to the ECR and creating and deploying task definitions. In case this helps anyone, here are the permission policies I created:
(I am aware that setting the resource to "*" is a bad practice. I will change this once I figure out how to correctly set the ARN so that it points to the multiple different resources I want.)
This IAM user will be able to see the resources created by me in my account. I used this user's access keys to authorize the workflow.
As pointed out to me in another answer by Arnold Daniels, Amazon does not recommend this practice. Instead, I should be using the OIDC method. From what I understand, the OIDC method only allows a certain GitHub repository to perform actions on AWS, and this is why it is more safe. I will be looking into switching to that method in the future.
AWS highly recommends not using access tokens for CI workflows, but use AWS OpenID Connect (OIDC) instead. This is less prone to errors and much more secure, since the role is locked to a specific GitHub organization or repository.
1. Add GitHub as Identity Provider
https://token.actions.githubusercontent.com
sts.amazonaws.com
2. Create an IAM role
Create an IAM web identity role with the proper privileges to push to AWS ECR.
3. Configure GitHub actions to assume the role
For more information see "Use IAM roles to connect GitHub Actions to actions in AWS
".