2026/05/08

テクノロジー

AWS CDK bootstrap とクロスアカウントデプロイ

この記事の目次

    はじめに

    AWS CDK(Cloud Development Kit)を使って、異なるAWSアカウント間(クロスアカウント)でリソースをデプロイする方法を解説します。

    • 対象読者:AWSちょっとわかるレベル
    • 所要時間:約60〜90分
    • 実行環境:Windows PowerShell

    このハンズオンで学べること

    • CDKプロジェクトの初期化とスタック構成
    • cdk bootstrap の仕組みと役割
    • クロスアカウントデプロイに必要なIAM設定
    • --cloudformation-execution-policies による最小権限の実現
    • cdk destroy を使ったリソースの後片付け

    アカウント構成

    本ハンズオンでは2つのAWSアカウントを使用します。

    事前準備

    必要なツール

    • Node.js(v18以上推奨)
    • AWS CDK CLI(npm install -g aws-cdk
    • AWS CLI v2
    • PowerShell

    AWSプロファイルの設定

    本ハンズオンでは以下の2つのプロファイルを使用します。

    プロファイル名対象アカウント用途
    test-111111111111アカウントA(111111111111)デプロイ先の操作
    test-AアカウントB(222222222222)のIAMユーザーCDKデプロイの実行元

    ~/.aws/credentials および ~/.aws/config に各プロファイルを設定しておいてください。

    Step 1:CDKプロジェクトの作成

    プロジェクトディレクトリの作成

    mkdir C:\github\cdk-cross
    cd C:\github\cdk-cross

    CDKアプリの初期化

    cdk init app --language typescript

    実行すると以下のようなプロジェクト構成が生成されます。

    cdk-cross/
    ├── bin/
    │   └── cdk-cross.ts      # エントリーポイント
    ├── lib/
    │   └── cdk-cross-stack.ts # スタック定義
    ├── cdk.json              # CDK設定ファイル
    └── package.json

    Notegit config の設定がない場合、Unable to initialize git repository という警告が出ますが、ハンズオンの進行には影響ありません。

    Step 2:スタックの実装

    エントリーポイントの編集

    bin/cdk-cross.ts を以下のように編集します。デプロイ先のアカウントIDとリージョンを明示的に指定します。

    import * as cdk from 'aws-cdk-lib';
    import { CdkCrossStack } from '../lib/cdk-cross-stack';
    
    const app = new cdk.App();
    
    new CdkCrossStack(app, 'CdkCrossStack', {
      env: {
        account: "111111111111",  <em>// デプロイ先アカウントA</em>
        region: "ap-northeast-1"
      }
    });

    ポイント:クロスアカウントデプロイでは env の account と region を必ず明示する必要があります。省略すると CDK が環境を解決できずエラーになります。

    スタック定義の編集

    lib/cdk-cross-stack.ts を以下のように編集します。今回はシンプルなS3バケットを1つ作成します。

    import * as cdk from 'aws-cdk-lib';
    import { Bucket } from 'aws-cdk-lib/aws-s3';
    
    export class CdkCrossStack extends cdk.Stack {
      constructor(scope: Construct, id: string, props?: cdk.StackProps) {
        super(scope, id, props);
    
        new Bucket(this, 'TestBucket', {
          removalPolicy: cdk.RemovalPolicy.DESTROY,
          autoDeleteObjects: true
        });
      }
    }
    • removalPolicy: DESTROYcdk destroy 実行時にバケットを削除する設定
    • autoDeleteObjects: true:バケット内にオブジェクトが残っていても削除できるようにする設定(ハンズオン向けの設定です。本番環境では慎重に検討してください)

    CloudFormationテンプレートの確認

    実際にデプロイする前に、CDKが生成するCloudFormationテンプレートを確認しましょう。

    cdk synth

    S3バケット・バケットポリシー・Lambda関数(autoDeleteObjects用)・IAMロールが出力されれば成功です。

    Step 3:bootstrap(1回目)

    bootstrapとは

    CDKでデプロイを行うには、事前に対象アカウント・リージョンにCDKToolkitというCloudFormationスタックを作成する必要があります。これを cdk bootstrap と呼びます。

    bootstrapのメリット

    • デプロイの自動化:アセット(Lambda ZIPやDockerイメージ)のアップロード先(S3・ECR)が自動で用意されるため、手動でバケットやリポジトリを作成する必要がない
    • IAMロールの一元管理:デプロイに必要なIAMロールがまとめて作成・管理されるため、個別にロールを設定する手間が省ける
    • クロスアカウント対応--trust オプションで他アカウントからのデプロイを安全に許可できる
    • 権限の最小化--cloudformation-execution-policies でCloudFormationが使う権限を絞り込める
    • 冪等性(何度実行しても同じ結果になる性質):すでにbootstrap済みの環境に再実行しても、差分のみUpdateとして適用されるため安全に再実行できる

    bootstrapはアカウントとリージョンに紐づく

    bootstrapは 「AWSアカウント × リージョン」の組み合わせごとに1回実行する必要があります。

    • アカウントAの ap-northeast-1 にデプロイ → aws://111111111111/ap-northeast-1 にbootstrap
    • アカウントAの us-east-1 にもデプロイしたい → aws://111111111111/us-east-1 に別途bootstrap
    • アカウントBの ap-northeast-1 にもデプロイしたい → aws://222222222222/ap-northeast-1 に別途bootstrap
      同じアカウントでもリージョンが異なれば別のbootstrapが必要です。

    bootstrapで作成されるリソース

    bootstrapによって以下のリソースが作成されます。

    • S3バケット(StagingBucket):デプロイ用アセットの保存場所
    • ECRリポジトリ:Dockerイメージのアセット保存場所
    • IAMロール群:CDKがデプロイ操作を行うための各種ロール
      • DeploymentActionRole:デプロイ操作を担うロール
      • CloudFormationExecutionRole:CloudFormationがリソースを作成する際に使うロール
      • FilePublishingRole / ImagePublishingRole:アセットをS3/ECRにアップロードするロール
      • LookupRole:コンテキスト情報の参照に使うロール

    組織のIAMポリシー制限がある場合

    組織(AWS Organizations)のSCP(Service Control Policy)やセキュリティポリシーによって、各種リソースの作成が制限されている環境では、bootstrapをそのまま実行できないケースがあります。

    その場合は以下のいずれかの対応を取ります。

    • 既存のbootstrap済み環境を使う:組織の管理者がすでにCDKToolkitをセットアップしている場合は、そのまま利用する(追加のbootstrapは不要)
    • 別途ロールを手動作成して利用する:セキュリティチームが承認した最小権限のIAMロールを事前に作成し、--role-arn オプションでCDKに指定する
    cdk deploy `
      --role-arn arn:aws:iam::111111111111:role/MyCustomDeployRole `
      --profile test-111111111111

    アカウントAにbootstrapを実行(1回目)

    確認ポイント:デプロイ先アカウントにすでに CDKToolkit という名前のCloudFormationスタックが存在する場合は、bootstrapは実行済みです。その場合は本Stepをスキップしてください。

    まずはシンプルにアカウントAへbootstrapします。

    cdk bootstrap aws://111111111111/ap-northeast-1 `
      --profile test-111111111111

    成功すると ✅ Environment aws://111111111111/ap-northeast-1 bootstrapped. と表示されます。

    Step 4:アカウントAへのデプロイ(同一アカウント)

    まず、アカウントAのプロファイルで直接デプロイできることを確認します。

    cdk deploy --profile test-111111111111

    IAMの変更内容が表示されるので確認し、y を入力します。

    Do you wish to deploy these changes (y/n)? y

    ✅ CdkCrossStack と表示されればデプロイ成功です。

    Step 5:クロスアカウントデプロイの試行(失敗)

    次に、アカウントB(test-A プロファイル)からデプロイを試みます。

    cdk deploy --profile test-A

    以下のエラーが発生します。

    Could not assume role in target account using current credentials
    (which are for account 222222222222)
    User: arn:aws:iam::222222222222:user/test1 is not authorized to perform:
    sts:AssumeRole on resource:
    arn:aws:iam::111111111111:role/cdk-hnb659fds-deploy-role-111111111111-ap-northeast-1

    Note:エラーメッセージ中の cdk-hnb659fds はCDK bootstrapが生成するデフォルトのqualifier(識別子)です。
    cdk bootstrap --qualifier <任意の値> で変更可能なため、組織の設定によっては異なる文字列になる場合があります。
    本ハンズオンではデフォルト値(hnb659fds)を使用します。

    なぜ失敗するのか

    CDKのクロスアカウントデプロイでは、操作元アカウントBのユーザーが、デプロイ先アカウントAの DeploymentActionRole を AssumeRole(一時的に引き受ける) することでデプロイを行います。

    しかし現時点では、

    1. アカウントAの DeploymentActionRole がアカウントBからのAssumeRoleを許可していない
    2. アカウントBの test1 ユーザーが sts:AssumeRole を実行する権限を持っていない

    この2つを解決する必要があります。

    Step 6:最小権限ポリシーの作成

    --cloudformation-execution-policies とは

    cdk bootstrap の --cloudformation-execution-policies オプションは、CloudFormationがリソースを作成・更新・削除する際に使用するIAMポリシーを指定するものです。

    デフォルト(AdministratorAccess)の問題点

    指定しない場合は AdministratorAccess(全権限)が使われます。これには以下のリスクがあります。

    • CDKスタックのコードに誤りがあった場合、意図しないリソースを削除・変更してしまう可能性がある
    • 最小権限の原則(Principle of Least Privilege)に反する
    • 組織のセキュリティポリシーに違反するケースがある

    最小権限ポリシーを使うべき理由

    • CloudFormationが操作できるリソースをスタックで必要なものだけに限定できる
    • 万が一のミスや不正アクセス時の被害範囲を最小化できる
    • 組織のコンプライアンス要件を満たしやすくなる

    今回のスタックで必要な権限は以下の3つです。

    • S3:バケットの作成・削除・ポリシー設定
    • IAM:Lambda実行ロールの作成・削除・ポリシーアタッチ
    • Lambda:autoDeleteObjects用Lambda関数の作成・削除

    ポリシーJSONの作成

    @"
    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Action": ["s3:*"],
          "Resource": "*"
        },
        {
          "Effect": "Allow",
          "Action": [
            "iam:PassRole",
            "iam:CreateRole",
            "iam:DeleteRole",
            "iam:AttachRolePolicy",
            "iam:DetachRolePolicy"
          ],
          "Resource": "*"
        },
        {
          "Effect": "Allow",
          "Action": ["lambda:*"],
          "Resource": "*"
        }
      ]
    }
    "@ | Set-Content cdk-minimal-policy.json

    ポリシーをアカウントAに作成

    aws iam create-policy `
      --policy-name CdkMinimalPolicy `
      --policy-document file://cdk-minimal-policy.json `
      --profile test-111111111111

    作成されたポリシーのARN(arn:aws:iam::111111111111:policy/CdkMinimalPolicy)を控えておきます。

    Step 7:bootstrap(2回目)―クロスアカウント対応

    なぜ2回bootstrapするのか

    1回目のbootstrapは「CDKToolkitを作成する」ための最低限の実行でした。この時点では:

    • --trust 未指定 → アカウントBからのAssumeRoleが許可されていない
    • --cloudformation-execution-policies 未指定 → AdministratorAccess が使われている

    2回目のbootstrapでは、これらを正しく設定し直します。CDKToolkitスタックはUpdateとして適用されるため、既存リソースを削除せずに設定を変更できます。

    Tips:最初からクロスアカウントデプロイを想定している場合は、1回目のbootstrapから --trust と --cloudformation-execution-policies を指定することで、2回に分ける必要はありません。

    クロスアカウント対応のbootstrapを実行

    cdk bootstrap aws://111111111111/ap-northeast-1 `
      --profile test-111111111111 `
      --trust 222222222222 `
      --cloudformation-execution-policies arn:aws:iam::111111111111:policy/CdkMinimalPolicy

    各オプションの意味:

    オプション意味
    --trust 222222222222アカウントB(222222222222)からのAssumeRoleを許可する
    --cloudformation-execution-policiesCloudFormationが使うIAMポリシーをAdministratorAccessから最小権限に変更する

    ✅ Environment aws://111111111111/ap-northeast-1 bootstrapped. と表示されれば成功です。

    補足:bootstrap再実行によって CloudFormationExecutionRole に紐づくポリシーが AdministratorAccess から CdkMinimalPolicy に切り替わります。
    ただし、Step 4でデプロイ済みの CdkCrossStack に対して新ポリシーが適用されるのは、次回 cdk deploy を実行したタイミングです。
    既存スタックのリソース自体はそのまま維持されます。

    DeploymentActionRoleの信頼ポリシーを確認

    bootstrap後、DeploymentActionRole の信頼ポリシーにアカウントBが追加されていることを確認します。

    aws iam get-role `
      --role-name cdk-hnb659fds-deploy-role-111111111111-ap-northeast-1 `
      --query "Role.AssumeRolePolicyDocument" `
      --profile test-111111111111 `
      --no-cli-pager

    レスポンスにアカウントB(arn:aws:iam::222222222222:root)の sts:AssumeRole が含まれていれば正しく設定されています。

    Step 8:アカウントBのIAMユーザーにAssumeRole権限を付与

    アカウントAのロールを引き受けられるようになりましたが、アカウントBの test1 ユーザー自身にも sts:AssumeRole の権限が必要です。

    インラインポリシーのJSONを作成

    @"
    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Action": "sts:AssumeRole",
          "Resource": "arn:aws:iam::111111111111:role/cdk-hnb659fds-deploy-role-111111111111-ap-northeast-1"
        }
      ]
    }
    "@ | Set-Content assume-role.json

    test1ユーザーにポリシーをアタッチ

    aws iam put-user-policy `
      --user-name test1 `
      --policy-name AllowAssumeCdkDeployRole `
      --policy-document file://assume-role.json `
      --profile test-A

    Step 9:AssumeRoleの動作確認

    デプロイ前に、実際にAssumeRoleが成功するかを確認します。

    aws sts assume-role `
      --role-arn arn:aws:iam::111111111111:role/cdk-hnb659fds-deploy-role-111111111111-ap-northeast-1 `
      --role-session-name test `
      --profile test-A

    以下のように一時クレデンシャルが返れば成功です。

    {
        "Credentials": {
            "AccessKeyId": "ASIAXXXXXXXXXXXXXXXX",
            "SecretAccessKey": "****",
            "SessionToken": "****",
            "Expiration": "2026-03-24T19:05:06+00:00"
        },
        "AssumedRoleUser": {
            "AssumedRoleId": "AROAXXXXXXXXXXXXXXXXX:test",
            "Arn": "arn:aws:sts::111111111111:assumed-role/cdk-hnb659fds-deploy-role-111111111111-ap-northeast-1/test"
        }
    }

    Step 10:クロスアカウントデプロイの実行

    再度アカウントBからアカウントAへのクロスアカウントデプロイを実行します。

    cdk deploy --profile test-A

    ✅ CdkCrossStack (no changes) と表示されれば成功です。(Step 4で既にデプロイ済みのため変更なしと表示されます)

    Step 11:後片付け

    [!WARNING]
    この手順は 本ハンズオン用に作成した検証環境を前提としています。

    業務システムや他の CDK プロジェクトでも同一アカウント・リージョンで
    CDK を利用している場合、以下の操作を実行すると
    他のスタックやデプロイ処理に影響を与える可能性があります。

    • cdk destroy によるリソース削除
    • CDKToolkit スタック(bootstrap 環境)の削除
    • IAM ユーザー/ポリシー/アクセスキーの削除

    検証環境以外で実施する場合は、
    削除対象が本ハンズオンで作成したものに限定されていること
    事前に十分確認したうえで実行してください。

    スタックの削除

    クロスアカウント操作の確認ができたら、作成したリソースを削除します。

    cdk destroy --profile test-A

    Are you sure you want to delete: CdkCrossStack (y/n)? に y を入力します。
    ✅ CdkCrossStack: destroyed と表示されれば削除完了です。

    スタックが削除されたことを確認

    aws cloudformation describe-stacks `
      --stack-name CdkCrossStack `
      --profile test-111111111111

    Stack with id CdkCrossStack does not exist というエラーが返れば正しく削除されています。

    CDKToolkitスタックの削除

    aws cloudformation delete-stack `
      --stack-name CDKToolkit `
      --profile test-111111111111

    test1ユーザーのインラインポリシーを削除

    aws iam delete-user-policy `
      --user-name test1 `
      --policy-name AllowAssumeCdkDeployRole `
      --profile test-A

    test1ユーザーのアクセスキーを削除

    まずキーIDを確認します。

    aws iam list-access-keys --user-name test1 --profile test-A

    確認したキーIDを指定して削除します。

    aws iam delete-access-key `
      --user-name test1 `
      --access-key-id AKIAXXXXXXXXXXXXXXXX `
      --profile test-A

    AWSプロファイルの削除

    エディタで test-111111111111 および test-A のセクションを削除して保存します。

    削除後のプロファイル確認

    aws configure list-profiles

    削除したプロファイルが表示されなければ完了です。

    まとめ

    • cdk bootstrap はアカウントとリージョンの組み合わせごとに実行が必要
    • すでにbootstrap済みの環境では再実行不要。既存のCDKToolkitをそのまま利用する
    • 組織のIAMポリシー制限がある場合は、別途ロールを手動作成して --role-arn で指定する
    • cdk bootstrap --trust でデプロイ先アカウントが操作元アカウントを信頼する設定を行う
    • --cloudformation-execution-policies で AdministratorAccess を避け最小権限を使う
    • 操作元アカウントのIAMユーザーにも sts:AssumeRole 権限が必要
    • bin/*.ts の env.account は必ず明示的に指定する

    参考資料

    AWS CDK ブートストラップ
    AWS CDK で使用する環境をブートストラップする

    ※本記事は2026年05月時点の情報です。

    著者:マイナビエンジニアブログ編集部