skip to Main Content

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:
Access keys image

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


  1. Chosen as BEST ANSWER

    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:

    // AllowPushToAllRepo 
    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Action": [
                    "ecr:CompleteLayerUpload",
                    "ecr:GetAuthorizationToken",
                    "ecr:UploadLayerPart",
                    "ecr:InitiateLayerUpload",
                    "ecr:BatchCheckLayerAvailability",
                    "ecr:PutImage"
                ],
                "Resource": "*"
            }
        ]
    }
    
    // CreateTaskDefinition
    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Action": [
                    "iam:PassRole",
                    "ecs:RegisterTaskDefinition",
                    "ecs:DescribeServices",
                    "ecs:DescribeTaskDefinition",
                    "ecs:UpdateService"
                ],
                "Resource": "*"
            }
        ]
    }
    
    

    (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.


  2. 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

    enter image description here

    • For the provider URL: Use https://token.actions.githubusercontent.com
    • For the "Audience": Use sts.amazonaws.com

    2. Create an IAM role

    Create an IAM web identity role with the proper privileges to push to AWS ECR.

    Create IAM Web Identity role

    3. Configure GitHub actions to assume the role

    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:
            role-to-assume: arn:aws:iam::${{ env.AWS_ACCOUNT }}:role/${{ env.AWS_ROLE }}
            aws-region: ${{ env.AWS_REGION }}
    

    For more information see "Use IAM roles to connect GitHub Actions to actions in AWS
    "
    .

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search