GitHub Actions and no AWS credentials

At GRRR we know AWS STS assume role, because AWS Lambda functions use it. Now it's possible to use it in GitHub workflows to access the AWS API. I use the workflow that publishes this blog as an example.


Some background

To access the AWS API you can use an access key id. That gives an IAM user access to the API. Works fine, but the downside is that you have to provide credentials. In the case of a GitHub workflow two secrets containing the access key id and secret access key.

But there is another method. You can assume an IAM role. By using the credentials of your personal account you are allowed to become a role and gain access to other AWS resources. This makes it possible to give your private AWS account access to resources in another AWS account. A short-lived access token is created in the background and used to authenticate.

This method isn’t limited to giving access to other AWS accounts. AWS Lambda uses this method to give the Lambda function access to AWS resources within an account. Upon invoking the Lambda function an access token is created. That token gives access to the resources defined by the role policies.

It took me some time to wrap my head around, so here are some resources that helped me:

📖 A clear StackOverflow answer

📖 AssumeRole is a feature of AWS STS

OpenID

Since November 23 OpenID for GitHub Actions is generally available. With OpenID, GitHub can request short-lived access tokens directly from cloud providers. In this article I use AWS, but Azure, Google Cloud Platform, and HashiCorp are also available.

📖 Read the official announcement

Let’s get our hands dirty.

Identity provider

First, add GitHub as OpenID provider to IAM Identity providers. This connects AWS and GitHub, so they can exchange tokens.

Add GitHub as identity provider to AWS IAM.

Provider URL: https://token.actions.githubusercontent.com
Audience: sts.amazonaws.com

IAM role

Instead of a user, you have to create a role with a trust relationship. It’s a relationship between the role and the added GitHub identity provider.

Create an AWS IAM role

Press Next to add permissions. It’s the same as adding permissions to a user. You can copy the policies of the user you currently use.

Add permissions to the role

The last step is changing the trust relationship condition to restrict usage of the role. You can do a lot more with token.actions.githubusercontent.com:sub. This is just a simple one that restricts access from a specific repository, but you can use environments, event types, users, and a lot more. You can read about it in the GitHub Documentation.

📖 Read about security hardening

The new roles trust relationship with GitHub

The GitHub OpenID identifier is allowed to assume this role, but only when called from a workflow in the repository grrr-amsterdam/grrr.tech

Click on “Edit trust relationship” to start editing.

..
  "Condition": {
    "StringLike": {
      "token.actions.githubusercontent.com:sub": "repo:organization/repository:*"
    }
  }
..

If you want to use the role in multiple repositories you can let it match “repository-a” OR “repository-b”:

..
  "Condition": {
    "StringLike": {
      "token.actions.githubusercontent.com:sub": [
        "repo:organization/repository-a:*",
        "repo:organization/repository-b:*"
      ]
    }
  }
..

Update the workflow file

Finally, we can do something with the workflow file. It’s not a lot, but removing secrets is my favorite part. This is a simplified version of the workflow grrr.tech uses to deploy new versions.

name: Deploy

on:
  push:

jobs:
  deploy:
    name: Deploy
    runs-on: ubuntu-18.04

    permissions:
      id-token: write
      contents: read

    steps:
      - uses: actions/checkout@v2

      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          role-to-assume: arn:aws:iam::111111111111:role/deploy-grrr.tech
          aws-region: eu-central-1

      - name: Build
        ...

      - name: Publish front-end
        run: aws s3 sync . s3://grrr.tech

What changed?

The secrets containing AWS credentials have been removed:

env:
    AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
    AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

Before the workflow is allowed to create an OpenID token you have to modify the default permissions granted to the GitHub API token (GITHUB_TOKEN). You must add the id-token permission to the workflow file.

permissions:
  ...
  id-token: write
  ...

The step “Configure AWS Credentials” does the magic and authenticates the workflow.

📖 aws-actions/configure-aws-credentials documentation

All done!

And that’s it. Now you can remove the user! Or disable the access key id first, just to be sure.

Cheers!