@blimmer/cdk-github-oidc

中文文档
1.2.0发布于 2026/07/28Apache-2.0TypeScriptCommonJS零依赖构建来源已验证近 30 天下载 2819

AWS CDK construct to create OIDC roles for CircleCI jobs

原始使用文档
文档目录17 节
  1. What is OIDC?
  2. Installation
  3. Node.js
  4. Python
  5. Usage
  6. Create or Import a Provider
  7. Create a Role
  8. Subject Filters
  9. Immutable Subject Claims
  10. Granting Permissions to the Role
  11. Using a Role in a Workflow
  12. Troubleshooting
  13. Common Issues
  14. Migrating from aws-cdk-github-oidc
  15. Resource Replacement
  16. Resources
  17. Contributing

@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.

Why use OIDC instead of access keys?
  • 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

Usage

The examples below are TypeScript. For the full API in every supported language, see API.md.

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",
          ownerId: "630449",
          repository: "cdk-github-oidc",
          repositoryId: "919628491",
          branch: "*",
        }),
      ],
    });
  }
}

ownerId and repositoryId opt into GitHub's immutable subject claims, the default for repositories created after July 15, 2026. Omit both if your repository predates that.

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. The examples omit ownerId and repositoryId to keep the focus on what each filter does; add them as shown above if your repository uses immutable subject claims.

  • 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.

When writing your own, build the subject from the protected repositoryClaim getter rather than from owner and repository directly. It renders whichever repo: prefix the filter was configured for, so your filter keeps working if the repository moves to immutable subject claims.

class DeploymentFilter extends IGithubActionOidcFilter {
  public toSubject(): string {
    return `${this.repositoryClaim}:deployment`;
  }
}

You can learn more about subject filters in the Github docs

Immutable Subject Claims

GitHub is moving to an immutable subject claim format that embeds numeric owner and repository IDs:

repo:blimmer/cdk-github-oidc:ref:refs/heads/main                   # previous
repo:blimmer@630449/cdk-github-oidc@919628491:ref:refs/heads/main  # immutable

Repositories created after July 15, 2026 use the immutable format, as do repositories renamed or transferred after that date. Everything else keeps the previous format until you opt in, per repo or per org, in the OIDC settings UI or the REST API. A repository emits one format or the other, never both.

Pass ownerId and repositoryId to any filter to get the immutable format:

new BranchFilter({
  owner: "blimmer",
  ownerId: "630449",
  repository: "cdk-github-oidc",
  repositoryId: "919628491",
  branch: "main",
});

Leave them off and you get the previous format, which is what the subject filter examples above do.

Finding the IDs

gh api repos/OWNER/REPO --jq '{ownerId: .owner.id, repositoryId: .id}'

To check which format a repository emits right now, read sub_claim_prefix:

gh api repos/OWNER/REPO/actions/oidc/customization/sub
# {"use_default":true,"use_immutable_subject":false,"sub_claim_prefix":"repo:blimmer/cdk-github-oidc"}

The same setting lives at https://github.com/OWNER/REPO/settings/actions/oidc-configuration.

Migration Prompt

If you have more than a couple of filters, hand this to your coding agent.

Show the prompt
Upgrade `@blimmer/cdk-github-oidc` to the latest version, then audit this CDK app for GitHub's immutable OIDC
subject claim format.

Background: GitHub embeds numeric owner and repository IDs in the OIDC `sub` claim
(`repo:owner@123/repo@456:ref:refs/heads/main` instead of `repo:owner/repo:ref:refs/heads/main`). Repositories
created, renamed, or transferred after July 15, 2026 use it automatically. Older repositories keep the previous
format until someone opts in. A repository emits one format or the other, never both, so a trust policy built for
the wrong format fails with `Not authorized to perform sts:AssumeRoleWithWebIdentity`.

For every subject filter passed to a `GithubActionsRole` in this app:

1. Run `gh api repos/<owner>/<repository>/actions/oidc/customization/sub` and read `use_immutable_subject`.
2. If it is `false`, leave the filter alone. It is already correct.
3. If it is `true`, run `gh api repos/<owner>/<repository> --jq '{ownerId: .owner.id, repositoryId: .id}'` and add
   both values to that filter as `ownerId` and `repositoryId` (strings, not numbers). Keep `owner` and
   `repository` as the plain names.

Then find every class in this app that extends `IGithubActionOidcFilter`. If its `toSubject()` builds the subject
from `this.owner` and `this.repository`, rewrite it to use the `this.repositoryClaim` getter instead, leaving the
rest of the subject unchanged. Custom filters that skip this keep emitting the previous format no matter which IDs
are passed to them.

Report any repository the `gh` calls fail for rather than guessing its IDs, since a wrong ID produces a role nobody
can assume. Do not add, remove, or re-scope any filter, and do not change anything beyond the filter arguments and
the custom filter subject construction.

Switching an Existing Repository

Add a second filter carrying the IDs, deploy, opt in on GitHub, then delete the original filter. The role trusts both subjects in between, so nothing breaks mid-switch.

subjectFilters: [
  new BranchFilter({ owner: "blimmer", repository: "cdk-github-oidc", branch: "main" }),
  new BranchFilter({
    owner: "blimmer",
    ownerId: "630449",
    repository: "cdk-github-oidc",
    repositoryId: "919628491",
    branch: "main",
  }),
];

Double-check the IDs. A wrong one produces a subject that never matches, and the only symptom is Not authorized to perform sts:AssumeRoleWithWebIdentity.

Don't reach for a wildcard like blimmer@* to avoid looking them up. That trusts every account named blimmer, including whoever claims the name if the current owner renames or deletes it. Preventing exactly that is why the IDs exist.

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.

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
    
  2. Provider already exists: Only one OIDC provider can exist per AWS account. Use GithubActionsIdentityProvider.fromAccount() if one already exists.

  3. 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.

  4. Role assumption breaks after a repo is created, renamed, or transferred: the repository probably switched to immutable subject claims. Run gh api repos/OWNER/REPO/actions/oidc/customization/sub to see which format it emits, and pass ownerId and repositoryId to your filters if use_immutable_subject is true. CloudTrail shows the subject that was actually presented.

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!

版本与发布记录

@blimmer/cdk-github-oidc 共发布 5 个版本,首次发布于 2025/01/24;过去 12 个月发布了 1 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
1.2.0latest2026/07/283 个月前
1.1.02025/08/311.2 年前
1.0.02025/01/261.8 年前
0.0.12025/01/251.8 年前
0.0.02025/01/241.8 年前

关于 @blimmer/cdk-github-oidc 的常见问题

@blimmer/cdk-github-oidc 是什么?

AWS CDK construct to create OIDC roles for CircleCI jobs

如何安装 @blimmer/cdk-github-oidc?

在项目目录运行 npm install @blimmer/cdk-github-oidc,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:aws-cdk-lib(^2.73.0)、constructs(^10.5.1)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@blimmer/cdk-github-oidc 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@blimmer/cdk-github-oidc 支持 ESM 还是 CommonJS?

以 CommonJS 形式发布,可以直接 require();在 ES Module 项目中也可以用 import 引入(Node.js 会把 module.exports 作为默认导出)。

@blimmer/cdk-github-oidc 可以商用吗?

@blimmer/cdk-github-oidc 使用 Apache-2.0 许可。宽松许可:允许商业使用、修改和再分发,并附带明确的专利授权;分发时需保留许可与 NOTICE 文件,修改过的文件要注明改动。以上为概括,不构成法律意见,请以许可原文为准。

@blimmer/cdk-github-oidc 的下载量有多少?

根据 npm 官方下载统计,@blimmer/cdk-github-oidc 在 2026/10/09 – 2026/11/07 这 30 天内被下载 2,819 次,日均约 94 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@blimmer/cdk-github-oidc 还在维护吗?

最新版本 1.2.0 发布于 2026/07/28(3 个月前);至今共发布 5 个版本,其中过去 12 个月发布了 1 个;首次发布于 2025/01/24。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。