Skip to main content

AWS CDK construct to create OIDC roles for CircleCI jobs

Project description

@blimmer/cdk-github-oidc

A CDK construct library that enables secure authentication between GitHub Actions and AWS using OpenID Connect (OIDC). This eliminates the need for long-lived AWS credentials in your GitHub repositories.

What is OIDC?

OIDC (OpenID Connect) allows GitHub Actions to authenticate directly with AWS using short-lived tokens instead of storing AWS credentials. The process is described in GitHub's documentation.

Security Benefits

Using OIDC for GitHub Actions authentication:

  • Eliminates the need to store AWS credentials as GitHub secrets
  • Provides short-lived, automatically rotated credentials
  • Enables fine-grained access control based on repository, branch, environment, or other conditions
  • Follows security best practices for cloud access

Installation

Node.js

npm install --save @blimmer/cdk-github-oidc

or

yarn add @blimmer/cdk-github-oidc

Python

pip install cdk-github-oidc

For Python, see below.

Create or Import a Provider

Each AWS account must be bootstrapped with a single OIDC provider.

To create it in your stack, use the GithubActionsIdentityProvider construct.

import { GithubActionsIdentityProvider } from "@blimmer/cdk-github-oidc";

export class MyStack extends Stack {
  constructor(scope: Construct, id: string, props: StackProps) {
    super(scope, id, props);

    const provider = new GithubActionsIdentityProvider(this, "Provider");
  }
}

Or, if another stack created the provider, you can import it using the GithubActionsIdentityProvider.fromAccount() method.

import { GithubActionsIdentityProvider } from "@blimmer/cdk-github-oidc";

export class MyStack extends Stack {
  constructor(scope: Construct, id: string, props: StackProps) {
    super(scope, id, props);

    const provider = GithubActionsIdentityProvider.fromAccount(this);
  }
}

Create a Role

Once you have a handle to a provider, you can create a role assumed by GitHub Actions. You grant this role permission to access the resources/APIs you need (more on that below).

import { GithubActionsRole, GithubActionsIdentityProvider, BranchFilter } from "@blimmer/cdk-github-oidc";

export class MyStack extends Stack {
  constructor(scope: Construct, id: string, props: StackProps) {
    super(scope, id, props);

    const provider = new GithubActionsIdentityProvider(this, "Provider");

    const role = new GithubActionsRole(this, "Role", {
      provider,
      roleName: "my-github-actions-role",
      description: "Role assumed by GitHub Actions",
      subjectFilters: [new BranchFilter({ owner: "blimmer", repository: "cdk-github-oidc", branch: "*" })],
    });
  }
}

Subject Filters

You must pass one or more SubjectFilters to the GithubActionsRole construct. These filters are used to determine which GitHub Actions workflows can assume the role.

This construct exposes first class support for the following filters:

  • AllowAllFilter

    // Allow all branches, tags, environments, pull requests, etc.
    new AllowAllFilter({
      owner: "blimmer",
      repository: "cdk-github-oidc",
    });
    
  • BranchFilter

    // Allow all branches
    new BranchFilter({
      owner: "blimmer",
      repository: "cdk-github-oidc",
      branch: "*",
    });
    
    // Specify a branch
    new BranchFilter({
      owner: "blimmer",
      repository: "cdk-github-oidc",
      branch: "main",
    });
    
    // Specify a branch pattern
    new BranchFilter({
      owner: "blimmer",
      repository: "cdk-github-oidc",
      branch: "feature/*",
    });
    
  • TagFilter

    // Allow all tags
    new TagFilter({
      owner: "blimmer",
      repository: "cdk-github-oidc",
      tag: "*",
    });
    
    // Specify a tag
    new TagFilter({
      owner: "blimmer",
      repository: "cdk-github-oidc",
      tag: "v1.0.0",
    });
    
    // Specify a tag pattern
    new TagFilter({
      owner: "blimmer",
      repository: "cdk-github-oidc",
      tag: "v1.*",
    });
    
  • EnvironmentFilter

    // Allow all environments
    new EnvironmentFilter({
      owner: "blimmer",
      repository: "cdk-github-oidc",
      environment: "*",
    });
    
    // Specify an environment
    new EnvironmentFilter({
      owner: "blimmer",
      repository: "cdk-github-oidc",
      environment: "staging",
    });
    
  • PullRequestFilter

    // Allow all pull requests
    new PullRequestFilter({
      owner: "blimmer",
      repository: "cdk-github-oidc",
    });
    

If none of these filters fit your use case, you can implement your own via the IGithubActionOidcFilter interface, or use the CustomFilter construct.

You can learn more about subject filters in the Github docs

Granting Permissions to the Role

The GithubActionsRole construct is a Role construct, so you can use all of the same properties and methods as you would with a normal CDK IAM Role construct.

import { GithubActionsRole, GithubActionsIdentityProvider, BranchFilter } from "@blimmer/cdk-github-oidc";
import { Bucket } from "aws-cdk-lib/aws-s3";
import { PolicyStatement } from "aws-cdk-lib/aws-iam";

export class MyStack extends Stack {
  constructor(scope: Construct, id: string, props: StackProps) {
    super(scope, id, props);

    const bucket = new Bucket(this, "Bucket");

    const provider = new GithubActionsIdentityProvider(this, "Provider");
    const role = new GithubActionsRole(this, "Role", {
      provider,
      roleName: "my-github-actions-role",
      description: "Role assumed by GitHub Actions",
      subjectFilters: [
        new BranchFilter({
          owner: "blimmer",
          repository: "cdk-github-oidc",
          branch: "*",
        }),
      ],
    });

    // Grant access via CDK `grant*` methods
    // https://docs.aws.amazon.com/cdk/v2/guide/permissions.html#permissions_grants
    role.grantReadWrite(bucket);

    // Add a custom policy
    role.addToPolicy(
      new PolicyStatement({
        actions: ["s3:PutObject"],
        resources: ["arn:aws:s3:::my-bucket/*"],
      }),
    );
  }
}

Using a Role in a Workflow

To use a role in a GitHub Actions workflow, you can use the aws-actions/configure-aws-credentials action.

jobs:
  deploy:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      id-token: write # Required for OIDC role assumption
    steps:
      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/my-github-actions-role
          region: us-west-2

See the aws-actions/configure-aws-credentials docs for more details.

Usage

For detailed API docs, see API.md.

Troubleshooting

Common Issues

  1. Role assumption fails: Ensure your GitHub Action has the required permissions:
permissions:
  id-token: write # Required for OIDC
  contents: read # Required for checking out code
  1. Provider already exists: Only one OIDC provider can exist per AWS account. Use GithubActionsIdentityProvider.fromAccount() if one already exists.
  2. Subject filter not matching: Double check your subject filter configuration matches your GitHub workflow context. Use logging to debug the actual subject string being provided.

Migrating from aws-cdk-github-oidc

This package was inspired by aws-cdk-github-oidc, but that package became unmaintained.

For a role that looked like this in aws-cdk-github-oidc:

import { GithubActionsIdentityProvider, GithubActionsRole } from "aws-cdk-github-oidc";

const provider = new GithubActionsIdentityProvider(scope, "GithubProvider");
const deployRole = new GithubActionsRole(scope, "DeployRole", {
  provider,
  owner: "octo-org",
  repo: "octo-repo",
  roleName: "MyDeployRole",
  description: "This role deploys stuff to AWS",
  maxSessionDuration: cdk.Duration.hours(2),
});

The equivalent role in this package looks like this:

import { GithubActionsIdentityProvider, GithubActionsRole, AllowAllFilter } from "@blimmer/cdk-github-oidc";

const provider = new GithubActionsIdentityProvider(scope, "GithubProvider");
const deployRole = new GithubActionsRole(scope, "DeployRole", {
  provider,
  roleName: "MyDeployRole",
  description: "This role deploys stuff to AWS",
  subjectFilters: [
    // I encourage you to scope this down to a different filter (e.g., BranchFilter, TagFilter, PullRequestFilter, etc.)
    new AllowAllFilter({ owner: "octo-org", repository: "octo-repo" }),
  ],
  maxSessionDuration: cdk.Duration.hours(2),
});

Resource Replacement

By default, CloudFormation will create resources before destroying the old ones. This is a problem when transitioning between aws-cdk-github-oidc and @blimmer/cdk-github-oidc because the GithubActionsIdentityProvider is a singleton. It might also affect your roles, if you specified a roleName.

To work around this issue, delete the old provider and role(s) before migrating to use this package. Note that this will make the role unavailable for a few minutes while things are recreated

Resources

Contributing

Contributions, issues, and feedback are welcome!

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cdk_github_oidc-1.1.0.tar.gz (74.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cdk_github_oidc-1.1.0-py3-none-any.whl (72.4 kB view details)

Uploaded Python 3

File details

Details for the file cdk_github_oidc-1.1.0.tar.gz.

File metadata

  • Download URL: cdk_github_oidc-1.1.0.tar.gz
  • Upload date:
  • Size: 74.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for cdk_github_oidc-1.1.0.tar.gz
Algorithm Hash digest
SHA256 42b83e2a60135ff5fb96b408e3c9dec944904d71bbf84914ed064361b4b30372
MD5 904d2bd7f605281b74003b27152db5a2
BLAKE2b-256 e9702aae79aa20321512ea46a3dfa05a3712d273122712e2a1cba1e2da4fa485

See more details on using hashes here.

Provenance

The following attestation bundles were made for cdk_github_oidc-1.1.0.tar.gz:

Publisher: release.yml on blimmer/cdk-github-oidc

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file cdk_github_oidc-1.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for cdk_github_oidc-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 4e27f9c0823b694a16300608d7c915c88f1f62362a42373b3fd22912288681b7
MD5 43cd5520d09451c924cb91636c723afe
BLAKE2b-256 9e7757b9a6dd6d8b1243c16e1a87f4a75a656209df69d472bc91693edd2c7f05

See more details on using hashes here.

Provenance

The following attestation bundles were made for cdk_github_oidc-1.1.0-py3-none-any.whl:

Publisher: release.yml on blimmer/cdk-github-oidc

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page