

これは AWS CDK v2 デベロッパーガイドです。旧版の CDK v1 は 2022 年 6 月 1 日にメンテナンスを開始し、2023 年 6 月 1 日にサポートを終了しました。

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

# AWS CDK アプリケーションのデプロイ
<a name="deploy"></a>

AWS Cloud Development Kit (AWS CDK) のデプロイは、AWS でインフラストラクチャをプロビジョニングするプロセスです。

## AWS CDK のデプロイの仕組み
<a name="deploy-how"></a>

AWS CDK は、AWS CloudFormation サービスを使用してデプロイを実行します。デプロイする前に、CDK スタックを合成します。これにより、アプリケーション内の各 CDK スタックの CloudFormation テンプレートとデプロイアーティファクトが作成されます。デプロイは、ローカル開発マシンまたは*継続的統合と継続的配信 (CI/CD)* 環境から開始されます。デプロイ中、アセットはブートストラップされたリソースにアップロードされ、CloudFormation テンプレートが CloudFormation に送信されて AWS リソースをプロビジョニングします。

デプロイを成功させるには、以下が必要です。
+ AWS CDK コマンドラインインターフェイス (AWS CDK CLI) には有効なアクセス許可が必要です。
+ AWS 環境はブートストラップする必要があります。
+ AWS CDK は、アセットをアップロードするブートストラップされたリソースを把握している必要があります。

## CDK デプロイの前提条件
<a name="deploy-prerequisites"></a>

AWS CDK アプリケーションをデプロイする前に、以下を完了する必要があります。
+ CDK CLI のセキュリティ認証情報を設定する。
+ AWS 環境のブートストラップ。
+ CDK スタックごとに AWS 環境を設定する。
+ CDK アプリを開発する。<a name="deploy-prerequisites-creds"></a>

 **セキュリティ認証情報を設定する**   
CDK CLI を使用して AWS を操作するには、ローカルマシンでセキュリティ認証情報を設定する必要があります。手順については、「[AWS CDK CLI のセキュリティ認証情報を設定する](configure-access.md)」を参照してください。<a name="deploy-prerequisites-bootstrap"></a>

 **AWS 環境のブートストラップ**   
デプロイは常に 1 つ以上の AWS [環境](environments.md)に関連付けられます。デプロイする前に、まず環境を[ブートストラップ](bootstrapping.md)する必要があります。ブートストラップは、CDK がデプロイの実行と管理に使用するリソースを環境内にプロビジョニングします。これらのリソースには、[アセット](assets.md)を保存および管理するための Amazon Simple Storage Service (Amazon S3) バケットと Amazon Elastic Container Registry (Amazon ECR) リポジトリなどがあります。また、これらのリソースには、開発とデプロイ中にアクセス許可を付与するために使用される AWS Identity and Access Management (IAM) ロールも含まれます。  
環境をブートストラップする際は、AWS CDK コマンドラインインターフェイス (AWS CLI) の `cdk bootstrap` コマンドを使用することをお勧めします。必要に応じて、ブートストラップをカスタマイズすることや、環境内に手動でリソースを作成することができます。手順については、「[AWS CDK で使用する環境のブートストラップ](bootstrapping-env.md)」を参照してください。<a name="deploy-prerequisites-env"></a>

 **AWS 環境を設定する**   
各 CDK スタックは、スタックのデプロイ先を決定するために環境に関連付ける必要があります。手順については、「[AWS CDK で使用する環境を設定する](configure-env.md)」を参照してください。<a name="deploy-prerequisites-develop"></a>

 **CDK アプリの開発**   
CDK [プロジェクト](projects.md) 内では、CDK アプリを作成および開発します。アプリ内では、CDK [スタック](stacks.md)を 1 つ以上作成します。スタック内では、AWS コンストラクトライブラリから[コンストラクト](constructs.md)をインポートして使用し、インフラストラクチャを定義します。デプロイの前には、CDK アプリに少なくとも 1 つのスタックが含まれている必要があります。

## CDK アプリケーションの合成
<a name="deploy-how-synth"></a>

合成を実行する際は、CDK CLI の `cdk synth` コマンドを使用することをお勧めします。`cdk deploy` コマンドも、デプロイを開始する前に合成を実行はします。しかし、`cdk synth` を使用すると、デプロイを開始する前に CDK アプリを検証してエラーを検出してくれます。

合成の動作は、CDK スタック用に設定した[スタックシンセサイザー](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib-readme.html#stack-synthesizers)によって決まります。シンセサイザーを特に設定しない場合は、` [DefaultStackSynthesizer](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.DefaultStackSynthesizer.html) ` が使用されます。合成をニーズに合わせて設定およびカスタマイズすることもできます。手順については、「[CDK スタック合成を設定して実行する](configure-synth.md)」を参照してください。

合成された CloudFormation テンプレートを環境に正常にデプロイするには、環境のブートストラップ方法と互換性がある必要があります。たとえば、CloudFormation テンプレートは、アセットをデプロイする正しい Amazon S3 バケットを指定する必要があります。環境のブートストラップにデフォルトのメソッドを使用すると、デフォルトのスタックシンセサイザーが機能します。ブートストラップや合成のカスタマイズなど、CDK の動作をカスタマイズすると、CDK デプロイの動作が変化する場合があります。<a name="deploy-how-synth-app"></a>

 **アプリケーションのライフサイクル**   
合成を実行すると、CDK アプリケーションは、*アプリケーションのライフサイクル*と呼ばれる以下のフェーズを順に実行します。    
 **コンストラクト (または初期化)**   
コードは、定義されたすべてのコンストラクトをインスタンス化し、それらをリンクします。このステージでは、すべてのコンストラクト (アプリケーション、スタック、およびそれらの子コンストラクト) がインスタンス化され、コンストラクターチェーンが実行されます。ほとんどのアプリケーションコードはこの段階で実行されます。  
 **準備**   
`prepare` メソッドを実装したすべてのコンストラクトは、最終状態を設定するための最終変更ラウンドに参加します。準備フェーズは自動的に行われます。このフェーズからのフィードバックは、ユーザーには表示されません。「準備」フックを使用する必要はまれであり、一般的には推奨されません。オペレーションの順序が動作に影響する可能性があるため、このフェーズでコンストラクトツリーをミューテーションするときは細心の注意を払ってください。  
このフェーズでは、コンストラクトツリーが構築されると、設定したすべての[アスペクト](aspects.md)も適用されます。  
 **検証**   
`validate` メソッドを実装したすべてのコンストラクトは、正しくデプロイされる状態であることを確認するための自己検証を行うことができます。このフェーズ中に発生した検証失敗は通知されます。通常、できるだけ早く (通常、入力が得られたらすぐに) 検証を実行し、できるだけ早く例外をスローすることをおすすめします。検証を早期に実行すると、スタックトレースの精度が向上し、コードを安全に実行し続けることができるため、信頼性が向上します。  
 **合成**   
これは、CDK アプリを実行する最後の段階です。`app.synth()` への呼び出しによってトリガーされ、コンストラクトツリーを横断し、すべてのコンストラクトで `synthesize` メソッドを呼び出します。`synthesize` を実装するコンストラクトは、合成に参加して、結果のクラウドアセンブリにデプロイアーティファクトを生成できます。これらのアーティファクトには、CloudFormation テンプレート、AWS Lambda アプリケーションバンドル、ファイルおよび Docker イメージアセット、その他のデプロイアーティファクトが含まれます。ほとんどの場合、`synthesize` メソッドを実装する必要はありません。<a name="deploy-how-synth-run"></a>

 **アプリの実行**   
CDK CLI は、CDK アプリの実行方法を知る必要があります。`cdk init` コマンドを使用してテンプレートからプロジェクトを作成した場合、アプリの `cdk.json` ファイルには `app` キーが含まれます。このキーは、アプリケーションが書き込まれる言語に必要なコマンドを指定します。言語にコンパイルが必要な場合、コマンドラインはアプリを自動的に実行する前にこのステップを実行します。  

**Example**  

```
{
  "app": "npx ts-node --prefer-ts-exts bin/my-app.ts"
}
```

```
{
  "app": "node bin/my-app.js"
}
```

```
{
    "app": "python app.py"
}
```

```
{
  "app": "mvn -e -q compile exec:java"
}
```

```
{
  "app": "dotnet run -p src/MyApp/MyApp.csproj"
}
```

```
{
  "app": "go mod download && go run my-app.go"
}
```
CDK CLI を使用してプロジェクトを作成しなかった場合、または `cdk.json` で指定されたコマンドラインを上書きしたい場合は、`cdk` コマンドの実行時に ` --app ` オプションを指定します。

```
$ cdk --app '<executable>' <cdk-command> ...
```

コマンドの `<executable>` の部分は、CDK アプリケーションを実行するために実行する必要があるコマンドを示します。このようなコマンドにはスペースが含まれているため、図のように引用符を使用します。`<cdk-command>` は、`synth` や `deploy` のようなサブコマンドで、アプリケーションで実行したい内容を CDK CLI に指示します。これに続けて、そのサブコマンドに必要な追加オプションを指定します。

CDK CLI は、既に合成されたクラウドアセンブリを直接操作することもできます。これを行うには、クラウドアセンブリが保存されているディレクトリを `--app` で渡します。以下の例では、`./my-cloud-assembly` に格納されているクラウドアセンブリで定義されているスタックが一覧表示されます。

```
$ cdk --app <./my-cloud-assembly> ls
```<a name="deploy-how-synth-assemblies"></a>

 **クラウドアセンブリ**   
`app.synth()` への呼び出しは、アプリケーションからクラウドアセンブリを合成するよう AWS CDK に指示するものです。通常、クラウドアセンブリを直接操作することはありません。これらは、アプリケーションをクラウド環境にデプロイするために必要なすべてを含むファイルです。例えば、これにはアプリケーション内の各スタックの AWS CloudFormation テンプレートが含まれます。また、アプリで参照するファイルアセットまたは Docker イメージのコピーも含まれます。  
クラウドアセンブリのフォーマットの詳細については、「[クラウドアセンブリ仕様](https://github.com/aws/aws-cdk/blob/master/design/cloud-assembly.md)」を参照してください。  
AWS CDK アプリが作成するクラウドアセンブリを操作するには、通常 AWS CDK CLI を使用します。もっとも、クラウドアセンブリ形式を読み取ることができるツールであれば、どれでもアプリケーションのデプロイに使用できます。

## アプリケーションをデプロイします
<a name="deploy-how-deploy"></a>

アプリケーションをデプロイするには、CDK CLI の `cdk deploy` コマンドを使用してデプロイを開始するか、自動デプロイを設定することをお勧めします。

`cdk deploy` を実行すると、CDK CLI はデプロイの準備として `cdk synth` を起動します。以下の図は、デプロイの文脈におけるアプリケーションのライフサイクルを示しています。

![\[<shared id="AWS"/> CDK アプリのライフサイクルのフローチャート。\]](http://docs.aws.amazon.com/ja_jp/cdk/v2/guide/images/app-lifecycle_cdk-flowchart.png)


デプロイ中、CDK CLI は合成によって生成されたクラウドアセンブリを受け取り、AWS 環境にデプロイします。アセットは Amazon S3 と Amazon ECR にアップロードされ、CloudFormation テンプレートはデプロイのために AWS CloudFormation に送信されます。

AWS CloudFormation のデプロイフェーズが開始されるまでに、CDK アプリの実行と終了は既に完了しています。これには、以下のような影響があります。
+ CDK アプリは、作成中のリソースやデプロイ全体の終了など、デプロイ中に発生するイベントには応答できません。デプロイ段階でコードを実行するには、[カスタムリソース](cfn-layer.md#develop-customize-custom)として AWS CloudFormation テンプレートにコードを挿入する必要があります。アプリケーションにカスタムリソースを追加する方法の詳細については、[「AWS CloudFormation モジュール」](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_cloudformation-readme.html)、または[カスタムリソース](https://github.com/aws-samples/aws-cdk-examples/tree/master/typescript/custom-resource/)の例を参照してください。デプロイ中にコードを実行するように[トリガー](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.triggers-readme.html)モジュールを設定することもできます。
+ CDK アプリは、実行時にはわからない値を操作する必要がある場合があります。例えば、AWS CDK アプリが自動生成された名前で Amazon S3 バケットを定義し、`bucket.bucketName` (Python: `bucket_name`) 属性を取得した場合、その値はデプロイされたバケットの名前ではありません。代わりに、`Token` の値が返されます。特定の値が使用可能かどうかを判断するには、`cdk.isUnresolved(value)` (Python: `is_unresolved`) を呼び出します。詳細については、「[トークンと AWS CDK](tokens.md)」を参照してください。<a name="deploy-how-deploy-permissions"></a>

 **デプロイのアクセス許可**   
デプロイを実行する前には、アクセス許可を確立する必要があります。以下の図は、デフォルトのブートストラッププロセスとスタックシンセサイザーを使用する場合に、デフォルトのデプロイ中に使用されるアクセス許可を示しています。  

![\[デフォルトの <shared id="AWS"/> CDK デプロイプロセスのフローチャート。\]](http://docs.aws.amazon.com/ja_jp/cdk/v2/guide/images/default-deploy-process_cdk_flowchart.png)
  
 **アクターがデプロイを開始する**   
デプロイは、*アクター*により、CDK CLI を使用して開始されます。アクターは人物、または AWS CodePipeline などのサービスのいずれかです。  
必要に応じて、`cdk deploy` の実行時に CDK CLI が `cdk synth` を実行します。合成中、AWS アイデンティティは `LookupRole` を引き受け、AWS 環境でコンテキストルックアップを実行します。  
 **アクセス許可が確立される**   
まず、アクターのセキュリティ認証情報を使用して AWS に認証を行い、その過程で最初の IAM アイデンティティを取得します。アクターが人間である場合、セキュリティ認証情報の設定と取得方法は、ユーザーまたは組織がユーザーを管理する方法によって異なります。詳細については、「[AWS CDK CLI のセキュリティ認証情報を設定する](configure-access.md)」を参照してください。アクターが CodePipeline などのサービスである場合、IAM 実行ロールが引き受けられ、使用されます。  
次に、ブートストラップ中に AWS 環境で作成された IAM ロールを使用して、デプロイに必要なアクションを実行するためのアクセス許可を確立します。これらのロールおよびロールが付与するアクセス許可の詳細については、「[ブートストラップ中に作成された IAM ロール](bootstrapping-env.md#bootstrapping-env-roles)」を参照してください。このプロセスには以下が含まれます。  
+ AWS ID は `DeploymentActionRole` ロールを引き受け、`CloudFormationExecutionRole` ロールを CloudFormation に渡すことで、CloudFormation が AWS 環境で何らかのアクションを実行する際に、ロールを確実に引き受けるようにします。`DeploymentActionRole` は、環境へのデプロイを実行するアクセス許可を付与し、`CloudFormationExecutionRole` は、CloudFormation が実行できるアクションを決定します。
+ AWS ID は `FilePublishingRole` を引き受け、ブートストラップ中に作成された Amazon S3 バケットに対して実行できるアクションを決定します。
+ AWS ID は `ImagePublishingRole` を引き受け、ブートストラップ中に作成された Amazon ECR リポジトリで実行できるアクションを決定します。
+ 必要に応じて、AWS ID は `LookupRole` を引き受け、AWS 環境でコンテキスト検索を実行します。このアクションは、テンプレートの合成中に実行することもできます。  
 **デプロイが実行される**   
デプロイ中、CDK CLI はブートストラップバージョンパラメータを読み取り、ブートストラップバージョン番号を確認します。AWSCloudFormation は、デプロイ時にこのパラメータを読み取り、確認を行います。デプロイワークフロー全体のアクセス許可が有効である場合、デプロイが実行されます。アセットはブートストラップされたリソースにアップロードされ、合成時に生成された CloudFormation テンプレートは CloudFormation サービスを CloudFormation スタックとして使用してデプロイされ、リソースがプロビジョニングされます。

# 合成時の AWS CDK ポリシー検証
<a name="policy-validation-synthesis"></a>

## 合成時のポリシー検証
<a name="policy-validation"></a>

ユーザーまたは組織が [AWS CloudFormation Guard](https://docs.aws.amazon.com/cfn-guard/latest/ug/what-is-guard.html) や [OPA](https://www.openpolicyagent.org/) などのポリシー検証ツールを使用して AWS CloudFormation テンプレートの制約を定義する場合、合成時に AWS CDK と統合できます。適切なポリシー検証プラグインを使用すると、合成直後に AWS CDK アプリケーションが生成された AWS CloudFormation テンプレートとポリシーを照合させることができます。違反がある場合、合成は失敗してレポートがコンソールに出力されます。

合成時に AWS CDK によって実行される検証は、デプロイライフサイクルのある時点で制御を検証しますが、合成以外で発生するアクションに影響を与えることはできせん。例には、コンソールで直接実行されるアクションや、サービス API を介したアクションが含まれます。合成後、AWS CloudFormation テンプレートの変更には耐性がありません。「[AWS CloudFormation フック](https://docs.aws.amazon.com/cloudformation-cli/latest/userguide/hooks.html)」や「[AWS Config](https://docs.aws.amazon.com/config/latest/developerguide/WhatIsConfig.html)」など、同じルールセットをより権威的に検証する他のメカニズムを個別に設定する必要があります。ただし、検出速度およびデベロッパーの生産性を向上させるため、AWS CDK が開発中にルールセットを評価する能力は依然として有用です。

AWS CDK ポリシー検証の目的は、開発時に必要なセットアップ量を最小限に抑え、可能な限り簡単にすることです。

**注記**  
この機能は実験的なものとして考えられているため、プラグイン API および検証レポートの形式の両方は今後変更の対象となります。

## アプリケーションデベロッパー向け
<a name="for-application-developers"></a>

アプリケーションで 1 つ以上の検証プラグインを使用するには、`Stage` の `policyValidationBeta1` プロパティを使用します。

```
import { CfnGuardValidator } from '@cdklabs/cdk-validator-cfnguard';
const app = new App({
  policyValidationBeta1: [
    new CfnGuardValidator()
  ],
});
// only apply to a particular stage
const prodStage = new Stage(app, 'ProdStage', {
  policyValidationBeta1: [...],
});
```

合成の直後、この方法で登録されたすべてのプラグインが呼び出され、定義したスコープで生成されたすべてのテンプレートが検証されます。特に、`App` オブジェクトにテンプレートを登録した場合、すべてのテンプレートが検証の対象となります。

**警告**  
クラウドアセンブリを変更することに加え、プラグインは AWS CDK アプリケーションができることをすべてできます。ファイルシステムからデータを読み取ったり、ネットワークにアクセスしたりすることなどができます。プラグインを安全に使用できることを確認することは、プラグインのコンシューマーとしてユーザーの責任です。

### AWS CloudFormation Guard プラグイン
<a name="cfnguard-plugin"></a>

[https://github.com/cdklabs/cdk-validator-cfnguard](https://github.com/cdklabs/cdk-validator-cfnguard) プラグインを使用すると、「[AWS CloudFormation Guard](https://github.com/aws-cloudformation/cloudformation-guard)」を使用してポリシーの検証を実行できます。`CfnGuardValidator` プラグインには、厳選された一連の「[AWS Control Tower プロアクティブコントロール](https://docs.aws.amazon.com/controltower/latest/userguide/proactive-controls.html)」が組み込まれています。現在のルールのセットは、「[プロジェクトドキュメント](https://github.com/cdklabs/cdk-validator-cfnguard/blob/main/README.md)」にあります。「[合成時のポリシー検証](#policy-validation)」で説明したように、組織は「[AWS CloudFormation フック](https://docs.aws.amazon.com/cloudformation-cli/latest/userguide/hooks.html)」を使用してより権威的な検証方法を設定することをお勧めします。

「[AWS Control Tower](https://docs.aws.amazon.com/controltower/latest/userguide/what-is-control-tower.html) 」の顧客の場合、これらの同じプロアクティブコントロールは組織全体にデプロイできます。AWS Control Tower 環境で AWS Control Tower プロアクティブコントロールを有効にすると、コントロールは AWS CloudFormation を介してデプロイされた非準拠リソースのデプロイを阻止できます。マネージドプロアクティブコントロールとその仕組みの詳細については、「[AWS Control Tower キュメント](https://docs.aws.amazon.com/controltower/latest/userguide/proactive-controls.html)」を参照してください。

これらの AWS CDK でバンドルされたコントロールおよびマネージド AWS Control Tower プロアクティブコントロールは、一緒に使用すると最適です。このシナリオでは、AWS Control Tower クラウド環境でアクティブなプロアクティブコントロールを使用し、この検証プラグインを設定できます。その後、`cdk synth` をローカルで実行し、AWS CDK アプリケーションが AWS Control Tower コントロールを渡すことに対して短時間で安心を得ることができます。

### 検証レポート
<a name="validation-report"></a>

AWS CDK アプリを合成すると、検証プラグインが呼び出されて結果が出力されます。レポートの例が以下に示されています。

```
Validation Report (CfnGuardValidator)
-------------------------------------
(Summary)
╔═══════════╤════════════════════════╗
║ Status    │ failure                ║
╟───────────┼────────────────────────╢
║ Plugin    │ CfnGuardValidator      ║
╚═══════════╧════════════════════════╝
(Violations)
Ensure S3 Buckets are encrypted with a KMS CMK (1 occurrences)
Severity: medium
  Occurrences:

    - Construct Path: MyStack/MyCustomL3Construct/Bucket
    - Stack Template Path: ./cdk.out/MyStack.template.json
    - Creation Stack:
        └──  MyStack (MyStack)
             │ Library: aws-cdk-lib.Stack
             │ Library Version: 2.50.0
             │ Location: Object.<anonymous> (/home/johndoe/tmp/cdk-tmp-app/src/main.ts:25:20)
             └──  MyCustomL3Construct (MyStack/MyCustomL3Construct)
                  │ Library: N/A - (Local Construct)
                  │ Library Version: N/A
                  │ Location: new MyStack (/home/johndoe/tmp/cdk-tmp-app/src/main.ts:15:20)
                  └──  Bucket (MyStack/MyCustomL3Construct/Bucket)
                       │ Library: aws-cdk-lib/aws-s3.Bucket
                       │ Library Version: 2.50.0
                       │ Location: new MyCustomL3Construct (/home/johndoe/tmp/cdk-tmp-app/src/main.ts:9:20)
    - Resource Name: amzn-s3-demo-bucket
    - Locations:
      > BucketEncryption/ServerSideEncryptionConfiguration/0/ServerSideEncryptionByDefault/SSEAlgorithm
  Recommendation: Missing value for key `SSEAlgorithm` - must specify `aws:kms`
  How to fix:
    > Add to construct properties for `cdk-app/MyStack/Bucket`
      `encryption: BucketEncryption.KMS`

Validation failed. See above reports for details
```

デフォルトでは、レポートは人間が読み取れる形式で出力されます。JSON 形式のレポートが必要な場合、CLI を介して `@aws-cdk/core:validationReportJson` を使用して有効にするか、アプリケーションに直接渡します。

```
const app = new App({
  context: { '@aws-cdk/core:validationReportJson': true },
});
```

または、プロジェクトディレクトリの `cdk.json` または `cdk.context.json` ファイルを使用し、このコンテキストキーと値のペアを設定できます (「[コンテキスト値と AWS CDK](context.md)」を参照)。

JSON 形式を選択した場合、AWS CDK はポリシー検証レポートをクラウドアセンブリディレクトリの `policy-validation-report.json` というファイルに出力します。デフォルトの人間が読める形式の場合、レポートは標準出力で出力されます。

## プラグイン作成者向け
<a name="plugin-authors"></a>

### プラグイン
<a name="plugins"></a>

AWS CDK コアフレームワークは、プラグインを登録して呼び出したら、フォーマットされた検証レポートを表示する役割を果たしています。プラグインの役割は、AWS CDK フレームワークとポリシー検証ツール間の変換レイヤーとして機能することです。プラグインは、AWS CDK でサポートされているすべての言語で作成できます。複数の言語を使用するプラグインを作成する場合、JSII を使用してプラグインを各 AWS CDK 言語で公開できるように、プラグインを `TypeScript` で作成することをお勧めします。

### プラグインの作成
<a name="creating-plugins"></a>

AWS CDK コアモジュールとポリシーツール間の通信プロトコルは、`IPolicyValidationPluginBeta1` インターフェイスによって定義されます。新しいプラグインを作成するには、このインターフェイスを実装するクラスを記述する必要があります。実装する必要があるものは 2 つあり、プラグイン名 (`name` プロパティを上書きすることで実装) および `validate()` メソッドです。

フレームワークは `validate()` を呼び出し、`IValidationContextBeta1` オブジェクトを渡します。検証するテンプレートの場所は `templatePaths` によって指定されます。プラグインは `ValidationPluginReportBeta1` のインスタンスを返します。このオブジェクトは、合成の最後にユーザーが受け取るレポートを表します。

```
validate(context: IPolicyValidationContextBeta1): PolicyValidationReportBeta1 {
  // First read the templates using context.templatePaths...
  // ...then perform the validation, and then compose and return the report.
  // Using hard-coded values here for better clarity:
  return {
    success: false,
    violations: [{
      ruleName: 'CKV_AWS_117',
      description: 'Ensure that AWS Lambda function is configured inside a VPC',
      fix: 'https://docs.bridgecrew.io/docs/ensure-that-aws-lambda-function-is-configured-inside-a-vpc-1',
      violatingResources: [{
        resourceName: 'MyFunction3BAA72D1',
        templatePath: '/home/johndoe/myapp/cdk.out/MyService.template.json',
        locations: 'Properties/VpcConfig',
      }],
    }],
  };
}
```

プラグインは、クラウドアセンブリのものを一切変更できないことに注意してください。変更しようとすると合成が失敗します。

プラグインが外部ツールに依存している場合、一部のデベロッパーがまだそのツールをワークステーションにインストールしていない場合があることに注意してください。わずらわしさを最小限に抑えるには、プロセス全体を自動化するため、プラグインパッケージと共にインストールスクリプトを提供することを強くお勧めします。さらに、パッケージのインストールの一環として、そのスクリプトを実行することをお勧めします。例えば、`npm` を使用すると、`package.json` ファイルの `postinstall`「[スクリプト](https://docs.npmjs.com/cli/v9/using-npm/scripts)」に追加できます。

### 適用除外の処理
<a name="handling-exemptions"></a>

組織に適用除外を処理するメカニズムがある場合、検証プラグインの一部として実装できます。

実現可能な適用除外メカニズムを説明するシナリオの例
+ 特定のシナリオ*を除き*、ある組織にはパブリック Amazon S3 バケットが許可されないというルールがあります。
+ デベロッパーはこれらのシナリオのいずれかに該当する Amazon S3 バケットを作成し、適用除外を要求します (チケットの作成など)。
+ セキュリティのツールは、適用除外を登録する内部システムから読み取る方法を知っています

このシナリオでは、デベロッパーは内部システムで例外を要求し、その例外を「登録」する方法が必要になります。ガードプラグインの例に追加すると、内部チケットシステムに一致する適用除外がある違反をフィルタリングすることにより、適用除外を処理するプラグインを作成できます。

実装例については、既存のプラグインを参照してください。
+  [@cdklabs/cdk-validator-cfnguard](https://github.com/cdklabs/cdk-validator-cfnguard) 

# CDK Pipelines を使用した継続的インテグレーションと継続的デリバリー (CI/CD)
<a name="cdk-pipeline"></a>

AWS コンストラクトライブラリの [CDK Pipelines](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.pipelines-readme.html) モジュールを使用して、AWS CDK アプリケーションの継続的デリバリーを設定します。CDK アプリのソースコードを AWS CodeCommit、GitHub、または AWS CodeStar にコミットすると、CDK Pipelines が自動的に新しいバージョンのビルド、テスト、デプロイを行います。

CDK Pipelines は自動更新です。アプリケーションステージまたはスタックを追加すると、パイプラインは自動的に再設定され、それらの新しいステージまたはスタックがデプロイされます。

**注記**  
CDK Pipelines は 2 つの API をサポートしています。1 つは、CDK Pipelines 開発者プレビューで利用可能になった元の API です。もう 1 つは、プレビューフェーズで受け取った CDK 顧客からのフィードバックが組み込まれた、最新の API です。このトピックの例では、最新の API を使用しています。2 つのサポートされている API の違いの詳細については、「*aws-cdk GitHub リポジトリ*」の「[CDK Pipelines オリジナル API](https://github.com/aws/aws-cdk/blob/master/packages/@aws-cdk/pipelines/ORIGINAL_API.md)」を参照してください。

## AWS 環境のブートストラップ
<a name="cdk-pipeline-bootstrap"></a>

CDK Pipelines を使用する前に、スタックをデプロイする AWS [環境](environments.md)をブートストラップする必要があります。

CDK パイプラインには、少なくとも 2 つの環境が含まれます。1 つめの環境は、パイプラインがプロビジョニングされる場所です。2 つめの環境は、アプリケーションのスタックまたはステージをデプロイする場所です (ステージは関連するスタックのグループです)。これらの環境は同じにすることができますが、ベストプラクティスとしては、異なる環境でステージを分離することをおすすめします。

**注記**  
ブートストラップによって作成されるリソースの種類と、ブートストラップスタックをカスタマイズする方法については、「[AWS ブートストラップ](bootstrapping.md)」を参照してください。

CDK Pipelines での継続的なデプロイでは、CDK Toolkit スタックに以下を含める必要があります。
+ 1 つの Amazon Simple Storage Service (Amazon S3) バケット
+ Amazon ECR リポジトリ
+ パイプラインのさまざまな部分に必要なアクセス許可を付与する IAM ロール

CDK Toolkit は、既存のブートストラップスタックをアップグレードするか、必要に応じて新しいブートストラップスタックを作成します。

AWS CDK パイプラインをプロビジョニングできる環境をブートストラップするには、以下の例に示すように `cdk bootstrap` を呼び出します。`npx` コマンドを使用して AWS CDK Toolkit を呼び出すと、必要に応じて一時的にインストールされます。また、現在のプロジェクトにインストールされている Toolkit が存在する場合は、そのバージョンも使用します。

 `--cloudformation-execution-policies` は、将来の CDK Pipelines デプロイを実行するポリシーの ARN を指定します。デフォルトの `AdministratorAccess` ポリシーにより、あらゆるタイプの AWS リソースをデプロイできるパイプラインが確実に作成されます。このポリシーを使用する場合は、AWS CDK アプリを構成するすべてのコードと依存関係を信頼するようにしてください。

ほとんどの組織は、自動化によってデプロイできるリソースの種類をより厳しく制御することを義務付けています。組織内の適切な部門に問い合わせて、パイプラインが使用するポリシーを決定します。

デフォルトの AWS プロファイルに必要な認証設定と AWS リージョンが含まれている場合は、`--profile` オプションを省略できます。

**Example**  

```
npx cdk bootstrap aws://<ACCOUNT-NUMBER>/<REGION> --profile <ADMIN-PROFILE> \
    --cloudformation-execution-policies arn:aws:iam::aws:policy/AdministratorAccess
```

```
npx cdk bootstrap aws://<ACCOUNT-NUMBER></REGION> --profile< ADMIN-PROFILE> ^
    --cloudformation-execution-policies arn:aws:iam::aws:policy/AdministratorAccess
```

パイプラインによって AWS CDK アプリケーションがデプロイされる追加の環境をブートストラップするには、代わりに以下のコマンドを使用します。`--trust` オプションは、AWS CDK アプリケーションをこの環境にデプロイするアクセス許可を、他のどのアカウントに付与するかを指定します。このオプションでは、パイプラインの AWS アカウント ID を指定します。

ここでも、デフォルトの AWS プロファイルに必要な認証設定と AWS リージョンが含まれている場合は、`--profile` オプションを省略できます。

**Example**  

```
npx cdk bootstrap aws://<ACCOUNT-NUMBER>/<REGION> --profile <ADMIN-PROFILE> \
    --cloudformation-execution-policies arn:aws:iam::aws:policy/AdministratorAccess \
    --trust <PIPELINE-ACCOUNT-NUMBER>
```

```
npx cdk bootstrap aws://<ACCOUNT-NUMBER>/<REGION> --profile <ADMIN-PROFILE> ^
    --cloudformation-execution-policies arn:aws:iam::aws:policy/AdministratorAccess ^
    --trust <PIPELINE-ACCOUNT-NUMBER>
```

**ヒント**  
管理認証情報は、ブートストラップと初期パイプラインのプロビジョニングにのみ使用します。その後、ローカルマシンではなくパイプライン自体を使用して変更をデプロイします。

レガシーブートストラップ環境をアップグレードする場合、新しいバケットが作成されると、以前の Amazon S3 バケットは孤立します。これは、Amazon S3 コンソールを使用して手動で削除してください。

### ブートストラップスタックの削除からの保護
<a name="cdk-pipeline-protect"></a>

ブートストラップスタックが削除されると、CDK デプロイをサポートするために環境で最初にプロビジョニングされた AWS リソースも削除されます。これにより、パイプラインの動作が停止します。これが起きると、復旧のための一般的なソリューションはありません。

環境がブートストラップされた後は、環境のブートストラップスタックの削除と再作成は行わないでください。代わりに、`cdk bootstrap` コマンドを再度実行して、ブートストラップスタックを新しいバージョンに更新してみてください。

ブートストラップスタックが誤って削除されないように保護するには、終了保護を有効にする `--termination-protection` オプションに `cdk bootstrap` コマンドを指定することをおすすめします。新規または既存のブートストラップスタックで終了保護を有効にすることができます。このオプションの詳細については、「` --termination-protection `」を参照してください。

終了保護を有効にした後、AWS CLI または CloudFormation コンソールを使用して検証できます。

1. 次のコマンドを実行して、新規または既存のブートストラップスタックで終了保護を有効にします。

   ```
   $ cdk bootstrap --termination-protection
   ```

1. AWS CLI または CloudFormation コンソールを使用して確認します。以下に示しているのは、AWS CLI を使用した例です。ブートストラップスタック名を変更した場合は、`CDKToolkit` をスタック名に置き換えます。

   ```
   $ aws cloudformation describe-stacks --stack-name <CDKToolkit> --query "Stacks[0].EnableTerminationProtection"
   true
   ```

## プロジェクトの初期化
<a name="cdk-pipeline-init"></a>

新しい空の GitHub プロジェクトを作成し、`my-pipeline` ディレクトリ内のワークステーションにクローンします。(このトピックのコード例では、GitHub を使用します。AWS CodeStar または AWS CodeCommit を使用することもできます。)

```
git clone <GITHUB-CLONE-URL> my-pipeline
cd my-pipeline
```

**注記**  
アプリのメインディレクトリには、`my-pipeline` 以外の名前を使用できます。ただし、その場合は、このトピックの後半でファイルとクラス名を調整する必要があります。これは、AWS CDK ツールキットの一部のファイル名とクラス名がメインディレクトリの名前に基づいているためです。

クローンを作成したら、通常どおりにプロジェクトを初期化します。

**Example**  

```
$ cdk init app --language typescript
```

```
$ cdk init app --language javascript
```

```
$ cdk init app --language python
```
アプリを作成したら、以下の 2 つのコマンドも入力します。これにより、アプリの Python 仮想環境がアクティブ化され、AWS CDK コア依存関係がインストールされます。  

```
$ source .venv/bin/activate # On Windows, run `.\venv\Scripts\activate` instead
$ python -m pip install -r requirements.txt
```

```
$ cdk init app --language java
```
IDE を使用している場合は、これでプロジェクトを開くかインポートできるようになります。たとえば Eclipse では、**[ファイル]**、**[インポート]**、**[Maven]**、**[既存の Maven プロジェクト]** を選択します。プロジェクト設定が Java 8 (1.8) を使用するように設定されていることを確認してください。

```
$ cdk init app --language csharp
```
Visual Studio を使用している場合は、`src` ディレクトリでソリューションファイルを開きます。

```
$ cdk init app --language go
```
アプリを作成したら、以下のコマンドを入力して、アプリに必要な AWS コンストラクトライブラリモジュールをインストールします。  

```
$ go get
```

**重要**  
`cdk.json` および `cdk.context.json` ファイルは必ずソースコントロールにコミットしてください。コンテキスト情報 (AWS アカウントから取得した特徴量フラグやキャッシュされた値など) は、プロジェクトの状態の一部です。値は環境ごとに異なる場合があり、結果として予期せぬ変更が生じる可能性があります。詳細については、「[コンテキスト値と AWS CDK](context.md)」を参照してください。

## パイプラインを定義する
<a name="cdk-pipeline-define"></a>

CDK Pipelines アプリケーションには、少なくとも 2 つのスタックが含まれます。1 つはパイプライン自体を表すスタックで、もう 1 つかそれ以上は、それを通してデプロイされたアプリケーションを表すスタックです。スタックは*ステージ*にグループ化することもできます。ステージを使用して、インフラストラクチャスタックのコピーをさまざまな環境にデプロイできます。ひとまずはパイプラインを検討し、後ほどにはデプロイするアプリケーションについて掘り下げていきます。

コンストラクト ` [CodePipeline](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.pipelines.CodePipeline.html) ` は、AWS をデプロイエンジンとして使用する CDK Pipelines を表すコンストラクトです。`CodePipeline` をスタックでインスタンス化する場合は、パイプラインのソースの場所 (GitHub リポジトリなど) を定義します。また、アプリケーションを構築するためのコマンドも定義します。

たとえば、ソースが GitHub リポジトリに保存されているパイプラインを以下に示します。これには、TypeScript CDK アプリケーションのビルドステップも含まれています。GitHub リポジトリに関する情報を、指定された場所に入力します。

**注記**  
デフォルトでは、パイプラインは、Secrets Manager に `github-token` という名前で保存されている個人用アクセストークンを使用して GitHub を認証します。

また、パイプラインスタックのインスタンス化を更新して、AWS アカウントとリージョンを指定する必要があります。

**Example**  
`lib/my-pipeline-stack.ts` に作成 (プロジェクトフォルダの名前が `my-pipeline` ではない場合は、異なる場合があります)  

```
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { CodePipeline, CodePipelineSource, ShellStep } from 'aws-cdk-lib/pipelines';

export class MyPipelineStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const pipeline = new CodePipeline(this, 'Pipeline', {
      pipelineName: 'MyPipeline',
      synth: new ShellStep('Synth', {
        input: CodePipelineSource.gitHub('OWNER/REPO', 'main'),
        commands: ['npm ci', 'npm run build', 'npx cdk synth']
      })
    });
  }
}
```
`bin/my-pipeline.ts` に作成 (プロジェクトフォルダの名前が `my-pipeline` ではない場合は、異なる場合があります)  

```
#!/usr/bin/env node
import * as cdk from 'aws-cdk-lib';
import { MyPipelineStack } from '../lib/my-pipeline-stack';

const app = new cdk.App();
new MyPipelineStack(app, 'MyPipelineStack', {
  env: {
    account: '111111111111',
    region: 'eu-west-1',
  }
});

app.synth();
```
`lib/my-pipeline-stack.js` に作成 (プロジェクトフォルダの名前が `my-pipeline` ではない場合は、異なる場合があります)  

```
const cdk = require('aws-cdk-lib');
const { CodePipeline, CodePipelineSource, ShellStep } = require('aws-cdk-lib/pipelines');

 class MyPipelineStack extends cdk.Stack {
  constructor(scope, id, props) {
    super(scope, id, props);

    const pipeline = new CodePipeline(this, 'Pipeline', {
      pipelineName: 'MyPipeline',
      synth: new ShellStep('Synth', {
        input: CodePipelineSource.gitHub('OWNER/REPO', 'main'),
        commands: ['npm ci', 'npm run build', 'npx cdk synth']
      })
    });
  }
}

module.exports = { MyPipelineStack }
```
`bin/my-pipeline.js` に作成 (プロジェクトフォルダの名前が `my-pipeline` ではない場合は、異なる場合があります)  

```
#!/usr/bin/env node

const cdk = require('aws-cdk-lib');
const { MyPipelineStack } = require('../lib/my-pipeline-stack');

const app = new cdk.App();
new MyPipelineStack(app, 'MyPipelineStack', {
  env: {
    account: '111111111111',
    region: 'eu-west-1',
  }
});

app.synth();
```
`my-pipeline/my-pipeline-stack.py` に作成 (プロジェクトフォルダの名前が `my-pipeline` ではない場合は、異なる場合があります)  

```
import aws_cdk as cdk
from constructs import Construct
from aws_cdk.pipelines import CodePipeline, CodePipelineSource, ShellStep

class MyPipelineStack(cdk.Stack):

    def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        pipeline =  CodePipeline(self, "Pipeline",
                        pipeline_name="MyPipeline",
                        synth=ShellStep("Synth",
                            input=CodePipelineSource.git_hub("OWNER/REPO", "main"),
                            commands=["npm install -g aws-cdk",
                                "python -m pip install -r requirements.txt",
                                "cdk synth"]
                        )
                    )
```
`app.py` に作成  

```
#!/usr/bin/env python3
import aws_cdk as cdk
from my_pipeline.my_pipeline_stack import MyPipelineStack

app = cdk.App()
MyPipelineStack(app, "MyPipelineStack",
    env=cdk.Environment(account="111111111111", region="eu-west-1")
)

app.synth()
```
`src/main/java/com/myorg/MyPipelineStack.java` に作成 (プロジェクトフォルダの名前が `my-pipeline` ではない場合は、異なる場合があります)  

```
package com.myorg;

import java.util.Arrays;
import software.constructs.Construct;
import software.amazon.awscdk.Stack;
import software.amazon.awscdk.StackProps;
import software.amazon.awscdk.pipelines.CodePipeline;
import software.amazon.awscdk.pipelines.CodePipelineSource;
import software.amazon.awscdk.pipelines.ShellStep;

public class MyPipelineStack extends Stack {
    public MyPipelineStack(final Construct scope, final String id) {
        this(scope, id, null);
    }

    public MyPipelineStack(final Construct scope, final String id, final StackProps props) {
        super(scope, id, props);

        CodePipeline pipeline = CodePipeline.Builder.create(this, "pipeline")
             .pipelineName("MyPipeline")
             .synth(ShellStep.Builder.create("Synth")
                .input(CodePipelineSource.gitHub("OWNER/REPO", "main"))
                .commands(Arrays.asList("npm install -g aws-cdk", "cdk synth"))
                .build())
             .build();
    }
}
```
`src/main/java/com/myorg/MyPipelineApp.java` に作成 (プロジェクトフォルダの名前が `my-pipeline` ではない場合は、異なる場合があります)  

```
package com.myorg;

import software.amazon.awscdk.App;
import software.amazon.awscdk.Environment;
import software.amazon.awscdk.StackProps;

public class MyPipelineApp {
    public static void main(final String[] args) {
        App app = new App();

        new MyPipelineStack(app, "PipelineStack", StackProps.builder()
            .env(Environment.builder()
                .account("111111111111")
                .region("eu-west-1")
                .build())
            .build());

        app.synth();
    }
}
```
`src/MyPipeline/MyPipelineStack.cs` に作成 (プロジェクトフォルダの名前が `my-pipeline` ではない場合は、異なる場合があります)  

```
using Amazon.CDK;
using Amazon.CDK.Pipelines;

namespace MyPipeline
{
    public class MyPipelineStack : Stack
    {
        internal MyPipelineStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props)
        {
            var pipeline = new CodePipeline(this, "pipeline", new CodePipelineProps
            {
                PipelineName = "MyPipeline",
                Synth = new ShellStep("Synth", new ShellStepProps
                {
                    Input = CodePipelineSource.GitHub("OWNER/REPO", "main"),
                    Commands = new string[] { "npm install -g aws-cdk", "cdk synth" }
                })
            });
        }
    }
}
```
`src/MyPipeline/Program.cs` に作成 (プロジェクトフォルダの名前が `my-pipeline` ではない場合は、異なる場合があります)  

```
using Amazon.CDK;

namespace MyPipeline
{
    sealed class Program
    {
        public static void Main(string[] args)
        {
            var app = new App();
            new MyPipelineStack(app, "MyPipelineStack", new StackProps
            {
                Env = new Amazon.CDK.Environment {
                    Account = "111111111111", Region = "eu-west-1" }
            });

            app.Synth();
        }
    }
}
```

```
package main

import (
	"github.com/aws/aws-cdk-go/awscdk/v2"
	codebuild "github.com/aws/aws-cdk-go/awscdk/v2/awscodebuild"
	ssm "github.com/aws/aws-cdk-go/awscdk/v2/awsssm"
	pipeline "github.com/aws/aws-cdk-go/awscdk/v2/pipelines"
	"github.com/aws/constructs-go/constructs/v10"
	"github.com/aws/jsii-runtime-go"
	"os"
)

// my CDK Stack with resources
func NewCdkStack(scope constructs.Construct, id *string, props *awscdk.StackProps) awscdk.Stack {
	stack := awscdk.NewStack(scope, id, props)

	// create an example ssm parameter
	_ = ssm.NewStringParameter(stack, jsii.String("ssm-test-param"), &ssm.StringParameterProps{
		ParameterName: jsii.String("/testparam"),
		Description:   jsii.String("ssm parameter for demo"),
		StringValue:   jsii.String("my test param"),
	})

	return stack
}

// my CDK Application
func NewCdkApplication(scope constructs.Construct, id *string, props *awscdk.StageProps) awscdk.Stage {
	stage := awscdk.NewStage(scope, id, props)

	_ = NewCdkStack(stage, jsii.String("cdk-stack"), &awscdk.StackProps{Env: props.Env})

	return stage
}

// my CDK Pipeline
func NewCdkPipeline(scope constructs.Construct, id *string, props *awscdk.StackProps) awscdk.Stack {
	stack := awscdk.NewStack(scope, id, props)

	// GitHub repo with owner and repository name
	githubRepo := pipeline.CodePipelineSource_GitHub(jsii.String("owner/repo"), jsii.String("main"), &pipeline.GitHubSourceOptions{
		Authentication: awscdk.SecretValue_SecretsManager(jsii.String("my-github-token"), nil),
	})

	// self mutating pipeline
	myPipeline := pipeline.NewCodePipeline(stack, jsii.String("cdkPipeline"), &pipeline.CodePipelineProps{
		PipelineName: jsii.String("CdkPipeline"),
		// self mutation true - pipeline changes itself before application deployment
		SelfMutation: jsii.Bool(true),
		CodeBuildDefaults: &pipeline.CodeBuildOptions{
			BuildEnvironment: &codebuild.BuildEnvironment{
				// image version 6.0 recommended for newer go version
				BuildImage: codebuild.LinuxBuildImage_FromCodeBuildImageId(jsii.String("aws/codebuild/standard:6.0")),
			},
		},
		Synth: pipeline.NewCodeBuildStep(jsii.String("Synth"), &pipeline.CodeBuildStepProps{
			Input: githubRepo,
			Commands: &[]*string{
				jsii.String("npm install -g aws-cdk"),
				jsii.String("cdk synth"),
			},
		}),
	})

	// deployment of actual CDK application
	myPipeline.AddStage(NewCdkApplication(stack, jsii.String("MyApplication"), &awscdk.StageProps{
		Env: targetAccountEnv(),
	}), &pipeline.AddStageOpts{
		Post: &[]pipeline.Step{
			pipeline.NewCodeBuildStep(jsii.String("Manual Steps"), &pipeline.CodeBuildStepProps{
				Commands: &[]*string{
					jsii.String("echo \"My CDK App deployed, manual steps go here ... \""),
				},
			}),
		},
	})

	return stack
}

// main app
func main() {
	defer jsii.Close()

	app := awscdk.NewApp(nil)

	// call CDK Pipeline
	NewCdkPipeline(app, jsii.String("CdkPipelineStack"), &awscdk.StackProps{
		Env: pipelineEnv(),
	})

	app.Synth(nil)
}

// env determines the AWS environment (account+region) in which our stack is to
// be deployed. For more information see: https://docs.aws.amazon.com/cdk/latest/guide/environments.html
func pipelineEnv() *awscdk.Environment {
	return &awscdk.Environment{
		Account: jsii.String(os.Getenv("CDK_DEFAULT_ACCOUNT")),
		Region:  jsii.String(os.Getenv("CDK_DEFAULT_REGION")),
	}
}

func targetAccountEnv() *awscdk.Environment {
	return &awscdk.Environment{
		Account: jsii.String(os.Getenv("CDK_DEFAULT_ACCOUNT")),
		Region:  jsii.String(os.Getenv("CDK_DEFAULT_REGION")),
	}
}
```

パイプラインは 1 度手動でデプロイする必要があります。その後、パイプラインはソースコードリポジトリから自身を最新の状態に保ち続けます。したがって、リポジトリ内のコードが、デプロイしたいコードであることを必ず確認してください。変更を確認して GitHub にプッシュし、デプロイします。

```
git add --all
git commit -m "initial commit"
git push
cdk deploy
```

**ヒント**  
最初のデプロイが完了したら、ローカル AWS アカウントには管理アクセスが不要になります。これは、アプリケーションへのすべての変更はパイプラインを介してデプロイされるためです。必要なのは GitHub にプッシュすることだけです。

## アプリケーションステージ
<a name="cdk-pipeline-stages"></a>

パイプラインに一度に追加できるマルチスタック AWS アプリケーションを定義するには、` [Stage](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.Stage.html) ` のサブクラスを定義します。(これは CDK Pipelines モジュールの `CdkStage` とは異なります。)

ステージには、アプリケーションを構成するスタックが含まれています。スタック間に依存関係がある場合、スタックはパイプラインに自動的に正しい順序で追加されます。相互に依存しないスタックは、並列にデプロイされます。`stack1.addDependency(stack2)` を呼び出すことで、スタック間に依存関係を追加できます。

ステージはデフォルトの `env` 引数を受け入れます。これは、その中のスタックのデフォルトの環境になります。(スタックには独自の環境を指定することもできます)。

アプリケーションをパイプラインに追加するには、[ステージ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.Stage.html)のインスタンスで ` [addStage()](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.pipelines.CodePipeline.html#addwbrstagestage-optionss) ` を呼び出します。ステージをインスタンス化してパイプラインに複数回追加することで、DTAP またはマルチリージョンアプリケーションパイプラインのさまざまなステージを定義できます。

シンプルな Lambda 関数を含むスタックを作成し、そのスタックをステージに配置します。次に、ステージをパイプラインに追加してデプロイできるようにします。

**Example**  
Lambda 関数を含むアプリケーションスタックを保持する新しいファイル `lib/my-pipeline-lambda-stack.ts` を作成します。  

```
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { Function, InlineCode, Runtime } from 'aws-cdk-lib/aws-lambda';

export class MyLambdaStack extends cdk.Stack {
    constructor(scope: Construct, id: string, props?: cdk.StackProps) {
      super(scope, id, props);

      new Function(this, 'LambdaFunction', {
        runtime: Runtime.NODEJS_18_X,
        handler: 'index.handler',
        code: new InlineCode('exports.handler = _ => "Hello, CDK";')
      });
    }
}
```
ステージを保持する新しいファイル `lib/my-pipeline-app-stage.ts` を作成します。  

```
import * as cdk from 'aws-cdk-lib';
import { Construct } from "constructs";
import { MyLambdaStack } from './my-pipeline-lambda-stack';

export class MyPipelineAppStage extends cdk.Stage {

    constructor(scope: Construct, id: string, props?: cdk.StageProps) {
      super(scope, id, props);

      const lambdaStack = new MyLambdaStack(this, 'LambdaStack');
    }
}
```
`lib/my-pipeline-stack.ts` を編集して、ステージをパイプラインに追加します。  

```
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { CodePipeline, CodePipelineSource, ShellStep } from 'aws-cdk-lib/pipelines';
import { MyPipelineAppStage } from './my-pipeline-app-stage';

export class MyPipelineStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const pipeline = new CodePipeline(this, 'Pipeline', {
      pipelineName: 'MyPipeline',
      synth: new ShellStep('Synth', {
        input: CodePipelineSource.gitHub('OWNER/REPO', 'main'),
        commands: ['npm ci', 'npm run build', 'npx cdk synth']
      })
    });

    pipeline.addStage(new MyPipelineAppStage(this, "test", {
      env: { account: "111111111111", region: "eu-west-1" }
    }));
  }
}
```
Lambda 関数を含むアプリケーションスタックを保持する新しいファイル `lib/my-pipeline-lambda-stack.js` を作成します。  

```
const cdk = require('aws-cdk-lib');
const { Function, InlineCode, Runtime } = require('aws-cdk-lib/aws-lambda');

class MyLambdaStack extends cdk.Stack {
    constructor(scope, id, props) {
      super(scope, id, props);

      new Function(this, 'LambdaFunction', {
        runtime: Runtime.NODEJS_18_X,
        handler: 'index.handler',
        code: new InlineCode('exports.handler = _ => "Hello, CDK";')
      });
    }
}

module.exports = { MyLambdaStack }
```
ステージを保持する新しいファイル `lib/my-pipeline-app-stage.js` を作成します。  

```
const cdk = require('aws-cdk-lib');
const { MyLambdaStack } = require('./my-pipeline-lambda-stack');

class MyPipelineAppStage extends cdk.Stage {

    constructor(scope, id, props) {
      super(scope, id, props);

      const lambdaStack = new MyLambdaStack(this, 'LambdaStack');
    }
}

module.exports = { MyPipelineAppStage };
```
`lib/my-pipeline-stack.ts` を編集して、ステージをパイプラインに追加します。  

```
const cdk = require('aws-cdk-lib');
const { CodePipeline, CodePipelineSource, ShellStep } = require('aws-cdk-lib/pipelines');
const { MyPipelineAppStage } = require('./my-pipeline-app-stage');

 class MyPipelineStack extends cdk.Stack {
  constructor(scope, id, props) {
    super(scope, id, props);

    const pipeline = new CodePipeline(this, 'Pipeline', {
      pipelineName: 'MyPipeline',
      synth: new ShellStep('Synth', {
        input: CodePipelineSource.gitHub('OWNER/REPO', 'main'),
        commands: ['npm ci', 'npm run build', 'npx cdk synth']
      })
    });

    pipeline.addStage(new MyPipelineAppStage(this, "test", {
      env: { account: "111111111111", region: "eu-west-1" }
    }));

  }
}

module.exports = { MyPipelineStack }
```
Lambda 関数を含むアプリケーションスタックを保持する新しいファイル `my_pipeline/my_pipeline_lambda_stack.py` を作成します。  

```
import aws_cdk as cdk
from constructs import Construct
from aws_cdk.aws_lambda import Function, InlineCode, Runtime

class MyLambdaStack(cdk.Stack):
    def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        Function(self, "LambdaFunction",
            runtime=Runtime.NODEJS_18_X,
            handler="index.handler",
            code=InlineCode("exports.handler = _ => 'Hello, CDK';")
        )
```
ステージを保持する新しいファイル `my_pipeline/my_pipeline_app_stage.py` を作成します。  

```
import aws_cdk as cdk
from constructs import Construct
from my_pipeline.my_pipeline_lambda_stack import MyLambdaStack

class MyPipelineAppStage(cdk.Stage):
    def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        lambdaStack = MyLambdaStack(self, "LambdaStack")
```
`my_pipeline/my-pipeline-stack.py` を編集して、ステージをパイプラインに追加します。  

```
import aws_cdk as cdk
from constructs import Construct
from aws_cdk.pipelines import CodePipeline, CodePipelineSource, ShellStep
from my_pipeline.my_pipeline_app_stage import MyPipelineAppStage

class MyPipelineStack(cdk.Stack):

    def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        pipeline =  CodePipeline(self, "Pipeline",
                        pipeline_name="MyPipeline",
                        synth=ShellStep("Synth",
                            input=CodePipelineSource.git_hub("OWNER/REPO", "main"),
                            commands=["npm install -g aws-cdk",
                                "python -m pip install -r requirements.txt",
                                "cdk synth"]))

        pipeline.add_stage(MyPipelineAppStage(self, "test",
            env=cdk.Environment(account="111111111111", region="eu-west-1")))
```
Lambda 関数を含むアプリケーションスタックを保持する新しいファイル `src/main/java/com.myorg/MyPipelineLambdaStack.java` を作成します。  

```
package com.myorg;

import software.constructs.Construct;
import software.amazon.awscdk.Stack;
import software.amazon.awscdk.StackProps;

import software.amazon.awscdk.services.lambda.Function;
import software.amazon.awscdk.services.lambda.Runtime;
import software.amazon.awscdk.services.lambda.InlineCode;

public class MyPipelineLambdaStack extends Stack {
    public MyPipelineLambdaStack(final Construct scope, final String id) {
        this(scope, id, null);
    }

    public MyPipelineLambdaStack(final Construct scope, final String id, final StackProps props) {
        super(scope, id, props);

        Function.Builder.create(this, "LambdaFunction")
          .runtime(Runtime.NODEJS_18_X)
          .handler("index.handler")
          .code(new InlineCode("exports.handler = _ => 'Hello, CDK';"))
          .build();

    }

}
```
ステージを保持する新しいファイル `src/main/java/com.myorg/MyPipelineAppStage.java` を作成します。  

```
package com.myorg;

import software.constructs.Construct;
import software.amazon.awscdk.Stack;
import software.amazon.awscdk.Stage;
import software.amazon.awscdk.StageProps;

public class MyPipelineAppStage extends Stage {
    public MyPipelineAppStage(final Construct scope, final String id) {
        this(scope, id, null);
    }

    public MyPipelineAppStage(final Construct scope, final String id, final StageProps props) {
        super(scope, id, props);

        Stack lambdaStack = new MyPipelineLambdaStack(this, "LambdaStack");
    }

}
```
`src/main/java/com.myorg/MyPipelineStack.java` を編集して、ステージをパイプラインに追加します。  

```
package com.myorg;

import java.util.Arrays;
import software.constructs.Construct;
import software.amazon.awscdk.Environment;
import software.amazon.awscdk.Stack;
import software.amazon.awscdk.StackProps;
import software.amazon.awscdk.StageProps;
import software.amazon.awscdk.pipelines.CodePipeline;
import software.amazon.awscdk.pipelines.CodePipelineSource;
import software.amazon.awscdk.pipelines.ShellStep;

public class MyPipelineStack extends Stack {
    public MyPipelineStack(final Construct scope, final String id) {
        this(scope, id, null);
    }

    public MyPipelineStack(final Construct scope, final String id, final StackProps props) {
        super(scope, id, props);

        final CodePipeline pipeline = CodePipeline.Builder.create(this, "pipeline")
            .pipelineName("MyPipeline")
            .synth(ShellStep.Builder.create("Synth")
                .input(CodePipelineSource.gitHub("OWNER/REPO", "main"))
                .commands(Arrays.asList("npm install -g aws-cdk", "cdk synth"))
                .build())
            .build();

        pipeline.addStage(new MyPipelineAppStage(this, "test", StageProps.builder()
            .env(Environment.builder()
                .account("111111111111")
                .region("eu-west-1")
                .build())
            .build()));
    }
}
```
Lambda 関数を含むアプリケーションスタックを保持する新しいファイル `src/MyPipeline/MyPipelineLambdaStack.cs` を作成します。  

```
using Amazon.CDK;
using Constructs;
using Amazon.CDK.AWS.Lambda;

namespace MyPipeline
{
    class MyPipelineLambdaStack : Stack
    {
        public MyPipelineLambdaStack(Construct scope, string id, StackProps props=null) : base(scope, id, props)
        {
            new Function(this, "LambdaFunction", new FunctionProps
            {
                Runtime = Runtime.NODEJS_18_X,
                Handler = "index.handler",
                Code = new InlineCode("exports.handler = _ => 'Hello, CDK';")
            });
        }
    }
}
```
ステージを保持する新しいファイル `src/MyPipeline/MyPipelineAppStage.cs` を作成します。  

```
using Amazon.CDK;
using Constructs;

namespace MyPipeline
{
    class MyPipelineAppStage : Stage
    {
        public MyPipelineAppStage(Construct scope, string id, StageProps props=null) : base(scope, id, props)
        {
            Stack lambdaStack = new MyPipelineLambdaStack(this, "LambdaStack");
        }
    }
}
```
`src/MyPipeline/MyPipelineStack.cs` を編集して、ステージをパイプラインに追加します。  

```
using Amazon.CDK;
using Constructs;
using Amazon.CDK.Pipelines;

namespace MyPipeline
{
    public class MyPipelineStack : Stack
    {
        internal MyPipelineStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props)
        {
            var pipeline = new CodePipeline(this, "pipeline", new CodePipelineProps
            {
                PipelineName = "MyPipeline",
                Synth = new ShellStep("Synth", new ShellStepProps
                {
                    Input = CodePipelineSource.GitHub("OWNER/REPO", "main"),
                    Commands = new string[] { "npm install -g aws-cdk", "cdk synth" }
                })
            });

            pipeline.AddStage(new MyPipelineAppStage(this, "test", new StageProps
            {
                Env = new Environment
                {
                    Account = "111111111111", Region = "eu-west-1"
                }
            }));
        }
    }
}
```

`addStage()` で追加されたすべてのアプリケーションステージは、`addStage()` コールで返された ` [StageDeployment](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.pipelines.StageDeployment.html) ` インスタンスで表される、対応するパイプラインステージを追加します。デプロイ前アクションまたはデプロイ後アクションは、`addPre()` または `addPost()` のメソッドを呼び出すことでステージに追加できます。

**Example**  

```
// import { ManualApprovalStep } from 'aws-cdk-lib/pipelines';

const testingStage = pipeline.addStage(new MyPipelineAppStage(this, 'testing', {
  env: { account: '111111111111', region: 'eu-west-1' }
}));

    testingStage.addPost(new ManualApprovalStep('approval'));
```

```
// const { ManualApprovalStep } = require('aws-cdk-lib/pipelines');

const testingStage = pipeline.addStage(new MyPipelineAppStage(this, 'testing', {
  env: { account: '111111111111', region: 'eu-west-1' }
}));

testingStage.addPost(new ManualApprovalStep('approval'));
```

```
# from aws_cdk.pipelines import ManualApprovalStep

testing_stage = pipeline.add_stage(MyPipelineAppStage(self, "testing",
    env=cdk.Environment(account="111111111111", region="eu-west-1")))

testing_stage.add_post(ManualApprovalStep('approval'))
```

```
// import software.amazon.awscdk.pipelines.StageDeployment;
// import software.amazon.awscdk.pipelines.ManualApprovalStep;

StageDeployment testingStage =
        pipeline.addStage(new MyPipelineAppStage(this, "test", StageProps.builder()
                .env(Environment.builder()
                        .account("111111111111")
                        .region("eu-west-1")
                        .build())
                .build()));

testingStage.addPost(new ManualApprovalStep("approval"));
```

```
var testingStage = pipeline.AddStage(new MyPipelineAppStage(this, "test", new StageProps
{
    Env = new Environment
    {
        Account = "111111111111", Region = "eu-west-1"
    }
}));

testingStage.AddPost(new ManualApprovalStep("approval"));
```

例えば複数のアカウントやリージョンにステージをデプロイする場合などは、` [Wave](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.pipelines.Wave.html) ` にステージを追加して並列にデプロイできます。

**Example**  

```
const wave = pipeline.addWave('wave');
wave.addStage(new MyApplicationStage(this, 'MyAppEU', {
  env: { account: '111111111111', region: 'eu-west-1' }
}));
wave.addStage(new MyApplicationStage(this, 'MyAppUS', {
  env: { account: '111111111111', region: 'us-west-1' }
}));
```

```
const wave = pipeline.addWave('wave');
wave.addStage(new MyApplicationStage(this, 'MyAppEU', {
  env: { account: '111111111111', region: 'eu-west-1' }
}));
wave.addStage(new MyApplicationStage(this, 'MyAppUS', {
  env: { account: '111111111111', region: 'us-west-1' }
}));
```

```
wave = pipeline.add_wave("wave")
wave.add_stage(MyApplicationStage(self, "MyAppEU",
    env=cdk.Environment(account="111111111111", region="eu-west-1")))
wave.add_stage(MyApplicationStage(self, "MyAppUS",
    env=cdk.Environment(account="111111111111", region="us-west-1")))
```

```
// import software.amazon.awscdk.pipelines.Wave;
final Wave wave = pipeline.addWave("wave");
wave.addStage(new MyPipelineAppStage(this, "MyAppEU", StageProps.builder()
        .env(Environment.builder()
                .account("111111111111")
                .region("eu-west-1")
                .build())
        .build()));
wave.addStage(new MyPipelineAppStage(this, "MyAppUS", StageProps.builder()
        .env(Environment.builder()
                .account("111111111111")
                .region("us-west-1")
                .build())
        .build()));
```

```
var wave = pipeline.AddWave("wave");
wave.AddStage(new MyPipelineAppStage(this, "MyAppEU", new StageProps
{
    Env = new Environment
    {
        Account = "111111111111", Region = "eu-west-1"
    }
}));
wave.AddStage(new MyPipelineAppStage(this, "MyAppUS", new StageProps
{
    Env = new Environment
    {
        Account = "111111111111", Region = "us-west-1"
    }
}));
```

## デプロイのテスト
<a name="cdk-pipeline-validation"></a>

CDK Pipeline にステップを追加して、実行しているデプロイを検証できます。例えば、CDK Pipeline ライブラリの ` [ShellStep](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.pipelines.ShellStep.html) ` を使用して、以下のようなタスクを実行できます。
+ Lambda 関数にバックアップされた新しくデプロイされた Amazon API Gateway へのアクセスを試みる
+ AWS CLI コマンドを実行してデプロイされたリソースの設定を確認する

最もシンプルな形式では、検証アクションの追加は以下のようになります。

**Example**  

```
// stage was returned by pipeline.addStage

stage.addPost(new ShellStep("validate", {
  commands: ['../tests/validate.sh'],
}));
```

```
// stage was returned by pipeline.addStage

stage.addPost(new ShellStep("validate", {
  commands: ['../tests/validate.sh'],
}));
```

```
# stage was returned by pipeline.add_stage

stage.add_post(ShellStep("validate",
  commands=[''../tests/validate.sh'']
))
```

```
// stage was returned by pipeline.addStage

stage.addPost(ShellStep.Builder.create("validate")
        .commands(Arrays.asList("'../tests/validate.sh'"))
        .build());
```

```
// stage was returned by pipeline.addStage

stage.AddPost(new ShellStep("validate", new ShellStepProps
{
    Commands = new string[] { "'../tests/validate.sh'" }
}));
```

多くの AWS CloudFormation デプロイでは、予測不可能な名前のリソースが生成されます。このため、CDK Pipelines はデプロイ後に AWS CloudFormation 出力を読み取る方法を提供します。これにより、生成されたロードバランサーの URL を (たとえば) テストアクションに渡すことができます。

出力を使用するには、関心のある `CfnOutput` オブジェクトを公開します。次に、ステップの `envFromCfnOutputs` プロパティに渡して、そのステップ内の環境変数として使用可能にします。

**Example**  

```
// given a stack lbStack that exposes a load balancer construct as loadBalancer
this.loadBalancerAddress = new cdk.CfnOutput(lbStack, 'LbAddress', {
  value: `https://${lbStack.loadBalancer.loadBalancerDnsName}/`
});

// pass the load balancer address to a shell step
stage.addPost(new ShellStep("lbaddr", {
  envFromCfnOutputs: {lb_addr: lbStack.loadBalancerAddress},
  commands: ['echo $lb_addr']
}));
```

```
// given a stack lbStack that exposes a load balancer construct as loadBalancer
this.loadBalancerAddress = new cdk.CfnOutput(lbStack, 'LbAddress', {
  value: `https://${lbStack.loadBalancer.loadBalancerDnsName}/`
});

// pass the load balancer address to a shell step
stage.addPost(new ShellStep("lbaddr", {
  envFromCfnOutputs: {lb_addr: lbStack.loadBalancerAddress},
  commands: ['echo $lb_addr']
}));
```

```
# given a stack lb_stack that exposes a load balancer construct as load_balancer
self.load_balancer_address = cdk.CfnOutput(lb_stack, "LbAddress",
    value=f"https://{lb_stack.load_balancer.load_balancer_dns_name}/")

# pass the load balancer address to a shell step
stage.add_post(ShellStep("lbaddr",
    env_from_cfn_outputs={"lb_addr": lb_stack.load_balancer_address}
    commands=["echo $lb_addr"]))
```

```
// given a stack lbStack that exposes a load balancer construct as loadBalancer
loadBalancerAddress = CfnOutput.Builder.create(lbStack, "LbAddress")
                            .value(String.format("https://%s/",
                                    lbStack.loadBalancer.loadBalancerDnsName))
                            .build();

stage.addPost(ShellStep.Builder.create("lbaddr")
    .envFromCfnOutputs(     // Map.of requires Java 9 or later
        java.util.Map.of("lbAddr", loadBalancerAddress))
    .commands(Arrays.asList("echo $lbAddr"))
    .build());
```

```
// given a stack lbStack that exposes a load balancer construct as loadBalancer
loadBalancerAddress = new CfnOutput(lbStack, "LbAddress", new CfnOutputProps
{
    Value = string.Format("https://{0}/", lbStack.loadBalancer.LoadBalancerDnsName)
});

stage.AddPost(new ShellStep("lbaddr", new ShellStepProps
{
    EnvFromCfnOutputs = new Dictionary<string, CfnOutput>
    {
        {  "lbAddr", loadBalancerAddress }
    },
    Commands = new string[] { "echo $lbAddr" }
}));
```

`ShellStep` で簡単な検証テストを記述することはできますが、テストが数行を超えると、このアプローチは扱いにくくなります。より複雑なテストでは、`inputs` プロパティを介して追加のファイル (完全なシェルスクリプト、他の言語のプログラムなど) を `ShellStep` に持ち込むことができます。入力は、ソース (GitHub リポジトリなど) や別の `ShellStep` など、出力を持つ任意のステップにすることができます。

ソースリポジトリからファイルを取り込むのは、ファイルがテストで直接使用できる場合 (たとえば、ファイル自体が実行可能である場合) に適しています。この例では、GitHub リポジトリを (`CodePipeline` の一部としてインラインでインスタンス化するのではなく) `source` として宣言します。次に、このファイルセットをパイプラインと検証テストの両方に渡します。

**Example**  

```
const source = CodePipelineSource.gitHub('OWNER/REPO', 'main');

const pipeline = new CodePipeline(this, 'Pipeline', {
  pipelineName: 'MyPipeline',
  synth: new ShellStep('Synth', {
    input: source,
    commands: ['npm ci', 'npm run build', 'npx cdk synth']
  })
});

const stage = pipeline.addStage(new MyPipelineAppStage(this, 'test', {
  env: { account: '111111111111', region: 'eu-west-1' }
}));

stage.addPost(new ShellStep('validate', {
  input: source,
  commands: ['sh ../tests/validate.sh']
}));
```

```
const source = CodePipelineSource.gitHub('OWNER/REPO', 'main');

const pipeline = new CodePipeline(this, 'Pipeline', {
  pipelineName: 'MyPipeline',
  synth: new ShellStep('Synth', {
    input: source,
    commands: ['npm ci', 'npm run build', 'npx cdk synth']
  })
});

const stage = pipeline.addStage(new MyPipelineAppStage(this, 'test', {
  env: { account: '111111111111', region: 'eu-west-1' }
}));

stage.addPost(new ShellStep('validate', {
  input: source,
  commands: ['sh ../tests/validate.sh']
}));
```

```
source   = CodePipelineSource.git_hub("OWNER/REPO", "main")

pipeline =  CodePipeline(self, "Pipeline",
                pipeline_name="MyPipeline",
                synth=ShellStep("Synth",
                    input=source,
                    commands=["npm install -g aws-cdk",
                        "python -m pip install -r requirements.txt",
                        "cdk synth"]))

stage = pipeline.add_stage(MyApplicationStage(self, "test",
            env=cdk.Environment(account="111111111111", region="eu-west-1")))

stage.add_post(ShellStep("validate", input=source,
    commands=["sh ../tests/validate.sh"],
))
```

```
final CodePipelineSource source = CodePipelineSource.gitHub("OWNER/REPO", "main");

final CodePipeline pipeline = CodePipeline.Builder.create(this, "pipeline")
        .pipelineName("MyPipeline")
        .synth(ShellStep.Builder.create("Synth")
                .input(source)
                .commands(Arrays.asList("npm install -g aws-cdk", "cdk synth"))
                .build())
        .build();

final StageDeployment stage =
        pipeline.addStage(new MyPipelineAppStage(this, "test", StageProps.builder()
                .env(Environment.builder()
                        .account("111111111111")
                        .region("eu-west-1")
                        .build())
                .build()));

stage.addPost(ShellStep.Builder.create("validate")
        .input(source)
        .commands(Arrays.asList("sh ../tests/validate.sh"))
        .build());
```

```
var source = CodePipelineSource.GitHub("OWNER/REPO", "main");

var pipeline = new CodePipeline(this, "pipeline", new CodePipelineProps
{
    PipelineName = "MyPipeline",
    Synth = new ShellStep("Synth", new ShellStepProps
    {
        Input = source,
        Commands = new string[] { "npm install -g aws-cdk", "cdk synth" }
    })
});

var stage = pipeline.AddStage(new MyPipelineAppStage(this, "test", new StageProps
{
    Env = new Environment
    {
        Account = "111111111111", Region = "eu-west-1"
    }
}));

stage.AddPost(new ShellStep("validate", new ShellStepProps
{
    Input = source,
    Commands = new string[] { "sh ../tests/validate.sh" }
}));
```

合成ステップから追加のファイルを取得することは、合成の一部として行われるテストをコンパイルする必要がある場合に適しています。

**Example**  

```
const synthStep = new ShellStep('Synth', {
  input: CodePipelineSource.gitHub('OWNER/REPO', 'main'),
  commands: ['npm ci', 'npm run build', 'npx cdk synth'],
});

const pipeline = new CodePipeline(this, 'Pipeline', {
  pipelineName: 'MyPipeline',
  synth: synthStep
});

const stage = pipeline.addStage(new MyPipelineAppStage(this, 'test', {
  env: { account: '111111111111', region: 'eu-west-1' }
}));

// run a script that was transpiled from TypeScript during synthesis
stage.addPost(new ShellStep('validate', {
  input: synthStep,
  commands: ['node tests/validate.js']
}));
```

```
const synthStep = new ShellStep('Synth', {
  input: CodePipelineSource.gitHub('OWNER/REPO', 'main'),
  commands: ['npm ci', 'npm run build', 'npx cdk synth'],
});

const pipeline = new CodePipeline(this, 'Pipeline', {
  pipelineName: 'MyPipeline',
  synth: synthStep
});

const stage = pipeline.addStage(new MyPipelineAppStage(this, "test", {
  env: { account: "111111111111", region: "eu-west-1" }
}));

// run a script that was transpiled from TypeScript during synthesis
stage.addPost(new ShellStep('validate', {
  input: synthStep,
  commands: ['node tests/validate.js']
}));
```

```
synth_step = ShellStep("Synth",
                input=CodePipelineSource.git_hub("OWNER/REPO", "main"),
                commands=["npm install -g aws-cdk",
                  "python -m pip install -r requirements.txt",
                  "cdk synth"])

pipeline   = CodePipeline(self, "Pipeline",
                pipeline_name="MyPipeline",
                synth=synth_step)

stage = pipeline.add_stage(MyApplicationStage(self, "test",
            env=cdk.Environment(account="111111111111", region="eu-west-1")))

# run a script that was compiled during synthesis
stage.add_post(ShellStep("validate",
    input=synth_step,
    commands=["node test/validate.js"],
))
```

```
final ShellStep synth = ShellStep.Builder.create("Synth")
                            .input(CodePipelineSource.gitHub("OWNER/REPO", "main"))
                            .commands(Arrays.asList("npm install -g aws-cdk", "cdk synth"))
                            .build();

final CodePipeline pipeline = CodePipeline.Builder.create(this, "pipeline")
        .pipelineName("MyPipeline")
        .synth(synth)
        .build();

final StageDeployment stage =
        pipeline.addStage(new MyPipelineAppStage(this, "test", StageProps.builder()
                .env(Environment.builder()
                        .account("111111111111")
                        .region("eu-west-1")
                        .build())
                .build()));

stage.addPost(ShellStep.Builder.create("validate")
        .input(synth)
        .commands(Arrays.asList("node ./tests/validate.js"))
        .build());
```

```
var synth = new ShellStep("Synth", new ShellStepProps
{
    Input = CodePipelineSource.GitHub("OWNER/REPO", "main"),
    Commands = new string[] { "npm install -g aws-cdk", "cdk synth" }
});

var pipeline = new CodePipeline(this, "pipeline", new CodePipelineProps
{
    PipelineName = "MyPipeline",
    Synth = synth
});

var stage = pipeline.AddStage(new MyPipelineAppStage(this, "test", new StageProps
{
    Env = new Environment
    {
        Account = "111111111111", Region = "eu-west-1"
    }
}));

stage.AddPost(new ShellStep("validate", new ShellStepProps
{
    Input = synth,
    Commands = new string[] { "node ./tests/validate.js" }
}));
```

## セキュリティ上の考慮事項
<a name="cdk-pipeline-security"></a>

どのような形の継続的デリバリーにも、固有のセキュリティリスクがあります。AWS [責任共有モデル](https://aws.amazon.com/compliance/shared-responsibility-model/)では、AWS クラウド内の情報のセキュリティにはユーザーが責任を担います。CDK Pipelines ライブラリは、セキュアなデフォルト値とモデリングのベストプラクティスを組み込むことで、開発を迅速に開始できます。

ただし、その性質上、意図した目的を達成するために高レベルのアクセスを必要とするライブラリは、完全なセキュリティを保証することはできません。AWS および組織の外には多くの攻撃ベクトルが存在します。

特に、次の点に注意してください。
+ 使用するソフトウェアに注意してください。パイプラインで実行するすべてのサードパーティーソフトウェアを検証します。これは、デプロイされるインフラストラクチャが変更される可能性があるためです。
+ 依存関係ロックを使用して、予期せぬアップグレードを防止します。CDK Pipelines は、依存関係が想定どおりのものであるよう、 `package-lock.json` と `yarn.lock` を遵守します。
+ CDK Pipelines は、独自のアカウントで作成されたリソースで実行され、それらのリソースの設定は、パイプラインを介してコードを送信する開発者によって制御されます。したがって、CDK Pipelines 自体は、コンプライアンスチェックをバイパスしようとする悪意のある開発者から保護することはできません。脅威モデルに CDK コードを記述する開発者が含まれている場合は、AWS CloudFormation 実行ロールに無効化するアクセス許可がない [AWS CloudFormation Hooks](https://aws.amazon.com/blogs/mt/proactively-keep-resources-secure-and-compliant-with-aws-cloudformation-hooks/) (予防) や [AWS Config](https://aws.amazon.com/config/) (事後対応) などの外部コンプライアンスメカニズムが必要です。
+ 本番稼働環境の認証情報は、有効期間が短くなければなりません。ブートストラップと初期プロビジョニングの後、開発者がアカウント認証情報を持つ必要はありません。変更はパイプラインを通じてデプロイできます。そもそも認証情報を必要とせず、認証情報が漏洩する可能性を減らします。

## トラブルシューティング
<a name="cdk-pipeline-troubleshooting"></a>

CDK Pipelines の使用を開始する際に、一般的に発生する問題は次のとおりです。

 **パイプライン: 内部障害**   

```
CREATE_FAILED  | {aws}::CodePipeline::Pipeline | Pipeline/Pipeline
Internal Failure
```
GitHub アクセストークンを確認します。欠落しているか、リポジトリにアクセスするアクセス許可がない可能性があります。

 **キーポリシーに 1 つ以上の無効なプリンシパルを含むステートメントが含まれています**   

```
CREATE_FAILED | {aws}::KMS::Key | Pipeline/Pipeline/ArtifactsBucketEncryptionKey
Policy contains a statement with one or more invalid principals.
```
ターゲット環境の 1 つが新しいブートストラップスタックでブートストラップされていません。すべてのターゲット環境がブートストラップされていることを確認します。

 **スタックは ROLLBACK\$1COMPLETE 状態であり、更新できません**   

```
Stack <STACK_NAME> is in ROLLBACK_COMPLETE state and cannot be updated. (Service:
AmazonCloudFormation; Status Code: 400; Error Code: ValidationError; Request
ID: ...)
```
スタックは以前のデプロイに失敗し、再試行不可能な状態です。AWS CloudFormation コンソールからスタックを削除し、デプロイを再試行します。

# CDK アプリでコンテナイメージアセットを構築してデプロイする
<a name="build-containers"></a>

AWS Cloud Development Kit (AWS CDK) を使用してコンテナイメージアセットを構築する場合、Docker はデフォルトでこれらのアクションを実行するために利用されます。別のコンテナ管理ツールを使用する場合は、`CDK_DOCKER` 環境変数を使用して Docker を置き換えることができます。

## 例: AWS CDK を使用してコンテナイメージアセットを構築して公開する
<a name="build-containers-intro-example"></a>

以下は、デフォルトで Docker を使用してコンテナアセットを構築して Amazon Elastic Container Registry (Amazon ECR) に公開する AWS CDK アプリの簡単な例です。

 **プロジェクトの構造**   

```
my-cdk-app/
├── lib/
│   ├── my-stack.ts
│   └── docker/
│       ├── Dockerfile
│       └── app/
│           └── index.js
├── bin/
│   └── my-cdk-app.ts
├── package.json
├── tsconfig.json
└── cdk.json
```

 **Dockerfile**:   

```
FROM public.ecr.aws/lambda/nodejs:16

# Copy application code
COPY app/ /var/task/

# (Optional) Install dependencies
# RUN npm install

# The Lambda Node.js base image looks for index.handler by default
```

 **アプリケーションコード**   
`lib/docker/app/index.js` に作成  

```
console.log("Hello from inside the container!");
```

 **CDK スタック**   

```
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as ecr_assets from 'aws-cdk-lib/aws-ecr-assets';

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

    // Define a Docker image asset
    const dockerImageAsset = new ecr_assets.DockerImageAsset(this, 'MyDockerImage', {
      directory: 'lib/docker', // Path to the directory containing the Dockerfile
    });

    // Output the ECR URI
    new cdk.CfnOutput(this, 'ECRImageUri', {
      value: dockerImageAsset.imageUri,
    });
  }
}
```

 **CDK アプリ**   

```
#!/usr/bin/env node
import * as cdk from 'aws-cdk-lib';
import { MyStack } from '../lib/my-stack';

const app = new cdk.App();
new MyStack(app, 'MyStack');
```

`cdk deploy` を実行すると、AWS Cloud Development Kit (AWS CDK) コマンドラインインターフェイス (CLI) は以下を行います。

1.  **Docker イメージを構築する** – 指定されたディレクトリ (`lib/docker`) の `Dockerfile` に基づいてローカルで `docker build` を実行します。

1.  **イメージにタグを付ける** – `docker tag` を実行して、イメージの内容に基づいて構築されたイメージに一意のハッシュをタグ付けします。

1.  **Amazon ECR に発行する** – `docker push` を実行して、コンテナイメージを Amazon ECR リポジトリに発行します。このリポジトリは既に存在している必要があります。これは、デフォルトのブートストラッププロセス中に作成されます。

1.  **イメージ URI を出力する** – デプロイが成功すると、発行されたコンテナイメージの Amazon ECR URI がコマンドプロンプトに出力されます。これは Amazon ECR にある Docker イメージの URI です。

## Docker を別のコンテナ管理ツールに置き換える方法
<a name="build-container-replace"></a>

`CDK_DOCKER` 環境変数を使用して、置き換えコンテナ管理ツールのバイナリへのパスを指定します。Docker を Finch に置き換える例を次に示します。

```
$ which finch
/usr/local/bin/finch # Locate the path to the binary

$ export CDK_DOCKER='/usr/local/bin/finch' # Set the environment variable

$ cdk deploy # Deploy using the replacement
```

エイリアスまたはリンクはサポートされていません。Docker を置き換えるには、`CDK_DOCKER` 環境変数を使用する必要があります。

## サポートされている Docker ドロップイン置き換えエンジン
<a name="build-container-supported"></a>

 Finch はサポートされていますが、使用できない Docker 機能がある場合や、ツールの進化に応じて動作が異なる場合があります。Finch の詳細については、「*AWS オープンソースブログ*」の「[飛行の準備ができました: Finch 1.0 GA のアナウンス\$1](https://aws.amazon.com/blogs/opensource/ready-for-flight-announcing-finch-1-0-ga/)」を参照してください。

他のコンテナ管理ツールは、機能する場合があります。CDK は、どの Docker 置き換えが、それがサポートされているかどうかを判断するために使用されているかを確認しません。ツールが同等の Docker コマンドを持ち、同様に動作する場合は、そのツールは機能するはずです。

# AWS CDK デプロイのトラブルシューティング
<a name="deploy-troubleshoot"></a>

AWS Cloud Development Kit (AWS CDK) アプリケーションをデプロイする際の一般的な問題をトラブルシューティングします。

## デプロイ時に間違ったサービスプリンシパルが作成される
<a name="deploy-troubleshoot-sp"></a>

サービスプリンシパルを持つ AWS Identity and Access Management (IAM) ロールを含む CDK アプリケーションをデプロイする際、サービスプリンシパルのドメインが正しく作成されていないことがわかったとします。

以下は、Amazon CloudWatch Logs がサービスプリンシパルを使用して引き受けることができる IAM ロールを作成する場合の基本的な例です。

```
import * as cdk from 'aws-cdk-lib';
import * as iam from 'aws-cdk-lib/aws-iam';
import { Construct } from 'constructs';

export class MyCdkProjectStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // Create an IAM role for CloudWatch Logs to assume
    const cloudWatchLogsRole = new iam.Role(this, 'CloudWatchLogsRole', {
      assumedBy: new iam.ServicePrincipal('logs.amazonaws.com'), // This is for CloudWatch Logs
      managedPolicies: [
        iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSCloudWatchLogsFullAccess')
      ]
    });

    // You can then use this role in other constructs or configurations where CloudWatch Logs needs to assume a role
  }
}
```

このスタックをデプロイすると、`logs.amazonaws.com` という名前のサービスプリンシパルが作成されるはずです。ほとんどの場合、AWS のサービスではサービスプリンシパルに `<service>.amazonaws.com` という名前が使用されます。

### 一般的な原因
<a name="deploy-troubleshoot-sp-causes"></a>

v2.150.0 より前のバージョンの AWS CDK を使用している場合、このバグが発生する可能性があります。AWS CDK の古いバージョンでは、サービスプリンシパルの命名が標準化されていないため、ドメインが正しくないサービスプリンシパルが作成される可能性があります。

AWS CDK v2.51.0 では、自動的に作成されるすべてのサービスプリンシパルが可能な限り `<service>.amazonaws.com` を使用するように標準化するという修正が実装されました。この修正は、`@aws-cdk/aws-iam:standardizedServicePrincipals` 機能フラグを許可することで利用できます。

AWS CDK v2.150.0 以降、これはデフォルトの動作になりました。

### 解決方法
<a name="deploy-troubleshoot-sp-resolution"></a>

AWS CDK v2.150.0 以降にアップグレードします。

AWS CDK v2.150.0 以降にアップグレードできない場合は、最低でも v2.51.0 以降にアップグレードする必要があります。次に、`cdk.json` ファイルで機能フラグ `@aws-cdk/aws-iam:standardizedServicePrincipals` を許可します。