Actions Container Job using ECR-Sourced Image

Observations made during testing of a GitHub actions container job posed some challenges/constraints, specifically related to masking of credentials when pulling ECR-based images. Authenticating to an Amazon container registry depends on retrieving a “dynamic” login password, i.e.,

$ aws ecr get-login-password --region us-east-1

The password is used to pull the required image from ECR. Addition of “preprocessing” capability to setup credentials would be ideal, however, this behaviour is not supported, and is generally accomplished by including a predecessor job.

Rather than building customized actions from scratch, I decided to use the docker container action as an alternative.

This post provides:

  • an example of showing GitHub’ official container action being used within a workflow
  • the implications of the constraint mentioned above
  • references to guidelines on masking secrets between jobs
  • a sample of the revised workflow using the docker container action

Using GitHub’ Container Job Approach

As previously mentioned, pulling images from ECR requires a “dynamic” password which would then be used as input by the container job.

The sample workflow below is made up two jobs:

  • retrieve-ecr-creds: generates password for authenticating to ECR registry
  • container-job-sample: uses the password to run a container job from the ECR image
name: GitHub Actions Container Job

on:
  workflow_dispatch:

permissions:
  contents: read
  id-token: write

jobs:
  retrieve-ecr-creds:
    runs-on: [self-hosted]
    steps:
      - name: Configure AWS credentials
        id: creds
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::nnnnnnnnnnnn:role/assumed-oidc
          aws-region: <region>

      - name: Login to ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v2

    outputs:
       docker_password: ${{ steps.login-ecr.outputs.docker_password_nnnnnnnnnnnn_dkr_ecr_<region>_amazonaws_com }}
       registry: ${{ steps.login-ecr.outputs.registry }}
 
  container-job-sample:
    name: Run job in container
    needs: [retrieve-ecr-creds]
    runs-on: [self-hosted]
    container:
      image: ${{ needs.retrieve-ecr-creds.outputs.registry }}/my-ecr-image:latest
      credentials:
        username: AWS
        password: ${{ needs.retrieve-ecr-creds.outputs.docker_password }}
    steps:
      - name: Checkout repo
        uses: actions/checkout@v4
      - name: Run steps in container
        run: |
            echo "running inside container"

As a result of credentials being passed between the jobs, triggering the workflow in “debug” mode leads to the unmasked ECR password appearing in the output logs.

Rerun Workflow Debug Mode
Unmasked Ecr Password

Guidelines on Masking Credentials Between Jobs

GitHub’ official guidelines, provide an example of masking credentials between workflow/jobs by the use of a secrets store.

Organization, repository or environment secrets can also established to ensure credentials are not exposed.

For example, in our sample workflow, we could update the retrieve-ecr-creds job to use the gh secret CLI command to store/update the ECR password as a repository secret with name ECR_TEMP_PASSWORD:

...
...

jobs:
  retrieve-ecr-creds:
    runs-on: [self-hosted]
    steps:
      - name: Configure AWS credentials
        ...
      - name: Login to ECR
        id: login-ecr
        run: |
          ...
          gh secret set ECR_TEMP_PASSWORD \
             --repo ${{ github.repository }} <<<"$(aws ecr get-login-password --region <region>)"

  container-job-sample:
    name: Run job in container
    needs: [retrieve-ecr-creds]
    runs-on: [self-hosted]
    ...
    container:
      image: nnnnnnnnnnnn.dkr.ecr.<region>_amazonaws_com/my-ecr-image:latest
      credentials:
        username: AWS
        password: ${{ secrets.ECR_TEMP_PASSWORD }}

Alternative: Using the Docker Container Action

The following is a sample workflow using the docker-container-action as an alternative to running the container job.

name: Run Container job using docker-container-action

on:
  workflow_dispatch:

permissions:
  id-token: write

jobs:
  container-job-sample:
    runs-on: [self-hosted]
    steps:
      - name: Checkout repo
        uses: actions/checkout@v4

      - name: Configure AWS credentials
        id: creds
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::nnnnnnnnnnnn:role/assumed-oidc
          aws-region: <region>
          mask-aws-account-id: "true"

      - name: Login to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v2
        with:
          mask-password: "true"

      - name: Run container using ECR Image
        uses: pl-strflt/docker-container-action@v1
        with:
          docker-registry-url: nnnnnnnnnnnn.dkr.ecr.<region>.amazonaws.com
          image: my-ecr-image
          tag: latest
          repository: ${{ github.repository }}
          ref: ${{ github.ref_name }}
          args: |
            echo "running inside container"