Using GitHub Actions with AWS IAM roles

Table of Contents

Problem statement

There are many different and interesting DevOps tools on the market nowadays. Companies can use and combine them depending on use cases, cost, historical reasons, personal preferences, etc. Some tools can be integrated with others quite well, others – not. No matter which tools we use, there are fundamental and critical areas that always should be under control, such as Security.

Automat-it as APN Partner is continuously conducting Well-Architected Reviews. Security is one of WAR pillars and it has to be evaluated not only for AWS resources, but for 3d party integrations as well. During one of the reviews we found out that GitHub Actions are used as CI/CD tools to deploy serverless applications in AWS. The simplest and fastest way to provide 3d party tolls with access to AWS is IAM user – static and long-term credentials and it was done exactly in this way, but we should avoid using IAM users wherever possible. Fortunately there is a way to get rid of IAM users and start using IAM roles with dynamic and short-term credentials.

Solution overview

First of all let’s look at how GitHub Actions use IAM users. GitHub secrets allow us to store sensitive data securely, but the main concern here is secret retention.

AWS_DEV_KEY_ID and AWS_DEV_SECRET values were stored in GutHub secrets in advance. Later we can use them in a pipeline.

name: Example
on:
 pull_request:
   branches: [ master ]
 
jobs:
 pull_request:
   runs-on: ubuntu-latest
 
   env:
     AWS_ACCESS_KEY_ID: ${{ secrets.AWS_DEV_KEY_ID }}
     AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_DEV_SECRET }}
 
   steps:
   - name: Checkout
     uses: actions/checkout@v2
 
   - name: Some AWS commands
     run: |
       aws --region us-east-1 .....

According to Security best practices in IAM , applications and services should use IAM roles instead of IAM users. Fortunately it is possible to configure it for GitHub actions using OIDC.

IAM OIDC identity providers are entities in IAM that describe an external identity provider (IdP) service that supports the OpenID Connect (OIDC) standard. You use an IAM OIDC identity provider when you want to establish trust between an OIDC-compatible IdP (GitHub in our case) and your AWS account.

1. Create a new Identity provider

For the provider URL: Use https://token.actions.githubusercontent.com

For the « Audience »: Use sts.amazonaws.com if you are using the official action.

2. Create an IAM role and select the Identity provider created earlier.

Once the role has been created, you need to modify Trust policy

{
   "Version": "2012-10-17",
   "Statement": [
       {
           "Effect": "Allow",
           "Principal": {
               "Federated": "arn:aws:iam::3**********0:oidc-provider/token.actions.githubusercontent.com"
           },
           "Action": "sts:AssumeRoleWithWebIdentity",
           "Condition": {
               "StringEquals": {
                   "token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
               },
               "StringLike": {
                   "token.actions.githubusercontent.com:sub": "repo:Example-org/*:*"
               }
           }
       }
   ]
}

Above condition allows whole GitHub org Example-org (all repos and branches) but you can also set particular repo and branch, for example:

"Condition": {
    "ForAllValues:StringEquals": {
        "token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
        "token.actions.githubusercontent.com:sub": "repo:octo-org/octo-repo:ref:refs/heads/octo-branch"
     }
 }

Once the IAM Role is ready, you can use it in GutHub Actions manifest. The job or workflow run requires a permissions setting with id-token: write. You won’t be able to request the OIDC JWT ID token if the permissions setting for id-token is set to read or none. The aws-actions/configure-aws-credentials action receives a JWT from the GitHub OIDC provider, and then requests an access token from AWS.

name: Example pipeline
on:
 pull_request:
   branches: [master]

permissions:
 id-token: write
 contents: read# This is required for actions/checkout@v2

jobs:
 pull_request:
   runs-on: ubuntu-latest

   env:
     AWS_DEFAULT_REGION: us-east-1

   steps:
   - name: configureawscredentials
     uses: aws-actions/configure-aws-credentials@v1
     with:
       role-to-assume: arn:aws:iam::3**********0:role/github-actions-role
       role-session-name: samplerolesession
       aws-region: ${{env.AWS_DEFAULT_REGION}}

   - name: Checkout
     uses: actions/checkout@v2

   - name: Some AWS commands
     run: |
       aws --region us-east-1 ……

Conclusion

AWS Well-Architected review helps cloud architects build secure, high-performing, resilient, and efficient infrastructure for a variety of applications and workloads. Security is one of six pillars, probably the most important. Proper IAM configuration is a common case for improvements, including the least privilege principle and rotation of credentials. In this post we looked at how to use IAM roles for GitHub actions as best security practice.