Connect GitHub Actions with AWS using OpenID Connect

Sep 26, 2024 3-minute read

💡

This post is also featured on the PostNL Engineering blog on Medium!

A common pattern is to invoke AWS actions from a GitHub Actions workflow. For example, a workflow can be used for AWS CDK deployments, invoking a Lambda function (e.g., for integration tests) or reading data from DynamoDB.

Using OpenID Connect (OIDC) such AWS actions can be invoked by an IAM role. The role trusts a specific GitHub repository or branch, giving granular control over how GitHub Actions can use AWS credentials. This solution uses temporary credentials, meaning that there is no need to store and rotate long-lived credentials.

This post demonstrates how to allow a specific GitHub repository branch to access AWS (with AWS CDK in TypeScript) and invoke actions on an AWS account (with GitHub Actions).

The code used in this post can be found on GitHub.

Create IAM OIDC Identity Provider

To establish a trust relationship between GitHub and AWS, create an IAM OIDC Identity Provider for GitHub.

const oidcProvider = new iam.CfnOIDCProvider(this, "GithubOidcProvider", {
  url: "https://token.actions.githubusercontent.com",
  clientIdList: ["sts.amazonaws.com"],
});

Create IAM Role

Next, the created identity provider is used to create an IAM role. The trust policy of the role defines which specific GitHub repository branch is allowed to assume the role (using the pattern repo:OWNER/REPOSITORY:ref:refs/heads/BRANCH).

const conditions: iam.Conditions = {
  StringEquals: {
    "token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
    "token.actions.githubusercontent.com:sub":
      "repo:mellevanderlinde/oidc-aws-github:ref:refs/heads/main",
  },
};

const oidcRole = new iam.Role(this, "GithubOidcRole", {
  roleName: "github-oidc-role",
  assumedBy: new iam.WebIdentityPrincipal(oidcProvider.ref, conditions),
});

Alternatively, an entire GitHub repository can be allowed using a wildcard * in the conditions. For this, StringLike is required instead of StringEquals.

const conditions: iam.Conditions = {
  StringEquals: {
    "token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
  },
  StringLike: {
    "token.actions.githubusercontent.com:sub":
      "repo:mellevanderlinde/oidc-aws-github:*",
  },
};

For other patterns (e.g. allowing specific GitHub environments), see Example subject claims.

Attach Permissions to IAM Role

To invoke AWS actions, the OIDC role needs to have the correct permissions. In this case the cdk diff command will be run, requiring read only permissions. Therefore, the OIDC role is granted permission to assume the lookup role (created when the AWS account is CDK bootstrapped).

const lookupRole = iam.Role.fromRoleName(
  this,
  "LookupRole",
  `cdk-hnb659fds-lookup-role-${this.account}-${this.region}`,
);

lookupRole.grantAssumeRole(oidcRole);

Assume IAM Role from GitHub Actions Workflow

Next, the IAM role is assumed from a GitHub Actions workflow. This is done with the action configure-aws-credentials, resulting in the following .github/workflows/oidc.yml file. Note that a dummy AWS account ID is used.

on: push

jobs:
  oidc:
    permissions:
      id-token: write
      contents: read
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Assume OIDC role
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-region: eu-west-1
          role-to-assume: arn:aws:iam::012345678912:role/github-oidc-role

Invoke AWS Actions from GitHub Actions Workflow

The last step is to invoke AWS actions from the workflow. In this case, the cdk diff command is run by adding the following step.

- name: Invoke AWS action
  run: |
    npm ci
    npx cdk diff

This results in the following .github/workflows/oidc.yml file.

on: push

jobs:
  oidc:
    permissions:
      id-token: write
      contents: read
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Assume OIDC role
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-region: eu-west-1
          role-to-assume: arn:aws:iam::012345678912:role/github-oidc-role
          
      - name: Invoke AWS action
        run: |
          npm ci
          npx cdk diff

Conclusion

Using OpenID Connect, integrating AWS with GitHub Actions is relatively simple and secure. This can be useful for deployments, testing purposes or other cases where AWS actions need to be invoked.

Resources

Melle