AWS CDK の Workshop をやってみた

# はじめに

AWS Cloud Development Kit (AWS CDK) は、使い慣れたプログラミング言語を使用してクラウドアプリケーションリソースを定義するためのオープンソースのソフトウェア開発フレームワークです。いわゆる、IaC (Infrastructure as a Code) を実現するための一つの選択肢になっています。

IaC といえば、CloudFormation も有力な選択肢の一つですが、CloudFormation と比較した CDK の主なメリットは以下の通りです。

- 一般的なプログラミング言語で利用可能
- コードの量が少なくなる
- テストコードが記述可能



AWS CDK は、2022年2月現在、次の言語で利用可能です。

- TypeScript
- JavaScript
- Python
- Java
- C#
- Go (Developer Preview) : 本番利用には適していない。

https://docs.aws.amazon.com/ja_jp/cdk/v2/guide/work-with.html

上記の言語のライブラリとして、AWS CDK を扱えるため、if 文による分岐やループなど、プログラマブルな制御が出来るようになります。

また、CDK では記述量が少ないという特徴があります。CloudFormation を使って、S3 バケットを生成してIAM User に権限を紐づけるときのコード例は次の通りです。

![image-20220213150701593.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/4c83be8e-18f8-bf97-4d18-5eb27bb2d6f5.png)



これを CDK で表現すると次の通りです。非常に完結で読みやすい形で記述できることがわかります。

![image-20220213150748973.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/45a9336b-b32b-4198-4940-e0ed1bdf10e5.png)



今回の記事は、便利な CDK を学ぶための以下のワークショップを一部実施する内容になっています。

https://catalog.us-east-1.prod.workshops.aws/v2/workshops/99731164-1d19-4d2e-9319-727a130e2d57/ja-JP/

ワークショップの内容は、AWS CDK v1 で記載されています。2021年12月には、AWS CDK v2 が新たに GA になりました。今回の記事では、AWS CDK v2 を扱うため、一部内容を修正しています。



# 前提条件

この記事では、次のツールがインストールされている Linux 環境があることを前提にしています。

- AWS CLI
- AWSアカウントとユーザー
- Node.js
- IDE : Visual Studio を使用
- AWS CDKツールキット



AWS CLI のバージョンを確認

```
> aws --version
aws-cli/2.4.7 Python/3.8.8 Linux/4.14.252-195.483.amzn2.x86_64 exe/x86_64.amzn.2 prompt/off
```



Node.js

```
> node --version
v16.13.0
```



CDK ツールキットのインストール

```
sudo su -
npm install -g aws-cdk
```



CDK ツールキットのVersion

```
> cdk --version
2.12.0 (build c9786db)
```



# 新しいプロジェクトの作成

この章では、 `cdk init` コマンドを使用し、新しいAWS CDK TypeScriptプロジェクトを作成します。

また、CDK Toolkitを使用してスターターアプリ用のAWS CloudFormation テンプレートを生成する方法と、アプリをAWSにデプロイする方法についても学習します。



## cdk init

プロジェクト用のディレクトリを作成します

```
mkdir ~/temp/cdk-workshop
cd ~/temp/cdk-workshop
```



TypeScript 用の CDK プロジェクトを作成します。

```
cdk init sample-app --language typescript
```



実行例

```
Executing npm install...
npm notice Beginning October 4, 2021, all connections to the npm registry - including for package installation - must use TLS 1.2 or higher. You are currently using plaintext http to connect. Please visit the GitHub blog for more information: https://github.blog/2021-08-23-npm-registry-deprecating-tls-1-0-tls-1-1/
npm notice Beginning October 4, 2021, all connections to the npm registry - including for package installation - must use TLS 1.2 or higher. You are currently using plaintext http to connect. Please visit the GitHub blog for more information: https://github.blog/2021-08-23-npm-registry-deprecating-tls-1-0-tls-1-1/
npm WARN deprecated source-map-url@0.4.1: See https://github.com/lydell/source-map-url#deprecated
npm WARN deprecated urix@0.1.0: Please see https://github.com/lydell/urix#deprecated
npm WARN deprecated resolve-url@0.2.1: https://github.com/lydell/resolve-url#deprecated
npm WARN deprecated source-map-resolve@0.5.3: See https://github.com/lydell/source-map-resolve#deprecated
npm WARN deprecated sane@4.1.0: some dependency vulnerabilities fixed, support for node < 10 dropped, and newer ECMAScript syntax/features added
✅ All done!
```



いろいろ生成されました

```
> ls -la
total 616
drwxr-xr-x   7 ec2-user docker    229 Feb 12 18:53 .
drwxrwxr-x  35 ec2-user docker   4096 Feb 12 18:52 ..
drwxr-xr-x   2 ec2-user docker     29 Feb 12 18:53 bin
-rw-r--r--   1 ec2-user docker    837 Feb 12 18:53 cdk.json
drwxr-xr-x   8 ec2-user docker    166 Feb 12 18:53 .git
-rw-r--r--   1 ec2-user docker     93 Feb 12 18:53 .gitignore
-rw-r--r--   1 ec2-user docker    157 Feb 12 18:53 jest.config.js
drwxr-xr-x   2 ec2-user docker     35 Feb 12 18:53 lib
drwxr-xr-x 360 ec2-user docker  12288 Feb 12 18:53 node_modules
-rw-r--r--   1 ec2-user docker     65 Feb 12 18:53 .npmignore
-rw-r--r--   1 ec2-user docker    507 Feb 12 18:53 package.json
-rw-r--r--   1 ec2-user docker 580214 Feb 12 18:53 package-lock.json
-rw-r--r--   1 ec2-user docker    684 Feb 12 18:53 README.md
drwxr-xr-x   2 ec2-user docker     34 Feb 12 18:53 test
-rw-r--r--   1 ec2-user docker    650 Feb 12 18:53 tsconfig.json
```





## npm run watch

新しい Terminal を起動して、プロジェクトのディレクトリに移動します。

```
cd ~/temp/cdk-workshop/
```



npm run watch を実行します

```
npm run watch
```



実行例

```
[7:02:56 PM] File change detected. Starting incremental compilation...

[7:02:56 PM] Found 0 errors. Watching for file changes.
```



これにより、TypeScriptコンパイラ（tsc）が"watch"モードで起動し、プロジェクトディレクトリが監視され、`.ts`ファイルへの変更が自動的に`.js`へコンパイルされます。

この `npm run watch` を実行した Terminal は開いたままにします。



## プロジェクト構造

`lib/cdk-workshop-stack.ts`を開いてみましょう。これがアプリケーションの要です。

![image-20220213114724417.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/7f8bd648-8af7-9d8c-489f-a363b6dad002.png)



ご覧のとおり、アプリはサンプルCDKスタック(`CdkWorkshopStack`)です.

このスタックは次のものを含みます。

- SQS キュー (`new sqs.Queue`)
- SNS トピック (`new sns.Topic`)
- キューをサブスクライブして、トピックに発行されたメッセージを受信します (`topic.addSubscription`)



## cdk synth

AWS CDKアプリ自体はコードを使用したインフラストラクチャの **定義** にすぎません。CDKアプリが実行されると、アプリケーションで定義された各スタックのAWS CloudFormationテンプレートが生成（CDKの用語では "**synthesize**" ）されます。

CDKアプリを生成するには、 `cdk synth` コマンドを実行してください。サンプルアプリから生成されたCloudFormationテンプレートを確認してみましょう。

```
cdk synth
```



コマンド実行例

- CloudFormation Template が出力されています

```
Resources:
  CdkWorkshopQueue50D9D426:
    Type: AWS::SQS::Queue
    Properties:
      VisibilityTimeout: 300
    UpdateReplacePolicy: Delete
    DeletionPolicy: Delete
    Metadata:
      aws:cdk:path: CdkWorkshopStack/CdkWorkshopQueue/Resource
  CdkWorkshopQueuePolicyAF2494A5:
    Type: AWS::SQS::QueuePolicy
    Properties:
      PolicyDocument:
        Statement:
          - Action: sqs:SendMessage
            Condition:
              ArnEquals:
                aws:SourceArn:
                  Ref: CdkWorkshopTopicD368A42F
            Effect: Allow
            Principal:
              Service: sns.amazonaws.com
            Resource:
              Fn::GetAtt:
                - CdkWorkshopQueue50D9D426
                - Arn
        Version: "2012-10-17"
      Queues:
        - Ref: CdkWorkshopQueue50D9D426
    Metadata:
      aws:cdk:path: CdkWorkshopStack/CdkWorkshopQueue/Policy/Resource
  CdkWorkshopQueueCdkWorkshopStackCdkWorkshopTopicD7BE96438B5AD106:
    Type: AWS::SNS::Subscription
    Properties:
      Protocol: sqs
      TopicArn:
        Ref: CdkWorkshopTopicD368A42F
      Endpoint:
        Fn::GetAtt:
          - CdkWorkshopQueue50D9D426
          - Arn
    Metadata:
      aws:cdk:path: CdkWorkshopStack/CdkWorkshopQueue/CdkWorkshopStackCdkWorkshopTopicD7BE9643/Resource
  CdkWorkshopTopicD368A42F:
    Type: AWS::SNS::Topic
    Metadata:
      aws:cdk:path: CdkWorkshopStack/CdkWorkshopTopic/Resource
  CDKMetadata:
    Type: AWS::CDK::Metadata
    Properties:
      Analytics: v2:deflate64:H4sIAAAAAAAA/1WOQQ7CIBBFz+IeRqmJF+gFtHVvWsBk2gqVAY0h3F2giYmbmfdffjLTgGjgsBvexKWa+YIjxN4PcmZZ3SI9CeIl6KBZezcb1Hm2C8rPT24xMTK534eRpMPVozWl8ZevdkVZbIWUCnaabHCy3mitUViaiRmrNEy0f4kTiGP+ciJE7oLx+NDQbfsLtH5wMMEAAAA=
    Metadata:
      aws:cdk:path: CdkWorkshopStack/CDKMetadata/Default
    Condition: CDKMetadataAvailable
Conditions:
  CDKMetadataAvailable:
    Fn::Or:
      - Fn::Or:
          - Fn::Equals:
              - Ref: AWS::Region
              - af-south-1
          - Fn::Equals:
              - Ref: AWS::Region
              - ap-east-1
          - Fn::Equals:
              - Ref: AWS::Region
              - ap-northeast-1
          - Fn::Equals:
              - Ref: AWS::Region
              - ap-northeast-2
          - Fn::Equals:
              - Ref: AWS::Region
              - ap-south-1
          - Fn::Equals:
              - Ref: AWS::Region
              - ap-southeast-1
          - Fn::Equals:
              - Ref: AWS::Region
              - ap-southeast-2
          - Fn::Equals:
              - Ref: AWS::Region
              - ca-central-1
          - Fn::Equals:
              - Ref: AWS::Region
              - cn-north-1
          - Fn::Equals:
              - Ref: AWS::Region
              - cn-northwest-1
      - Fn::Or:
          - Fn::Equals:
              - Ref: AWS::Region
              - eu-central-1
          - Fn::Equals:
              - Ref: AWS::Region
              - eu-north-1
          - Fn::Equals:
              - Ref: AWS::Region
              - eu-south-1
          - Fn::Equals:
              - Ref: AWS::Region
              - eu-west-1
          - Fn::Equals:
              - Ref: AWS::Region
              - eu-west-2
          - Fn::Equals:
              - Ref: AWS::Region
              - eu-west-3
          - Fn::Equals:
              - Ref: AWS::Region
              - me-south-1
          - Fn::Equals:
              - Ref: AWS::Region
              - sa-east-1
          - Fn::Equals:
              - Ref: AWS::Region
              - us-east-1
          - Fn::Equals:
              - Ref: AWS::Region
              - us-east-2
      - Fn::Or:
          - Fn::Equals:
              - Ref: AWS::Region
              - us-west-1
          - Fn::Equals:
              - Ref: AWS::Region
              - us-west-2
Parameters:
  BootstrapVersion:
    Type: AWS::SSM::Parameter::Value<String>
    Default: /cdk-bootstrap/hnb659fds/version
    Description: Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]
Rules:
  CheckBootstrapVersion:
    Assertions:
      - Assert:
          Fn::Not:
            - Fn::Contains:
                - - "1"
                  - "2"
                  - "3"
                  - "4"
                  - "5"
                - Ref: BootstrapVersion
        AssertDescription: CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI.
```



ご覧のとおり、このテンプレートには4つのリソースが含まれています。

- **AWS::SQS::Queue** - キュー
- **AWS::SNS::Topic** - トピック
- **AWS::SNS::Subscription** - キューとトピックの間のサブスクリプション
- **AWS::SQS::QueuePolicy** - このトピックがメッセージをキューに送信できるようにするIAMポリシー



## cdk deploy

CloudFormation Template が生成されたので、AWS への デプロイを行ってみましょう。

AWS CDKアプリを環境（アカウント/リージョン）に初めてデプロイするときは、「Bootstrapスタック」を構築する必要があります。このスタックには、ツールキットの操作に必要なリソースが含まれています。たとえば、スタックにはデプロイプロセスで使われるCloudformationテンプレートとアセットを保存するために使用されるS3バケットが含まれます。

`cdk bootstrap` コマンドを実行すれば、「bootstrapスタック」がAWS環境にデプロイされます。

```
cdk bootstrap
```



実行例

```
Trusted accounts for deployment: (none)
Trusted accounts for lookup: (none)
Using default execution policy of 'arn:aws:iam::aws:policy/AdministratorAccess'. Pass '--cloudformation-execution-policies' to customize.
CDKToolkit: creating CloudFormation changeset...
[█████████▋················································] (2/12)

snip

 ✅  Environment aws://xxxxxxxxxxxx/ap-northeast-1 bootstrapped.
```



bootstrap が終わったので、デプロイを行います。

```
cdk deploy
```



実行例。変更しても良いか聞かれるため、y を押します。

```
> cdk deploy

✨  Synthesis time: 6.67s

This deployment will make potentially sensitive changes according to your current security approval level (--require-approval broadening).
Please confirm you intend to make the following modifications:

IAM Statement Changes
┌───┬───────────────────────────────┬────────┬─────────────────┬───────────────────────────────┬────────────────────────────────┐
│   │ Resource                      │ Effect │ Action          │ Principal                     │ Condition                      │
├───┼───────────────────────────────┼────────┼─────────────────┼───────────────────────────────┼────────────────────────────────┤
│ + │ ${CdkWorkshopQueue.Arn}       │ Allow  │ sqs:SendMessage │ Service:sns.amazonaws.com     │ "ArnEquals": {                 │
│   │                               │        │                 │                               │   "aws:SourceArn": "${CdkWorks │
│   │                               │        │                 │                               │ hopTopic}"                     │
│   │                               │        │                 │                               │ }                              │
└───┴───────────────────────────────┴────────┴─────────────────┴───────────────────────────────┴────────────────────────────────┘
(NOTE: There may be security-related changes not in this list. See https://github.com/aws/aws-cdk/issues/1299)

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



実行例

```
CdkWorkshopStack: deploying...
[0%] start: Publishing 7426ecbbf6a9ef9e15e3e9436fc8e9993ae25ad26d2264244eb9945a6a066902:current_account-current_region
[100%] success: Published 7426ecbbf6a9ef9e15e3e9436fc8e9993ae25ad26d2264244eb9945a6a066902:current_account-current_region
CdkWorkshopStack: creating CloudFormation changeset...







 ✅  CdkWorkshopStack

✨  Deployment time: 102.9s

Stack ARN:
arn:aws:cloudformation:ap-northeast-1:xxxxxxxxxxxx:stack/CdkWorkshopStack/a2928c00-8c78-11ec-ba29-0ada3c19ff01

✨  Total time: 109.57s

```



実際の CloudFormation で Stack が作成されています

![image-20220213120052963.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/1c2b574c-822d-63f0-1825-0ecbd7aa380a.png)



# Hello, CDK!

この章では、いくつかのCDKコードを書きます。サンプルアプリにあるSNS / SQSの代わりに、API Gatewayのエンドポイントを持つLambda関数を追加します。

エンドポイントの任意のパスにアクセスするとレスポンスを受け取ることができるようになります。

![image-20220213120139789.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/3b2838df-9413-8bed-04bf-b1a303a4d46a.png)

## サンプルコードの削除

`cdk init sample-app` によって作成されたプロジェクトには、SQSキューとSNSトピックが含まれます。このプロジェクトではそれらを使用する予定はないので、 `CdkWorkshopStack` コンストラクタから削除しましょう。

`lib/cdk-workshop-stack.ts` を開き、削除します。最終的には次のようになります。

```typescript
import { Duration, Stack, StackProps } from 'aws-cdk-lib';
import { Construct } from 'constructs';

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

  }
}
```



上記の修正によって、どのような差分が発生するのか確認できます。 `cdk diff` を実行してみましょう。 (CDKアプリと現在デプロイされているリソースの差分を確認できます)

```
cdk diff
```



実行例

- SQN や SNS が destory と表示されており、削除されることがわかります。

```
Stack CdkWorkshopStack
IAM Statement Changes
┌───┬───────────────────────────────┬────────┬─────────────────┬───────────────────────────────┬────────────────────────────────┐
│   │ Resource                      │ Effect │ Action          │ Principal                     │ Condition                      │
├───┼───────────────────────────────┼────────┼─────────────────┼───────────────────────────────┼────────────────────────────────┤
│ - │ ${CdkWorkshopQueue50D9D426.Ar │ Allow  │ sqs:SendMessage │ Service:sns.amazonaws.com     │ "ArnEquals": {                 │
│   │ n}                            │        │                 │                               │   "aws:SourceArn": "${CdkWorks │
│   │                               │        │                 │                               │ hopTopicD368A42F}"             │
│   │                               │        │                 │                               │ }                              │
└───┴───────────────────────────────┴────────┴─────────────────┴───────────────────────────────┴────────────────────────────────┘
(NOTE: There may be security-related changes not in this list. See https://github.com/aws/aws-cdk/issues/1299)

Resources
[-] AWS::SQS::Queue CdkWorkshopQueue50D9D426 destroy
[-] AWS::SQS::QueuePolicy CdkWorkshopQueuePolicyAF2494A5 destroy
[-] AWS::SNS::Subscription CdkWorkshopQueueCdkWorkshopStackCdkWorkshopTopicD7BE96438B5AD106 destroy
[-] AWS::SNS::Topic CdkWorkshopTopicD368A42F destroy

```



cdk deploy で AWS 環境に反映をしていきます。

```
cdk deploy
```



これによって、CloudFormation の Stack も更新され、SQS や SNS などのリソースが自動的に削除されています。CDK で削除したので、想定通りです。

![image-20220213122915279.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/77bf1d56-7948-a44b-a6a3-0a234d6be76f.png)



## Lambda

まずは、Lambda handlerのコードから書いていきます。

1. プロジェクトツリーの最上位のディレクトリ(`bin`, `lib`ディレクトリと同階層 )に `lambda`ディレクトリを作成します。
2. `lambda/hello.js` を作成して以下のコードを追加します。

![image-20220213123129667.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/bcbd257d-8def-5275-eda8-5b90fc4e5f58.png)



コード全体

```typescript
exports.handler = async function (event) {
    console.log('request:', JSON.stringify(event, undefined, 2));
    return {
        statusCode: 200,
        headers: { 'Content-Type': 'text/plain' },
        body: `Hello, CDK! You've hit ${event.path}\n`
    };
};
```



AWS CDKには、AWS Construct Libraryと呼ばれるコンストラクトのための広範なライブラリが付属しています。AWS Construct Libraryは、AWSのサービスごとに独立した **モジュール** として提供されます。たとえば、AWS Lambda関数を定義する場合、AWS LambdaのConstruct Libraryを使用する必要があります。

AWSコンストラクト学ぶためには、 [AWS Construct Library reference ](https://docs.aws.amazon.com/cdk/api/latest/docs/aws-construct-library.html) を参照してください。



このワークショップでは、コピー&ペーストをするのではなく、実際にCDKのコードを入力することを強く推奨します（通常、入力する量は多くありません）。これにより、CDKの使い方についてより理解していただけるものとなります。IDEがオートコンプリート、インラインドキュメント、およびタイプセーフに対応しているのがご理解いただけるでしょう。

```typescript
import { Function, Runtime, AssetCode, Code } from "aws-cdk-lib/aws-lambda"
import { Duration, Stack, StackProps } from "aws-cdk-lib"
import { Construct } from "constructs"

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

    const hello = new Function(this, 'HelloHandler', {
      runtime: Runtime.NODEJS_14_X,    // execution environment
      code: Code.fromAsset('lambda'),  // code loaded from "lambda" directory
      handler: 'hello.handler'         // file is "hello", function is "handler"
    });
  }
}
```



差分を確認してみましょう。

```
cdk diff
```



実行例

- IAM Role と Lambda Function が差分となっています。

```
Stack CdkWorkshopStack
IAM Statement Changes
┌───┬─────────────────────────────────┬────────┬────────────────┬──────────────────────────────┬───────────┐
│   │ Resource                        │ Effect │ Action         │ Principal                    │ Condition │
├───┼─────────────────────────────────┼────────┼────────────────┼──────────────────────────────┼───────────┤
│ + │ ${HelloHandler/ServiceRole.Arn} │ Allow  │ sts:AssumeRole │ Service:lambda.amazonaws.com │           │
└───┴─────────────────────────────────┴────────┴────────────────┴──────────────────────────────┴───────────┘
IAM Policy Changes
┌───┬─────────────────────────────┬────────────────────────────────────────────────────────────────────────────────┐
│   │ Resource                    │ Managed Policy ARN                                                             │
├───┼─────────────────────────────┼────────────────────────────────────────────────────────────────────────────────┤
│ + │ ${HelloHandler/ServiceRole} │ arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole │
└───┴─────────────────────────────┴────────────────────────────────────────────────────────────────────────────────┘
(NOTE: There may be security-related changes not in this list. See https://github.com/aws/aws-cdk/issues/1299)

Resources
[+] AWS::IAM::Role HelloHandler/ServiceRole HelloHandlerServiceRole11EF7C63 
[+] AWS::Lambda::Function HelloHandler HelloHandler2E4FBA4D 

```



上記のとおり、このコードから **AWS::Lambda::Function** リソース用のCloudFormationテンプレートを生成しました。

それでは Deploy をしてみます

```
cdk deploy
```



CloudFormation の Stack を確認すると、Lambda Function と IAM Role が自動生成されています。

![image-20220213141533027.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/41073fe5-a789-cc06-c47e-ce67bad909cf.png)



Lambda Function の詳細画面を開くと、CDK で定義したプログラムがアップロードされています。

![image-20220213141716270.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/57a16b25-94cb-753c-64f2-667dd024bf6d.png)



動作確認のために、Test を押します。

![image-20220213141905310.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/b5d17f16-d172-e4b3-4c3b-9ddd9208da19.png)



apigateway-aws-proxy を選択し、Event name に test と入れて、Create を押します。

![image-20220213142008336.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/f83f7eab-c7a8-7391-b032-fcdb5159e4fe.png)



テストのためのパラメータを作成出来たため、テスト実行するために再度 Test を押します。

![image-20220213142117452.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/4bbbeb96-9a80-9f98-93d2-c78f7d2af65f.png)



正常に実行されています。

![image-20220213142136413.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/5cdb8419-c88b-703b-1918-bd85da80ac8d.png)



## API Gateway

次のステップは、Lambda関数の前にAPI Gatewayを追加することです。API Gatewayは、インターネット上の誰でも[curl ](https://curl.haxx.se/)やWebブラウザなどのHTTPクライアントでアクセスできるパブリックなHTTPエンドポイントを公開します。

APIのルートにマウントされた[Lambdaプロキシ統合 ](javascript:void(0))を使用します。つまり、URLパスへのリクエストはすべてLambda関数に直接プロキシされ、Lambda関数からの応答がユーザーに返されます。



`lib/cdk-workshop-stack.ts` を開き、APIエンドポイントを定義してLambda関数に関連付けます。

```typescript
import { Function, Runtime, AssetCode, Code } from "aws-cdk-lib/aws-lambda"
import * as apigw from 'aws-cdk-lib/aws-apigateway';
import { Duration, Stack, StackProps } from "aws-cdk-lib"
import { Construct } from "constructs"

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

    // defines an AWS Lambda resource
    const hello = new Function(this, 'HelloHandler', {
      runtime: Runtime.NODEJS_14_X,    // execution environment
      code: Code.fromAsset('lambda'),  // code loaded from "lambda" directory
      handler: 'hello.handler'         // file is "hello", function is "handler"
    });

    // defines an API Gateway REST API resource backed by our "hello" function.
    new apigw.LambdaRestApi(this, 'Endpoint', {
      handler: hello
    });
  }
}
```

AWS Lambda関数へのすべてのリクエストをプロキシするAPI Gatewayを定義するために必要なことはこれだけです。



差分を出力します。

```
cdk diff
```



実行例

追加したコードにより、12個の新しいリソースがスタックに追加されることがわかります。

```
Stack CdkWorkshopStack
IAM Statement Changes
┌───┬───────────────────────────┬────────┬───────────────────────────┬───────────────────────────┬──────────────────────────────┐
│   │ Resource                  │ Effect │ Action                    │ Principal                 │ Condition                    │
├───┼───────────────────────────┼────────┼───────────────────────────┼───────────────────────────┼──────────────────────────────┤
│ + │ ${Endpoint/CloudWatchRole │ Allow  │ sts:AssumeRole            │ Service:apigateway.amazon │                              │
│   │ .Arn}                     │        │                           │ aws.com                   │                              │
├───┼───────────────────────────┼────────┼───────────────────────────┼───────────────────────────┼──────────────────────────────┤
│ + │ ${HelloHandler.Arn}       │ Allow  │ lambda:InvokeFunction     │ Service:apigateway.amazon │ "ArnLike": {                 │
│   │                           │        │                           │ aws.com                   │   "AWS:SourceArn": "arn:${AW │
│   │                           │        │                           │                           │ S::Partition}:execute-api:${ │
│   │                           │        │                           │                           │ AWS::Region}:${AWS::AccountI │
│   │                           │        │                           │                           │ d}:${EndpointEEF1FD8F}/${End │
│   │                           │        │                           │                           │ point/DeploymentStage.prod}/ │
│   │                           │        │                           │                           │ */*"                         │
│   │                           │        │                           │                           │ }                            │
│ + │ ${HelloHandler.Arn}       │ Allow  │ lambda:InvokeFunction     │ Service:apigateway.amazon │ "ArnLike": {                 │
│   │                           │        │                           │ aws.com                   │   "AWS:SourceArn": "arn:${AW │
│   │                           │        │                           │                           │ S::Partition}:execute-api:${ │
│   │                           │        │                           │                           │ AWS::Region}:${AWS::AccountI │
│   │                           │        │                           │                           │ d}:${EndpointEEF1FD8F}/test- │
│   │                           │        │                           │                           │ invoke-stage/*/*"            │
│   │                           │        │                           │                           │ }                            │
│ + │ ${HelloHandler.Arn}       │ Allow  │ lambda:InvokeFunction     │ Service:apigateway.amazon │ "ArnLike": {                 │
│   │                           │        │                           │ aws.com                   │   "AWS:SourceArn": "arn:${AW │
│   │                           │        │                           │                           │ S::Partition}:execute-api:${ │
│   │                           │        │                           │                           │ AWS::Region}:${AWS::AccountI │
│   │                           │        │                           │                           │ d}:${EndpointEEF1FD8F}/${End │
│   │                           │        │                           │                           │ point/DeploymentStage.prod}/ │
│   │                           │        │                           │                           │ */"                          │
│   │                           │        │                           │                           │ }                            │
│ + │ ${HelloHandler.Arn}       │ Allow  │ lambda:InvokeFunction     │ Service:apigateway.amazon │ "ArnLike": {                 │
│   │                           │        │                           │ aws.com                   │   "AWS:SourceArn": "arn:${AW │
│   │                           │        │                           │                           │ S::Partition}:execute-api:${ │
│   │                           │        │                           │                           │ AWS::Region}:${AWS::AccountI │
│   │                           │        │                           │                           │ d}:${EndpointEEF1FD8F}/test- │
│   │                           │        │                           │                           │ invoke-stage/*/"             │
│   │                           │        │                           │                           │ }                            │
└───┴───────────────────────────┴────────┴───────────────────────────┴───────────────────────────┴──────────────────────────────┘
IAM Policy Changes
┌───┬────────────────────────────┬─────────────────────────────────────────────────────────────────────────────────────────┐
│   │ Resource                   │ Managed Policy ARN                                                                      │
├───┼────────────────────────────┼─────────────────────────────────────────────────────────────────────────────────────────┤
│ + │ ${Endpoint/CloudWatchRole} │ arn:${AWS::Partition}:iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs │
└───┴────────────────────────────┴─────────────────────────────────────────────────────────────────────────────────────────┘
(NOTE: There may be security-related changes not in this list. See https://github.com/aws/aws-cdk/issues/1299)

Resources
[+] AWS::ApiGateway::RestApi Endpoint EndpointEEF1FD8F 
[+] AWS::IAM::Role Endpoint/CloudWatchRole EndpointCloudWatchRoleC3C64E0F 
[+] AWS::ApiGateway::Account Endpoint/Account EndpointAccountB8304247 
[+] AWS::ApiGateway::Deployment Endpoint/Deployment EndpointDeployment318525DA5f8cdfe532107839d82cbce31f859259 
[+] AWS::ApiGateway::Stage Endpoint/DeploymentStage.prod EndpointDeploymentStageprodB78BEEA0 
[+] AWS::ApiGateway::Resource Endpoint/Default/{proxy+} Endpointproxy39E2174E 
[+] AWS::Lambda::Permission Endpoint/Default/{proxy+}/ANY/ApiPermission.CdkWorkshopStackEndpoint018E8349.ANY..{proxy+} EndpointproxyANYApiPermissionCdkWorkshopStackEndpoint018E8349ANYproxy747DCA52 
[+] AWS::Lambda::Permission Endpoint/Default/{proxy+}/ANY/ApiPermission.Test.CdkWorkshopStackEndpoint018E8349.ANY..{proxy+} EndpointproxyANYApiPermissionTestCdkWorkshopStackEndpoint018E8349ANYproxy41939001 
[+] AWS::ApiGateway::Method Endpoint/Default/{proxy+}/ANY EndpointproxyANYC09721C5 
[+] AWS::Lambda::Permission Endpoint/Default/ANY/ApiPermission.CdkWorkshopStackEndpoint018E8349.ANY.. EndpointANYApiPermissionCdkWorkshopStackEndpoint018E8349ANYE84BEB04 
[+] AWS::Lambda::Permission Endpoint/Default/ANY/ApiPermission.Test.CdkWorkshopStackEndpoint018E8349.ANY.. EndpointANYApiPermissionTestCdkWorkshopStackEndpoint018E8349ANYB6CC1B64 
[+] AWS::ApiGateway::Method Endpoint/Default/ANY EndpointANY485C938B 

Outputs
[+] Output Endpoint/Endpoint Endpoint8024A810: {"Value":{"Fn::Join":["",["https://",{"Ref":"EndpointEEF1FD8F"},".execute-api.",{"Ref":"AWS::Region"},".",{"Ref":"AWS::URLSuffix"},"/",{"Ref":"EndpointDeploymentStageprodB78BEEA0"},"/"]]}}

```



deploy を行います

```
cdk deploy
```



実行例

- Endpoint に、API Gateway の Endpoint が表示されています。

```
✨  Deployment time: 93.24s

Outputs:
CdkWorkshopStack.Endpoint8024A810 = https://cxjdzr9dw4.execute-api.ap-northeast-1.amazonaws.com/prod/
Stack ARN:
arn:aws:cloudformation:ap-northeast-1:xxxxxxxxxxxx:stack/CdkWorkshopStack/a2928c00-8c78-11ec-ba29-0ada3c19ff01

✨  Total time: 99.94s

```



curl で実際にアクセスすると、次のように API Gateway を経由して Lambda を実行した結果を確認できます。

```
> curl https://cxjdzr9dw4.execute-api.ap-northeast-1.amazonaws.com/prod/
Hello, CDK! You've hit /
```



# 参考URL

https://catalog.us-east-1.prod.workshops.aws/v2/workshops/99731164-1d19-4d2e-9319-727a130e2d57/ja-JP/