【ハンズオン】コードでAWS環境を管理しよう! AWS CDKハンズオン #AWSSummit

2020年9月8日から9月30日の間で開催されているAWS Summit Online のセッションに参加しています。 AWS Summit Onlineでは基調講演等の他、ハンズオンセッションという手を動かすセッションがあります。
2020.09.15

今回は、コードでAWS環境を管理しよう! AWS CDKハンズオンに参加したのでレポートします。

セッション概要

スピーカー

内田 大樹 氏

アマゾン ウェブサービス ジャパン インダストリソリューション部

ソリューションアーキテクト

セッション

HOL-10:コードでAWS環境を管理しよう! AWS CDKハンズオン
1時間程度の動画ですが丁寧に説明がされているため、CloudFormationやCDKを利用したことがない方でも問題なく進められると思います。

動画はこちら
手順書はこちら

目的

AWS CDK (TypeScript)を利用したAWS環境の構築方法を学ぶ

ハンズオンの大まかな流れ

本ハンズオンは、適宜詳細な解説を交えながら以下の流れで進行していきます。

  • ハンズオンで利用するサービス紹介
  • 環境構築
  • SNS + SQS
    • まずはリソースだけでAWS CDKの記載方法、デプロイ方法を学ぶ
  • Lambda
    • ソースコードの解説およびAWS CDKの記載方法、デプロイを学ぶ
    • Lambdaの動作確認
  • API Gateway + Lambda
    • AWS CDKの記載方法を学ぶ
    • 完成したAPIの動作確認

最終的な目標は、AWS CDKを用いてAPI Gateway + LambdaのAPIを構築し動作を確認することです。

前提条件

下記がインストールされていることが前提条件となります。
本記事では、インストール方法については割愛させていただきます。

  • Node.js > 10.3
  • AWS CLI

ハンズオンで利用するサービス紹介

今回のハンズオンで利用する主要なサービスの簡単な解説が行われます。 SNSとSQSについては、AWS CDKによる記載方法、デプロイ方法を学ぶ際にでてきますがハンズオンの目的とは異なるため割愛されているようです。

AWS CDKについて

AWS CDKの概要説明、およびCDKアプリケーションの構成に関する説明です。 App, Stack, Constructの概念はAWS CDKを利用する上で重要となるので頭に入れておきましょう。

環境構築

ここから実際に手を動かしながら学んでいきます。まずは、AWS CDKのインストールからです。

$ sudo npm install -g aws-cdk
/usr/local/bin/cdk -> /usr/local/lib/node_modules/aws-cdk/bin/cdk
+ aws-cdk@1.62.0
added 216 packages from 187 contributors in 7.762s

AWS CDKがインストールできたらcdk-workshopという空のディレクトリを作成しそこで初期コードを生成します。

$ cdk init app --language typescript
Applying project template app for typescript
# Welcome to your CDK TypeScript project!

This is a blank project for TypeScript development with CDK.

The `cdk.json` file tells the CDK Toolkit how to execute your app.

## Useful commands

 * `npm run build`   compile typescript to js
 * `npm run watch`   watch for changes and compile
 * `npm run test`    perform the jest unit tests
 * `cdk deploy`      deploy this stack to your default AWS account/region
 * `cdk diff`        compare deployed stack with current state
 * `cdk synth`       emits the synthesized CloudFormation template

Executing npm install...
npm WARN deprecated request@2.88.2: request has been deprecated, see https://github.com/request/request/issues/3142
npm WARN deprecated request-promise-native@1.0.9: request-promise-native has been deprecated because it extends the now deprecated request package, see https://github.com/request/request/issues/3142
npm WARN deprecated har-validator@5.1.5: this library is no longer supported
npm WARN deprecated resolve-url@0.2.1: https://github.com/lydell/resolve-url#deprecated
npm WARN deprecated urix@0.1.0: Please see https://github.com/lydell/urix#deprecated
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@^2.1.2 (node_modules/jest-haste-map/node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@2.1.3: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})
npm WARN cdk-workshop@0.1.0 No repository field.
npm WARN cdk-workshop@0.1.0 No license field.

✅ All done!

これでAWS CDKに必要なファイルが配置され環境構築は完了になります。

SNS + SQS

必要となるConstructライブラリ(各サービスに対応したライブラリ)をインストールします。 (ハンズオン手順としてはでてきませんが、自動インストールされなかったため手動でインストールしました)

$ npm install @aws-cdk/aws-sns @aws-cdk/aws-sns @aws-cdk/aws-sns-subscriptions
npm WARN cdk-workshop@0.1.0 No repository field.
npm WARN cdk-workshop@0.1.0 No license field.
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@2.1.3 (node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@2.1.3: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})

+ @aws-cdk/aws-sns@1.62.0
+ @aws-cdk/aws-sns@1.62.0
+ @aws-cdk/aws-sns-subscriptions@1.62.0
added 12 packages from 1 contributor, updated 1 package and audited 990 packages in 11.333s

24 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

AWS CDKが生成したコードに、SNSとSQSの定義を追加します。

cdk-workshop/lib/cdk-workshop-stack.ts

import * as sns from '@aws-cdk/aws-sns';
import * as subs from '@aws-cdk/aws-sns-subscriptions';
import * as sqs from '@aws-cdk/aws-sqs';
import * as cdk from '@aws-cdk/core';

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

    const queue = new sqs.Queue(this, 'CdkWorkshopQueue', {
      visibilityTimeout: cdk.Duration.seconds(300)
    });

    const topic = new sns.Topic(this, 'CdkWorkshopTopic');

    topic.addSubscription(new subs.SqsSubscription(queue));
  }
}

リソースの定義が記載できたので、デプロイの際にAWS CDKによって生成されるCloudFormationテンプレートを確認します。

$ cdk synth
Resources:
  CdkWorkshopQueue50D9D426:
    Type: AWS::SQS::Queue
    Properties:
      VisibilityTimeout: 300
    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:
      Modules: aws-cdk=1.62.0,@aws-cdk/aws-cloudwatch=1.62.0,@aws-cdk/aws-iam=1.62.0,@aws-cdk/aws-kms=1.62.0,@aws-cdk/aws-sns=1.62.0,@aws-cdk/aws-sns-subscriptions=1.62.0,@aws-cdk/aws-sqs=1.62.0,@aws-cdk/cloud-assembly-schema=1.62.0,@aws-cdk/core=1.62.0,@aws-cdk/cx-api=1.62.0,@aws-cdk/region-info=1.62.0,jsii-runtime=node.js/v10.19.0
    Condition: CDKMetadataAvailable
Conditions:
  CDKMetadataAvailable:
    Fn::Or:
      - Fn::Or:
          - 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::Equals:
              - Ref: AWS::Region
              - eu-central-1
      - Fn::Or:
          - Fn::Equals:
              - Ref: AWS::Region
              - eu-north-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::Equals:
              - Ref: AWS::Region
              - us-west-1
          - Fn::Equals:
              - Ref: AWS::Region
              - us-west-2

動作が確認できればデプロイ可能なためAWS CDKデプロイ管理用の環境(S3バケット)を作成します。このコマンドは初回のみ実行する必要があります。

 $ cdk bootstrap
 ⏳  Bootstrapping environment aws://10000000000/ap-northeast-1...
CDKToolkit: creating CloudFormation changeset...
[██████████████████████████████████████████████████████████] (2/2)


 ✅  Environment aws://10000000000/ap-northeast-1 bootstrapped.

デプロイを行います。

$ cdk deploy
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": "${CdkWorkshopTopic}"                │
│   │                         │        │                 │                           │ }                                                       │
└───┴─────────────────────────┴────────┴─────────────────┴───────────────────────────┴─────────────────────────────────────────────────────────┘
(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)? y
CdkWorkshopStack: deploying...
CdkWorkshopStack: creating CloudFormation changeset...
[██████████████████████████████████████████████████████████] (6/6)






 ✅  CdkWorkshopStack

Stack ARN:
arn:aws:cloudformation:ap-northeast-1:1000000000:stack/CdkWorkshopStack/60ca4330-f656-11ea-ad13-0aa2cd508fc6

AWSコンソールから、CloudFormationのスタックを表示し各リソースが実際にデプロイされていることを確認しました。

AWS CDKのコードを変更してデプロイする方法について学べたので、SNSとSQSについてはコードから削除します。

cdk-workshop/lib/cdk-workshop-stack.ts

import * as cdk from '@aws-cdk/core';

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

  }
}

削除したもののdiffを確認してみましょう。

$ cdk diff
Stack CdkWorkshopStack
IAM Statement Changes
┌───┬────────────────────────────────────────┬────────┬─────────────────┬────────────────────────────────────────┬──────────────────────────────────────────┐
│   │ Resource                               │ Effect │ Action          │ Principal                              │ Condition                                │
├───┼────────────────────────────────────────┼────────┼─────────────────┼────────────────────────────────────────┼──────────────────────────────────────────┤
│ - │ ${CdkWorkshopQueue50D9D426.Arn}        │ Allow  │ sqs:SendMessage │ Service:sns.amazonaws.com              │ "ArnEquals": {                           │
│   │                                        │        │                 │                                        │   "aws:SourceArn": "${CdkWorkshopTopicD3 │
│   │                                        │        │                 │                                        │ 68A42F}"                                 │
│   │                                        │        │                 │                                        │ }                                        │
└───┴────────────────────────────────────────┴────────┴─────────────────┴────────────────────────────────────────┴──────────────────────────────────────────┘
(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
CdkWorkshopStack: deploying...
CdkWorkshopStack: creating CloudFormation changeset...
[██████████████████████████████████████████████████████████] (6/6)




 ✅  CdkWorkshopStack

Stack ARN:
arn:aws:cloudformation:ap-northeast-1:10000000000:stack/CdkWorkshopStack/60ca4330-f656-11ea-ad13-0aa2cd508fc6

Lambda

ハンズオンの本題であるLambdaの作成に入ります。 まずはConstructライブラリのインストールを行います。

$ npm install @aws-cdk/aws-lambda
npm WARN cdk-workshop@0.1.0 No repository field.
npm WARN cdk-workshop@0.1.0 No license field.
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@2.1.3 (node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@2.1.3: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})

+ @aws-cdk/aws-lambda@1.62.0
updated 1 package and audited 991 packages in 7.85s

24 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

次に、Lambdaのソースをlambdaというディレクトリを作成し新規作成します。
処理としては、API Gatewayから渡されるイベント情報からアクセスパスを返却する簡単なものとなっています。

cdk-workshop/lambda/hello.js

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`
  };
};

Lambdaのソースが完成したので、AWS CDKの管理対象としてLambdaを定義します。
ポイントとしては、Assetの指定にディレクトリ名、handlerの指定にファイル名とexportしている関数名を結合したもの指定します。もし変更していた場合は間違えないようにしてください。

cdk-workshop/lib/cdk-workshop-stack.ts

import * as cdk from '@aws-cdk/core';
import * as lambda from '@aws-cdk/aws-lambda';

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

    const hello = new lambda.Function(this, 'HelloHandler', {
      runtime: lambda.Runtime.NODEJS_10_X,
      code: lambda.Code.fromAsset('lambda'),
      handler: 'hello.handler'
    })

  }
}

LambdaのソースコードとAWS CDKの記載が完了したので、diffを確認します。

$ cdk diff
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)

Parameters
[+] Parameter AssetParameters/f0156e9e857a3c790844d347ec128e4d95577dd58e2a11f152756874830b47f8/S3Bucket AssetParametersf0156e9e857a3c790844d347ec128e4d95577dd58e2a11f152756874830b47f8S3Bucket0DFBA133: {"Type":"String","Description":"S3 bucket for asset \"f0156e9e857a3c790844d347ec128e4d95577dd58e2a11f152756874830b47f8\""}
[+] Parameter AssetParameters/f0156e9e857a3c790844d347ec128e4d95577dd58e2a11f152756874830b47f8/S3VersionKey AssetParametersf0156e9e857a3c790844d347ec128e4d95577dd58e2a11f152756874830b47f8S3VersionKey2DB6E077: {"Type":"String","Description":"S3 key for asset version \"f0156e9e857a3c790844d347ec128e4d95577dd58e2a11f152756874830b47f8\""}
[+] Parameter AssetParameters/f0156e9e857a3c790844d347ec128e4d95577dd58e2a11f152756874830b47f8/ArtifactHash AssetParametersf0156e9e857a3c790844d347ec128e4d95577dd58e2a11f152756874830b47f8ArtifactHash7BD937C8: {"Type":"String","Description":"Artifact hash for asset \"f0156e9e857a3c790844d347ec128e4d95577dd58e2a11f152756874830b47f8\""}

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

問題なさそうなので、デプロイを行います。

$ cdk deploy
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 │
├───┼─────────────────────────────────┼────────┼────────────────┼──────────────────────────────┼───────────┤
│ + │ ${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)

Do you wish to deploy these changes (y/n)? y
CdkWorkshopStack: deploying...
[0%] start: Publishing f0156e9e857a3c790844d347ec128e4d95577dd58e2a11f152756874830b47f8:current
[100%] success: Published f0156e9e857a3c790844d347ec128e4d95577dd58e2a11f152756874830b47f8:current
CdkWorkshopStack: creating CloudFormation changeset...
[██████████████████████████████████████████████████████████] (4/4)




 ✅  CdkWorkshopStack

Stack ARN:
arn:aws:cloudformation:ap-northeast-1:10000000000:stack/CdkWorkshopStack/60ca4330-f656-11ea-ad13-0aa2cd508fc6

デプロイが行えたのでAWSコンソール上で動作確認を行います。

デプロイされたLambdaを確認します。

テスト用イベントとしてイベントテンプレートから、apigateway-aws-proxyを選択しイベントを作成します。

実際にテストを実行して、先ほど作成したテストイベント内容である、/path/to/resouceが返却されていることを確認します。

API Gateway + Lambda

Lambdaのデプロイ、動作確認が行えたのでAPI Gatewayを追加しAPI Gateway経由でLambdaが起動できるようにします。

まずは、Constructライブラリをインストールします。

$ npm install @aws-cdk/aws-apigateway
npm WARN cdk-workshop@0.1.0 No repository field.
npm WARN cdk-workshop@0.1.0 No license field.
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@2.1.3 (node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@2.1.3: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})

+ @aws-cdk/aws-apigateway@1.62.0
added 4 packages from 1 contributor and audited 994 packages in 5.543s

24 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

次にAWS CDKの管理対象としてAPI Gatewayを定義します。
API Gatewayのhandlerに直前で定義したLambda(hello)を渡しています。

cdk-workshop/lib/cdk-workshop-stack.ts

import * as cdk from '@aws-cdk/core';
import * as lambda from '@aws-cdk/aws-lambda';
import * as apigw from '@aws-cdk/aws-apigateway';

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

    const hello = new lambda.Function(this, 'HelloHandler', {
      runtime: lambda.Runtime.NODEJS_10_X,
      code: lambda.Code.fromAsset('lambda'),
      handler: 'hello.handler'
    })

    new apigw.LambdaRestApi(this, 'Endpoint', {
      handler: hello
    });

  }
}

AWS CDKの記載が完了したので、diffを確認します。

$ cdk diff
Stack CdkWorkshopStack
IAM Statement Changes
┌───┬──────────────────────────────────────┬────────┬───────────────────────┬──────────────────────────────────────┬────────────────────────────────────────┐
│   │ Resource                             │ Effect │ Action                │ Principal                            │ Condition                              │
├───┼──────────────────────────────────────┼────────┼───────────────────────┼──────────────────────────────────────┼────────────────────────────────────────┤
│ + │ ${Endpoint/CloudWatchRole.Arn}       │ Allow  │ sts:AssumeRole        │ Service:apigateway.amazonaws.com     │                                        │
├───┼──────────────────────────────────────┼────────┼───────────────────────┼──────────────────────────────────────┼────────────────────────────────────────┤
│ + │ ${HelloHandler.Arn}                  │ Allow  │ lambda:InvokeFunction │ Service:apigateway.amazonaws.com     │ "ArnLike": {                           │
│   │                                      │        │                       │                                      │   "AWS:SourceArn": "arn:${AWS::Partiti │
│   │                                      │        │                       │                                      │ on}:execute-api:${AWS::Region}:${AWS:: │
│   │                                      │        │                       │                                      │ AccountId}:${EndpointEEF1FD8F}/${Endpo │
│   │                                      │        │                       │                                      │ int/DeploymentStage.prod}/*/*"         │
│   │                                      │        │                       │                                      │ }                                      │
│ + │ ${HelloHandler.Arn}                  │ Allow  │ lambda:InvokeFunction │ Service:apigateway.amazonaws.com     │ "ArnLike": {                           │
│   │                                      │        │                       │                                      │   "AWS:SourceArn": "arn:${AWS::Partiti │
│   │                                      │        │                       │                                      │ on}:execute-api:${AWS::Region}:${AWS:: │
│   │                                      │        │                       │                                      │ AccountId}:${EndpointEEF1FD8F}/test-in │
│   │                                      │        │                       │                                      │ voke-stage/*/*"                        │
│   │                                      │        │                       │                                      │ }                                      │
│ + │ ${HelloHandler.Arn}                  │ Allow  │ lambda:InvokeFunction │ Service:apigateway.amazonaws.com     │ "ArnLike": {                           │
│   │                                      │        │                       │                                      │   "AWS:SourceArn": "arn:${AWS::Partiti │
│   │                                      │        │                       │                                      │ on}:execute-api:${AWS::Region}:${AWS:: │
│   │                                      │        │                       │                                      │ AccountId}:${EndpointEEF1FD8F}/${Endpo │
│   │                                      │        │                       │                                      │ int/DeploymentStage.prod}/*/"          │
│   │                                      │        │                       │                                      │ }                                      │
│ + │ ${HelloHandler.Arn}                  │ Allow  │ lambda:InvokeFunction │ Service:apigateway.amazonaws.com     │ "ArnLike": {                           │
│   │                                      │        │                       │                                      │   "AWS:SourceArn": "arn:${AWS::Partiti │
│   │                                      │        │                       │                                      │ on}:execute-api:${AWS::Region}:${AWS:: │
│   │                                      │        │                       │                                      │ AccountId}:${EndpointEEF1FD8F}/test-in │
│   │                                      │        │                       │                                      │ voke-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"},"/"]]}}

問題なくAPI Gateway関連のリソースが追加されているため、デプロイします。

$ cdk deploy
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                              │
├───┼──────────────────────────────────────┼────────┼───────────────────────┼──────────────────────────────────────┼────────────────────────────────────────┤
│ + │ ${Endpoint/CloudWatchRole.Arn}       │ Allow  │ sts:AssumeRole        │ Service:apigateway.amazonaws.com     │                                        │
├───┼──────────────────────────────────────┼────────┼───────────────────────┼──────────────────────────────────────┼────────────────────────────────────────┤
│ + │ ${HelloHandler.Arn}                  │ Allow  │ lambda:InvokeFunction │ Service:apigateway.amazonaws.com     │ "ArnLike": {                           │
│   │                                      │        │                       │                                      │   "AWS:SourceArn": "arn:${AWS::Partiti │
│   │                                      │        │                       │                                      │ on}:execute-api:${AWS::Region}:${AWS:: │
│   │                                      │        │                       │                                      │ AccountId}:${EndpointEEF1FD8F}/${Endpo │
│   │                                      │        │                       │                                      │ int/DeploymentStage.prod}/*/*"         │
│   │                                      │        │                       │                                      │ }                                      │
│ + │ ${HelloHandler.Arn}                  │ Allow  │ lambda:InvokeFunction │ Service:apigateway.amazonaws.com     │ "ArnLike": {                           │
│   │                                      │        │                       │                                      │   "AWS:SourceArn": "arn:${AWS::Partiti │
│   │                                      │        │                       │                                      │ on}:execute-api:${AWS::Region}:${AWS:: │
│   │                                      │        │                       │                                      │ AccountId}:${EndpointEEF1FD8F}/test-in │
│   │                                      │        │                       │                                      │ voke-stage/*/*"                        │
│   │                                      │        │                       │                                      │ }                                      │
│ + │ ${HelloHandler.Arn}                  │ Allow  │ lambda:InvokeFunction │ Service:apigateway.amazonaws.com     │ "ArnLike": {                           │
│   │                                      │        │                       │                                      │   "AWS:SourceArn": "arn:${AWS::Partiti │
│   │                                      │        │                       │                                      │ on}:execute-api:${AWS::Region}:${AWS:: │
│   │                                      │        │                       │                                      │ AccountId}:${EndpointEEF1FD8F}/${Endpo │
│   │                                      │        │                       │                                      │ int/DeploymentStage.prod}/*/"          │
│   │                                      │        │                       │                                      │ }                                      │
│ + │ ${HelloHandler.Arn}                  │ Allow  │ lambda:InvokeFunction │ Service:apigateway.amazonaws.com     │ "ArnLike": {                           │
│   │                                      │        │                       │                                      │   "AWS:SourceArn": "arn:${AWS::Partiti │
│   │                                      │        │                       │                                      │ on}:execute-api:${AWS::Region}:${AWS:: │
│   │                                      │        │                       │                                      │ AccountId}:${EndpointEEF1FD8F}/test-in │
│   │                                      │        │                       │                                      │ voke-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)

Do you wish to deploy these changes (y/n)? y
CdkWorkshopStack: deploying...
[0%] start: Publishing f0156e9e857a3c790844d347ec128e4d95577dd58e2a11f152756874830b47f8:current
[100%] success: Published f0156e9e857a3c790844d347ec128e4d95577dd58e2a11f152756874830b47f8:current
CdkWorkshopStack: creating CloudFormation changeset...
[██████████████████████████████████████████████████████████] (14/14)







 ✅  CdkWorkshopStack

Outputs:
CdkWorkshopStack.Endpoint8024A810 = https://w4z0werc3i.execute-api.ap-northeast-1.amazonaws.com/prod/

Stack ARN:
arn:aws:cloudformation:ap-northeast-1:10000000000:stack/CdkWorkshopStack/60ca4330-f656-11ea-ad13-0aa2cd508fc6

コンソール出力の最後に、API Gatewayのエンドポイントが表示されているので動作確認を行います。

まずはcurlでアクセスします。

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

次にブラウザでアクセスします。

ちゃんと動作していますね。

最後に、AWS CDKで作成したリソース群を削除します。
手順書には、もっと学びたい人のために追加の手順等が記載されているので学習を続ける方はリソースの削除をせずにハンズオンを進めてください。

$ cdk destroy
Are you sure you want to delete: CdkWorkshopStack (y/n)? y
CdkWorkshopStack: destroying...
3:52:32 PM | DELETE_IN_PROGRESS   | AWS::IAM::Role              | HelloHandler/ServiceRole

 ✅  CdkWorkshopStack: destroyed
**************************************************
*** Newer version of CDK is available [1.63.0] ***
*** Upgrade recommended                        ***
**************************************************

まとめ

今回のハンズオンで、AWS CDKの下記3点について経験することができました。

  • 環境構築
  • リソースの定義方法(Lambda, API Gateway)
  • デプロイやdiffの確認方法

最後に

今回初めてAWS CDKを利用してみました。CloudFormationテンプレートよりも抽象化されていることで記述量が減ること、型があるためIDEの支援を受けられることは大きな魅力に感じました!

以上なります。ハンズオンの動画や資料はとても丁寧でわかりやすいので、みなさんもぜひやってみてください。