はじめに
AWSでBackendシステムの基盤開発を行う際、次の構成を採用してきました。
- Git: AWS CodeCommit
- IaC: AWS CDK(TypeScript)
- CI/CD: CDK Pipelines(AWS CodePipeline)
- CICDアカウントと構築対象環境アカウントを分離したクロスアカウント構成
このたび「GitHubを使い、GitHub ActionsでCI/CDを組んでほしい」という依頼を受けました。GitHub Actionsのメリットを十分に理解しないまま移行を検討すると、構成のどこが本質的に変わり、どこが変わらないのかを見誤りがちです。特に迷ったのが、GitHub ActionsからCDKのsynth/diff/deployを実行する際の権限の持たせ方でした。
本稿では、CodeCommit+CDK Pipeline方式との比較を軸に、GitHub Actions × CDKのクロスアカウント権限設計を、公式ドキュメントとAWS公式パターンの情報をもとに整理します。
対象読者
- CodeCommit+CDK Pipelineでのクロスアカウント構築に慣れており、GitHub Actionsへの移行を検討している方
- GitHub ActionsからAWSへの認証をアクセスキーではなくOIDCで行いたい方
- CDKのクロスアカウントデプロイの権限モデル(bootstrap roles)を再確認したい方
背景・課題
CodeCommit+CDK Pipeline方式では、パイプライン全体が1つのCICDアカウント内のCodePipelineとして完結し、パイプラインの各ステージ(Source→Build→Self-Mutate→各環境へのDeploy)はCodePipelineのアクション定義として組み立てます。クロスアカウントデプロイはcdk bootstrap時の--trustオプションと、CDKが自動生成するIAMロール(bootstrap roles)によって実現されていました。
GitHub Actionsへの移行にあたり、次のように整理していました。
| 変化 | 内容 |
|---|---|
| CICDアカウントの位置づけ | GitHub Actions自体はGitHub側のホスト型ランナーで動くため、CodePipelineやCodeBuildを常設するアカウントは不要になる。ただしOIDCで認証する「入口」となるIAMロールを置くアカウントは必要 |
| Pipeline/Stageの組み立て方 | CodePipelineのStage定義ではなく、GitHub Actionsのワークフロー(.github/workflows/*.yml)のjob/stepとして表現する |
| 権限の持たせ方(不明点) | cdk synth/diff/deployをGitHub Actions上でどう認証・認可するか |
補足: 「CICDアカウントが不要になる」の正確な意味 上の表の「CodePipelineやCodeBuildを常設するアカウントは不要になる」は、そこに置くAWSリソース(CodePipeline・CodeBuildなど)が不要になるという意味であり、AWSアカウントという箱自体が丸ごと不要になるわけではありません。GitHub Actionsに移行しても、OIDCの入口となるHub Roleはどこかのアカウントに置く必要があり、本稿ではそのアカウントを引き続き「CICDアカウント」と呼びます。以降に出てくる「
--trustでCICDアカウントIDを指定する」といった記述は、すべてこのHub Roleを置いているアカウントのことを指しています。新たに別のアカウントを用意する話ではないので、混同しないよう注意してください。
以降、この「権限の持たせ方」を中心に調査した内容をまとめます。
アーキテクチャ比較
現行構成: CodeCommit + CDK Pipeline(クロスアカウント)
flowchart TB subgraph CICD["CICDアカウント"] CC["CodeCommitリポジトリ"] CP["CodePipeline(CDK Pipelines / Self-Mutating)"] CC --> CP end subgraph DEV["開発環境アカウント"] DevRole["cdk-deploy-role"] DevStack["CloudFormationスタック"] DevRole --> DevStack end subgraph PROD["本番環境アカウント"] ProdRole["cdk-deploy-role"] ProdStack["CloudFormationスタック"] ProdRole --> ProdStack end CP --> DevRole CP --> ProdRole
CodePipelineはCICDアカウント内の常設リソースで、認証は「CodePipelineのサービスロールが、bootstrap時に--trustで許可されたターゲットアカウントのbootstrap rolesをsts:AssumeRoleする」形で完結します。パイプライン自体が自己書き換え(Self-Mutation)する点も特徴です。
新構成: GitHub Actions + OIDC(クロスアカウント)
flowchart TB subgraph GH["GitHub"] Repo["リポジトリ"] Workflow["GitHub Actionsワークフロー"] Repo --> Workflow end subgraph CICD2["CICDアカウント(OIDCの入口)"] OIDCP["IAM OIDCプロバイダ"] HubRole["Hub IAMロール"] OIDCP --> HubRole end subgraph DEV2["開発環境アカウント"] DevRole2["cdk-deploy-role"] end subgraph PROD2["本番環境アカウント"] ProdRole2["cdk-deploy-role"] end Workflow --> OIDCP HubRole --> DevRole2 HubRole --> ProdRole2
GitHub Actionsのランナーは常設のAWSリソースを必要とせず、代わりに「GitHubのOIDCトークンを検証してAWS認証情報を発行するIAMロール(Hub Role)」がCICDアカウントに1つ存在すれば足ります。そこから各環境アカウントのCDK bootstrap roleへsts:AssumeRoleする、いわゆるhub-and-spoke型のロールチェインが基本パターンです。
核心: GitHub ActionsでCDKを実行する際の権限設計
1. OIDC IDプロバイダの作成(CICDアカウント側)
CICDアカウントに、GitHubのOIDC発行者を信頼するIDプロバイダを1つ作成します。
- プロバイダURL:
https://token.actions.githubusercontent.com - Audience:
sts.amazonaws.com
2. Hub IAMロールの信頼ポリシー
このIDプロバイダをPrincipalとし、subクレームで対象リポジトリ・ブランチ・Environmentを絞り込みます。sub条件を絞らないと、同じGitHub Organization内の無関係なリポジトリからロールを乗っ取られるリスクがあるため、AWSもtoken.actions.githubusercontent.com:subの検証を推奨しています。
以下は、dev Environmentからのジョブだけにロール引き受けを許可する例です。ワイルドカード(environment:*のような全許可条件)は使わず、環境ごとにEnvironment名まで指定するのが安全側の書き方です。本番用には、このsub条件だけをenvironment:prodに変えた別ロール(または別Statement)を用意します。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::<CICD_ACCOUNT_ID>:oidc-provider/token.actions.githubusercontent.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
"token.actions.githubusercontent.com:sub": "repo:<ORG>/<REPO>:environment:dev"
}
}
}
]
}注意(2026年7月時点): GitHub公式Changelog(2026年4月23日)によると、2026年7月15日以降に作成されたGitHubリポジトリ(および opt-in 済みの既存リポジトリ)では、
subクレームに組織・リポジトリの永続的な数値IDが@区切りで付与されるようになりました(例:repo:octocat@123456/my-repo@456789:ref:refs/heads/main)。これは、リポジトリ名やOrganization名が再利用(削除→同名で再作成)された場合に、古い信頼ポリシーが新しい別リポジトリに誤って一致してしまうリスクを防ぐための変更です。信頼ポリシーを新規に設計する際は、この仕様変更を踏まえてsub条件を確認してください。
3. Hub Roleからターゲットアカウントへのロールチェイン
Hub RoleにアタッチするIAMポリシーで、各環境アカウントのCDK bootstrap rolesへのsts:AssumeRoleを許可します。CDK標準bootstrap(--trust)を使う場合、ターゲットアカウントには次の4つのロールが作成されます。
| ロール | 用途 |
|---|---|
cdk-hnb659fds-deploy-role-<Account>-<Region> | CloudFormationのChangeSet作成・実行を指示する。実体はCloudFormationへの司令塔で、実際のリソース作成・更新は行わない |
cdk-hnb659fds-cfn-exec-role-<Account>-<Region> | CloudFormationサービスが引き受け、実際にリソースを作成・更新・削除する実行ロール(deploy-roleがiam:PassRoleでこのロールを渡す) |
cdk-hnb659fds-file-publishing-role-<Account>-<Region> | Lambdaコード等のアセットをS3へアップロード |
cdk-hnb659fds-image-publishing-role-<Account>-<Region> | コンテナイメージをECRへプッシュ |
cdk-hnb659fds-lookup-role-<Account>-<Region> | cdk diff等でのコンテキスト参照(読み取り専用) |
GitHub Actions側(Hub Role)が直接AssumeRoleするのはdeploy-roleまでで、cfn-exec-roleはCloudFormationサービスが内部的に引き受けるため、Hub Roleの許可ポリシーにcfn-exec-roleのARNを含める必要はありません。ただし実際にリソースへ変更を加える権限を持つのはこのcfn-exec-roleなので、後述のとおり権限を絞り込む対象として重要です。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": [
"arn:aws:iam::<DEV_ACCOUNT_ID>:role/cdk-hnb659fds-deploy-role-<DEV_ACCOUNT_ID>-<REGION>",
"arn:aws:iam::<DEV_ACCOUNT_ID>:role/cdk-hnb659fds-file-publishing-role-<DEV_ACCOUNT_ID>-<REGION>",
"arn:aws:iam::<DEV_ACCOUNT_ID>:role/cdk-hnb659fds-lookup-role-<DEV_ACCOUNT_ID>-<REGION>",
"arn:aws:iam::<PROD_ACCOUNT_ID>:role/cdk-hnb659fds-deploy-role-<PROD_ACCOUNT_ID>-<REGION>",
"arn:aws:iam::<PROD_ACCOUNT_ID>:role/cdk-hnb659fds-file-publishing-role-<PROD_ACCOUNT_ID>-<REGION>",
"arn:aws:iam::<PROD_ACCOUNT_ID>:role/cdk-hnb659fds-lookup-role-<PROD_ACCOUNT_ID>-<REGION>"
]
}
]
}ターゲットアカウント側は、cdk bootstrap時に--trustでCICDアカウントID(=Hub Roleを置いているアカウントのID)を指定するだけで、上記ロール側の信頼ポリシーにCICDアカウントが自動的に追加されます。
cdk bootstrap aws://<DEV_ACCOUNT_ID>/<REGION> \
--trust <CICD_ACCOUNT_ID> \
--cloudformation-execution-policies arn:aws:iam::aws:policy/PowerUserAccess--cloudformation-execution-policiesを省略するとCDK bootstrapのデフォルトはAdministratorAccessになります。CodeCommit+CDK Pipeline方式でも同じ注意点はありましたが、GitHub Actions移行を機に、環境ごとに必要最小限のポリシーへ絞り込むことを推奨します。
4. 認証・デプロイのシーケンス
sequenceDiagram participant GA as "GitHub Actions" participant STS as "AWS STS" participant Target as "cdk-deploy-role(環境アカウント)" GA->>STS: OIDCトークンを添えてsts:AssumeRoleWithWebIdentity(Hub Roleを指定) STS->>STS: Hub Roleの信頼ポリシー(sub条件)を検証 STS-->>GA: Hub Roleの一時クレデンシャルを発行 GA->>STS: 一時クレデンシャルでsts:AssumeRole(role-chaining、Target Roleを指定) STS-->>GA: Target Roleの一時クレデンシャルを発行 GA->>Target: cdk synth / cdk diff / cdk deployを実行
一時クレデンシャルを発行するのは常にAWS STSで、Hub RoleやTarget Roleはあくまで「どの条件を満たせば、どの権限を持つ一時クレデンシャルを発行してよいか」をSTSに指示する信頼ポリシー・許可ポリシーの集合です。GitHub Actions公式のaws-actions/configure-aws-credentialsアクションを2回連続で呼び出すことで、このロールチェインを表現できます。2回目の呼び出しでrole-chaining: trueを指定するのがポイントで、これによって1回目で得た一時クレデンシャルを使って2回目のロールをAssumeします。
GitHub Actionsワークフローのサンプル
mainブランチへのpushで開発環境へデプロイし、PR時はcdk diffの結果だけを確認する構成の例です。本番へのデプロイ前には、承認者が変更内容を確認できるようcdk diffを独立ジョブとして実行してから、Environment protection ruleの承認待ちに入ります。
flowchart LR A["push / pull_request"] --> B["cdk synth(全スタックを一度だけ合成)"] B --> C["cdk diff(対象PR/ブランチ)"] C --> D{"mainブランチへのpushか?"} D -->|Yes| E["Dev環境へcdk deploy"] D -->|No| F["PRにdiff結果をコメント"] E --> I["Prod環境へcdk diff(承認前に結果を提示)"] I --> G["Environment protection ruleで承認待ち"] G --> H["Prod環境へcdk deploy"]
CDKアプリ側ではnew MyStack(app, 'MyStack-dev', { env: devEnv })/new MyStack(app, 'MyStack-prod', { env: prodEnv })のように、1回のcdk synthで環境ごとのスタックをまとめて合成しておく想定です。こうすることでsynthジョブの成果物(cdk.out)を後続ジョブがダウンロードして使い回せ、「一度synthしたテンプレートをそのままdeployする」という不変性を保てます。
以降のジョブは共通してAssumeRoleの2段構え(Hub Role→ターゲットのdeploy-role)を行うため、checkout/setup-node/npm ci/2回のconfigure-aws-credentialsという定型部分は各ジョブで重複します。重複が気になる場合は、この定型部分を再利用可能ワークフロー(reusable workflows)として切り出し、workflow_callで環境名・ロールARNだけを引数化する構成にまとめられます。
# .github/workflows/cdk-deploy.yml
name: CDK Deploy
on:
pull_request:
branches: [main]
push:
branches: [main]
permissions:
id-token: write # OIDCトークン取得に必須
contents: read
pull-requests: write # diff結果をPRにコメントする場合
env:
AWS_REGION: ap-northeast-1
CICD_HUB_ROLE_ARN: arn:aws:iam::${{ secrets.CICD_ACCOUNT_ID }}:role/github-actions-cdk-hub-role
jobs:
synth:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- run: npx cdk synth # MyStack-dev / MyStack-prod をまとめて合成
- uses: actions/upload-artifact@v4
with:
name: cdk-out
path: cdk.out
diff-dev:
needs: synth
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
name: cdk-out
path: cdk.out
- name: Assume Hub Role (CICD account)
uses: aws-actions/configure-aws-credentials@v6
with:
role-to-assume: ${{ env.CICD_HUB_ROLE_ARN }}
aws-region: ${{ env.AWS_REGION }}
- name: Assume Dev deploy role (role chaining)
uses: aws-actions/configure-aws-credentials@v6
with:
role-to-assume: arn:aws:iam::${{ secrets.DEV_ACCOUNT_ID }}:role/cdk-hnb659fds-deploy-role-${{ secrets.DEV_ACCOUNT_ID }}-${{ env.AWS_REGION }}
role-chaining: true
aws-region: ${{ env.AWS_REGION }}
- run: npx cdk diff MyStack-dev --app cdk.out
# PRへのコメント投稿(actions/github-script等)は実装省略。
# 本文の内容をそのまま貼り付けるだけでも動作確認は可能です。
deploy-dev:
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
needs: synth
runs-on: ubuntu-latest
environment: dev
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
name: cdk-out
path: cdk.out
- name: Assume Hub Role (CICD account)
uses: aws-actions/configure-aws-credentials@v6
with:
role-to-assume: ${{ env.CICD_HUB_ROLE_ARN }}
aws-region: ${{ env.AWS_REGION }}
- name: Assume Dev deploy role (role chaining)
uses: aws-actions/configure-aws-credentials@v6
with:
role-to-assume: arn:aws:iam::${{ secrets.DEV_ACCOUNT_ID }}:role/cdk-hnb659fds-deploy-role-${{ secrets.DEV_ACCOUNT_ID }}-${{ env.AWS_REGION }}
role-chaining: true
aws-region: ${{ env.AWS_REGION }}
# Dev環境は開発中の変更を素早く反映させたいため --require-approval never を許容
- run: npx cdk deploy MyStack-dev --app cdk.out --require-approval never
diff-prod:
needs: deploy-dev
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
name: cdk-out
path: cdk.out
- name: Assume Hub Role (CICD account)
uses: aws-actions/configure-aws-credentials@v6
with:
role-to-assume: ${{ env.CICD_HUB_ROLE_ARN }}
aws-region: ${{ env.AWS_REGION }}
- name: Assume Prod deploy role (role chaining)
uses: aws-actions/configure-aws-credentials@v6
with:
role-to-assume: arn:aws:iam::${{ secrets.PROD_ACCOUNT_ID }}:role/cdk-hnb659fds-deploy-role-${{ secrets.PROD_ACCOUNT_ID }}-${{ env.AWS_REGION }}
role-chaining: true
aws-region: ${{ env.AWS_REGION }}
# environment: prod を付けず、承認ゲートより前に diff をジョブサマリへ出力する
- run: npx cdk diff MyStack-prod --app cdk.out | tee -a "$GITHUB_STEP_SUMMARY"
deploy-prod:
needs: diff-prod
runs-on: ubuntu-latest
environment: prod # GitHub Environmentの承認者が diff-prod の結果を見てからレビュー
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
name: cdk-out
path: cdk.out
- name: Assume Hub Role (CICD account)
uses: aws-actions/configure-aws-credentials@v6
with:
role-to-assume: ${{ env.CICD_HUB_ROLE_ARN }}
aws-region: ${{ env.AWS_REGION }}
- name: Assume Prod deploy role (role chaining)
uses: aws-actions/configure-aws-credentials@v6
with:
role-to-assume: arn:aws:iam::${{ secrets.PROD_ACCOUNT_ID }}:role/cdk-hnb659fds-deploy-role-${{ secrets.PROD_ACCOUNT_ID }}-${{ env.AWS_REGION }}
role-chaining: true
aws-region: ${{ env.AWS_REGION }}
# 本番は require-approval broadening(IAM/SG等の権限拡大を伴う変更は再度手動確認)
- run: npx cdk deploy MyStack-prod --app cdk.out --require-approval broadeningポイントは次の4つです。
permissions.id-token: writeをワークフロー全体(または該当job)に付与しないと、OIDCトークンがそもそも発行されないaws-actions/configure-aws-credentialsを2段構えで呼び、2回目にrole-chaining: trueを付けることでHub Role→ターゲットアカウントのbootstrap roleへ多段Assumeする- 本番デプロイのjobに
environment: prodを指定し、GitHubのEnvironment承認機能で人手承認ゲートを設ける(CodePipelineの手動承認アクションに相当)。ただし承認者が変更内容を確認できるよう、environmentを付けないdiff-prodジョブで先にcdk diff結果をジョブサマリへ出しておく - 本番の
cdk deployには--require-approval neverを使わない。少なくとも--require-approval broadeningを指定し、IAM/セキュリティグループなど権限が広がる変更にはCLI側でも確認を挟む
補足: GitHub ActionsのランナーはTTYを持たない非対話環境のため、
--require-approval broadening該当の変更が含まれるcdk deployは確認プロンプトを表示できず、その場でエラー終了します。これは事故防止の観点ではむしろ望ましい挙動で、「権限が広がる変更は自動デプロイを止め、人が内容を確認してから手動で実行する」というフェイルセーフとして機能します。診断チェックを迂回するために安易にneverへ戻さないよう注意してください。
CodeCommit + CDK Pipeline との比較表
| 観点 | CodeCommit + CDK Pipeline | GitHub Actions |
|---|---|---|
| ソース管理 | CodeCommit(AWS内で完結) | GitHub(AWS外の外部SaaS) |
| パイプライン実行基盤 | CICDアカウント内のCodePipeline/CodeBuild(常設リソース) | GitHubホスト型ランナー(AWS側に常設リソース不要) |
| Stage/Pipeline定義 | CDKコード内でaddStage()等により定義(IaCそのもの) | .github/workflows/*.ymlのYAMLで定義(IaC外) |
| AWSへの認証方式 | CodePipelineサービスロール(AWS内部で完結、外部秘密情報不要) | OIDC(推奨)またはIAMユーザーの長期アクセスキー(非推奨) |
| クロスアカウント権限の土台 | cdk bootstrap --trustで生成されるbootstrap roles(共通) | 同左(bootstrap rolesの仕組み自体は同じ) |
| 権限の入口 | CICDアカウントのCodePipelineサービスロール | CICDアカウントのOIDC Hub Role |
| 自己書き換え(Self-Mutation) | CDK Pipelinesが標準で対応 | 標準機能はなし。ワークフローYAML変更も次回実行時に自動反映されるが、CDK Pipelines特有の「Self-Mutateステージ」の概念はない |
| 承認ゲート | CodePipelineの手動承認アクション | GitHub Environmentのrequired reviewers |
| 変更差分の可視化 | CodePipelineコンソール/CloudWatch Logs | PRコメント(cdk diff結果をpost)やGitHub Actionsのログ |
| シークレット管理 | 基本不要(IAMロールで完結) | OIDCなら基本不要。ただしSecretsストア(GitHub Secrets)の運用が別途発生 |
| 監査ログ | AWS CloudTrail中心 | AWS CloudTrail+GitHub Actionsの実行ログ(2系統になる) |
| 課金体系 | CodeBuildのビルド時間課金+CodePipelineのパイプライン課金 | GitHubプランごとの月間無料分数+超過分のランナー時間課金(Private repoの場合)。常設リソースは無い一方、実行分数に応じた課金構造は同様に発生する |
比較して分かるのは、クロスアカウントの権限モデルの根幹(cdk bootstrap --trustとbootstrap roles)はどちらの方式でも変わらないという点です。変わるのは「その手前の、CICDアカウントに最初に入る認証方式」で、CodePipelineのサービスロールがOIDC Hub Roleに置き換わる、というのが本質的な差分です。
ベストプラクティス・注意点
sub条件は環境・ブランチ単位で絞り込む:repo:<ORG>/<REPO>:environment:prodのようにEnvironment単位で条件を絞ると、mainブランチ以外からの本番ロールAssumeを防げます。ワイルドカードで複数環境をまとめて許可しない。cfn-exec-roleにAdministratorAccessを使い続けない: CDK bootstrapのデフォルトはAdministratorAccessです。GitHub Actions移行のタイミングで、環境ごとに--cloudformation-execution-policiesを見直すとよいでしょう。本稿のサンプルで使ったPowerUserAccessもIAM操作を含む広い管理ポリシーなので、あくまで移行時の暫定値として扱い、最終的にはスタックが実際に使うサービスへ絞ったカスタム管理ポリシーに置き換えることを推奨します。- Hub Roleは1つに集約し、ターゲット側のロールで権限を絞る: Hub Role自体に強い権限を持たせず、「各環境のbootstrap roleをAssumeできる」権限だけに限定します。ただしHub Roleの許可ポリシーでdev/prod双方へのAssumeRoleを許可している場合、GitHub Environmentの承認ゲートはワークフローの実行順序を止めているだけで、IAM層で本番ロールへのAssumeを強制的にブロックしているわけではない点に注意してください。Hub Role自体のクレデンシャルが漏えいすれば、承認ゲートを経由せずにprod用deploy-roleへ到達できてしまいます。より厳密に分離したい場合は、環境ごとにHub Roleを分ける、またはHub Roleの許可ポリシーもEnvironmentごとの条件で絞る構成を検討してください。
- role chainingはセッション最大1時間に制限される: AWSの公式ナレッジセンターにある通り、role chaining(一時クレデンシャルを使ってさらに別ロールをAssumeRoleする操作)で得られるセッションは、対象ロールの
MaxSessionDuration設定によらず最大1時間に固定されます。大規模スタックのデプロイや長時間の待機を伴う変更セットがこの上限に達するとAssumeRoleの再実行が必要になるため、長時間デプロイが想定される場合は考慮してください。 - サードパーティActionsはコミットSHAで固定する:
aws-actions/configure-aws-credentials@v6のようなメジャータグ固定は、タグの再アタッチ(サプライチェーン攻撃)に対して脆弱です。AWS認証情報を扱うステップは特に、@<40桁のコミットSHA>で固定することを検討してください。 cdk-pipelines-githubという選択肢もある: CDK Pipelinesの記法(addStage()等)を維持しつつ、GitHub Actionsのワークフローファイルをcdk synth時に自動生成するcdklabs製の構築library(cdk-pipelines-github)も存在します。GitHubActionRoleコンストラクトでOIDC用ロールをCDKコードとして定義できるため、既存のCDK Pipelinesコードからの移行コストを抑えたい場合の選択肢になります。- 注意:
cdk-pipelines-githubを使っても「CICDアカウント」に相当する存在は不要になりません。Pipeline(GitHubWorkflow)のawsCreds(=GitHubActionRoleの置き場所)はパイプライン全体で1つだけ指定する設計で、内部的には素のCDK Pipelines(CodePipelineベース)と同じクロスアカウント方式(bootstrap--trustによるAssumeRole)を再利用しています。複数環境アカウントへデプロイする場合、ターゲット側はcdk bootstrap aws://<TARGET_ACCOUNT_ID>/<REGION> --trust <GitHubActionRoleのあるアカウントID>で信頼関係を張る必要があります(cdk-github-actions-sample)。「常設のCodePipeline/CodeBuildが不要になる」点は変わりませんが、「クロスアカウントの入口となる1アカウント」自体は本稿のHub Role構成と同様に必要です。
- 注意:
- アカウント数が多い組織ではロールARNの列挙が煩雑になる: 本稿のサンプルはdev/prodの2アカウントを前提にAssumeRole先を列挙していますが、環境アカウントが10・20と増える組織では、許可ポリシーへのARN追記が運用負担になります。アカウントIDの命名規則を揃えて
arn:aws:iam::*:role/cdk-hnb659fds-deploy-role-*のようなワイルドカードで束ねる、またはAWS Organizationsのタグ条件(aws:PrincipalOrgID等)と組み合わせて動的に制御する、といった設計を検討してください。 - 監査ログが2系統になる点を運用に組み込む: CloudTrailだけでなく、GitHub Actionsの実行履歴・Environmentの承認履歴も、監査対象として運用ドキュメントに含めておくと安心です。
まとめ
- クロスアカウントCDKデプロイの土台である「
cdk bootstrap --trustとbootstrap roles」は、CodeCommit+CDK PipelineでもGitHub Actionsでも共通の仕組みである - 変わるのは「CICDアカウントへの最初の入口」で、CodePipelineのサービスロールがGitHub OIDCを信頼するHub IAMロールに置き換わる
- GitHub Actions側は
permissions.id-token: writeとaws-actions/configure-aws-credentialsのrole-chaining: trueを組み合わせることで、Hub Role→ターゲット環境のcdk-deploy-roleという多段Assumeを表現できる - Stage/Pipelineの組み立てはCDKコードからワークフローYAMLへ、承認ゲートはCodePipelineの手動承認からGitHub Environmentへ、それぞれ移る
subクレームの絞り込みやcfn-exec-roleの最小権限化など、IAM信頼ポリシー周りの見直しは移行の良い機会になる
参考資料
- Configuring OpenID Connect in Amazon Web Services - GitHub Docs
- aws-actions/configure-aws-credentials
- Optimize multi-account serverless deployments by using the AWS CDK and GitHub Actions workflows - AWS Prescriptive Guidance
- aws-cdk-lib.pipelines module - AWS CDK API Reference
- cdklabs/cdk-pipelines-github
- AWS CDK Bootstrapping - AWS CDK Developer Guide
- Immutable subject claims for GitHub Actions OIDC tokens - GitHub Changelog
- Increase the IAM role chaining session duration - AWS re:Post Knowledge Center
- evandiewald/cdk-github-actions-sample