Say Goodbye to Hardcoded AWS Creds in GitHub Actions with OIDC Magic ⭐

nathanb

Nathan Bridgewater

Posted on December 27, 2023

Say Goodbye to Hardcoded AWS Creds in GitHub Actions with OIDC Magic ⭐

I've been tinkering with GitHub actions over the last few months, often times with some kind of AWS interaction in my workflow. As it turns out, there are simple and less simple methods of authenticating your workflows with AWS. Let's explore how to use GitHub's OIDC provider to free yourself from hardcoded AWS credentials.

Hardcoded access keys

Lets be real, we've all hardcoded access keys before. For beginners and people who are just looking to get something running, hardcoded credentials are great, it's the most straightforward way to authenticate your workflow with AWS.

Here's a typical example:

- 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: us-east-1
Enter fullscreen mode Exit fullscreen mode

However, this does not align with best practices, duplicating and storing long lived credentials for your AWS account is not the most secure way to authenticate your workflows.

Enter OpenID Connect (OIDC)

OIDC, or OpenID Connect, is an authentication protocol that lets a third party (in our case, AWS) verify a user's identity through a JSON Web Token (JWT). With OIDC, authentication is outsourced to the OIDC provider. Once authenticated, the user can obtain a JWT from the identity provider, using it to authenticate with the third party.

Image description

In our scenario, GitHub acts as an OIDC provider for workflows. This means our workflow can request a JWT from GitHub and then use it to assume an AWS role by obtaining temporary credentials from AWS.

How to use GitHub's OIDC provider in your workflows

Let's walk through a simple example that builds a Docker image and pushes it to ECR using GitHub's OIDC provider. If you want to follow along, I've prepared a NodeJS application and Docker file in this following repository:

https://github.com/Nathan-Bridgewater/GitHub-AWS-OIDC.git

1. Create an identity provider in AWS

Firstly, we add GitHub as an identity provider. This configures AWS to accept OIDC tokens from a workflow and return temporary access credentials.

aws create-open-id-connect-provider \
--url https://token.actions.githubusercontent.com  \
--client-id-list sts.amazonaws.com \
--thumbprint-list 1b511abead59c6ce207077c0bf0e0043b1382612 \
Enter fullscreen mode Exit fullscreen mode

2. Create the trust policy

Craft a JSON file containing a trust policy for an AWS role, specifying which GitHub workflows can assume our role.

trust-policy.json

{
  "Version": "2012-10-17",
  "Statement": [
      {
          "Effect": "Allow",
          "Action": "sts:AssumeRoleWithWebIdentity",
          "Principal": {
              "Federated": "arn:aws:iam::<ACCOUNT NUM>:oidc-provider/token.actions.githubusercontent.com"
          },
          "Condition": {
              "StringEquals": {
                  "token.actions.githubusercontent.com:aud": [
                      "sts.amazonaws.com"
                  ]
              },
              "StringLike": {
                  "token.actions.githubusercontent.com:sub": [
                      "repo:Nathan-Bridgewater/GitHub-AWS-OIDC:*"
                  ]
              }
          }
      }
  ]
}
Enter fullscreen mode Exit fullscreen mode

3. Create the role

We need to establish a role for our federated workflow to assume, and attach a policy allowing our workflow to push images to ECR.

aws iam create-role \
--role-name github-workflow-role \
--assume-role-policy-document file://trust-policy.json 

aws iam attach-role-policy \
--role-name github-workflow-role \
--policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryPowerUser
Enter fullscreen mode Exit fullscreen mode

4. Create an ECR repository

Set up an ECR repository to push Docker images.

aws ecr create-repository \
--repository-name nodejs-images
Enter fullscreen mode Exit fullscreen mode

5. Create the GitHub workflow

push-docker-actions.yaml

name: push-docker-ecr-actions
run-name: ${{ github.actor }} is running the push-docker-ecr workflow
on:
  push:
    branches:
      - 'main'

permissions:
  id-token: write
  contents: read  

jobs:
  build-image-push-to-ecr:
    name: Build docker image and push to ecr
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume:  arn:aws:iam::<ACCOUNT NUM>:role/github-workflow-role
          aws-region: us-east-1
      - name: Login to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v1
      - name: Build, tag and push image to ECR
        env:
          ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
          ECR_REPOSITORY: nodejs-images
          IMAGE_TAG: latest
        run: |
          docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
          docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
Enter fullscreen mode Exit fullscreen mode

6. Test it out

Once added, your workflows should now authenticate with AWS without hardcoded credentials. Freedom awaits!

💖 💪 🙅 🚩
nathanb
Nathan Bridgewater

Posted on December 27, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related