【AWS CDK入門】ネットワークリソースを生成してみる

CDK（プログラミング言語でAWSリソースの定義を書き､CloudFormationテンプレートを生成し､デプロイを行えるツール）の習得のため、既存のCloudFormationテンプレートのリソースを再現してみます。

# 再現対象
再現対象のテンプレートファイルは[こちら](https://github.com/kulikala/fullbok/blob/develop/fullbok-demo-template.yml)です。
リソース図は以下の通りです。
![new-designer (5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458187/9e888d37-7e60-085e-bbb5-0c729aaca115.png)
今回は、この中でもネットワーク関連のリソース（VPC、Subnet、GW、RouteTable）を再現したいと思います。

# 環境
今回はTypeScriptを使用します。

cdk:1.18.0
node:11.15.0
TypeScript:2.9.2

# セットアップ
cdkのインストールは以下のコマンドを叩きます。

```
$ npm install -g aws-cdk
```

以降は[こちらのCDK WORKSHOP](https://cdkworkshop.com/20-typescript.html)に沿ってセットアップをし、「PROJECT STRUCTURE」の節まで進めます。

そして、今回はEC2のモジュールを使用するので、予めインストールしておきます。

```
$ npm install @aws-cdk/aws-ec2
```

# Vpcコンストラクタを使ってみる
セットアップが完了したら、`lib/cdk-workshop-stack.ts`をいじっていきます。
まずは[Class Vpc](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.Vpc.html)を使って、リソースを生成してみます。

```lib/cdk-workshop-stack.ts
import { App, Stack, StackProps } from '@aws-cdk/core'
import { Vpc } from '@aws-cdk/aws-ec2'

export class CdkWorkshopStack extends Stack {
  constructor(scope: App, id: string, props?: StackProps) {
    super(scope, id, props)
    const vpc = new Vpc(this, 'VPC')
  }
}
```
上記の内容で、CloudFormationのテンプレートを出力してみます。
コマンドは以下を叩きます。

```
$ cdk synth
```
出てきたテンプレートは以下です。

```cdk-synth-result.yml
Resources:
  VPCB9E5F0B4:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      EnableDnsHostnames: true
      EnableDnsSupport: true
      InstanceTenancy: default
      Tags:
        - Key: Name
          Value: CdkWorkshopStack/VPC
    Metadata:
      aws:cdk:path: CdkWorkshopStack/VPC/Resource
  VPCPublicSubnet1SubnetB4246D30:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: 10.0.0.0/18
      VpcId:
        Ref: VPCB9E5F0B4
      AvailabilityZone:
        Fn::Select:
          - 0
          - Fn::GetAZs: ""
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: CdkWorkshopStack/VPC/PublicSubnet1
        - Key: aws-cdk:subnet-name
          Value: Public
        - Key: aws-cdk:subnet-type
          Value: Public
    Metadata:
      aws:cdk:path: CdkWorkshopStack/VPC/PublicSubnet1/Subnet
  VPCPublicSubnet1RouteTableFEE4B781:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId:
        Ref: VPCB9E5F0B4
      Tags:
        - Key: Name
          Value: CdkWorkshopStack/VPC/PublicSubnet1
    Metadata:
      aws:cdk:path: CdkWorkshopStack/VPC/PublicSubnet1/RouteTable
  VPCPublicSubnet1RouteTableAssociation0B0896DC:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId:
        Ref: VPCPublicSubnet1RouteTableFEE4B781
      SubnetId:
        Ref: VPCPublicSubnet1SubnetB4246D30
    Metadata:
      aws:cdk:path: CdkWorkshopStack/VPC/PublicSubnet1/RouteTableAssociation
  VPCPublicSubnet1DefaultRoute91CEF279:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId:
        Ref: VPCPublicSubnet1RouteTableFEE4B781
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId:
        Ref: VPCIGWB7E252D3
    DependsOn:
      - VPCVPCGW99B986DC
    Metadata:
      aws:cdk:path: CdkWorkshopStack/VPC/PublicSubnet1/DefaultRoute
  VPCPublicSubnet1EIP6AD938E8:
    Type: AWS::EC2::EIP
    Properties:
      Domain: vpc
    Metadata:
      aws:cdk:path: CdkWorkshopStack/VPC/PublicSubnet1/EIP
  VPCPublicSubnet1NATGatewayE0556630:
    Type: AWS::EC2::NatGateway
    Properties:
      AllocationId:
        Fn::GetAtt:
          - VPCPublicSubnet1EIP6AD938E8
          - AllocationId
      SubnetId:
        Ref: VPCPublicSubnet1SubnetB4246D30
      Tags:
        - Key: Name
          Value: CdkWorkshopStack/VPC/PublicSubnet1
    Metadata:
      aws:cdk:path: CdkWorkshopStack/VPC/PublicSubnet1/NATGateway
  VPCPublicSubnet2Subnet74179F39:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: 10.0.64.0/18
      VpcId:
        Ref: VPCB9E5F0B4
      AvailabilityZone:
        Fn::Select:
          - 1
          - Fn::GetAZs: ""
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: CdkWorkshopStack/VPC/PublicSubnet2
        - Key: aws-cdk:subnet-name
          Value: Public
        - Key: aws-cdk:subnet-type
          Value: Public
    Metadata:
      aws:cdk:path: CdkWorkshopStack/VPC/PublicSubnet2/Subnet
  VPCPublicSubnet2RouteTable6F1A15F1:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId:
        Ref: VPCB9E5F0B4
      Tags:
        - Key: Name
          Value: CdkWorkshopStack/VPC/PublicSubnet2
    Metadata:
      aws:cdk:path: CdkWorkshopStack/VPC/PublicSubnet2/RouteTable
  VPCPublicSubnet2RouteTableAssociation5A808732:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId:
        Ref: VPCPublicSubnet2RouteTable6F1A15F1
      SubnetId:
        Ref: VPCPublicSubnet2Subnet74179F39
    Metadata:
      aws:cdk:path: CdkWorkshopStack/VPC/PublicSubnet2/RouteTableAssociation
  VPCPublicSubnet2DefaultRouteB7481BBA:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId:
        Ref: VPCPublicSubnet2RouteTable6F1A15F1
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId:
        Ref: VPCIGWB7E252D3
    DependsOn:
      - VPCVPCGW99B986DC
    Metadata:
      aws:cdk:path: CdkWorkshopStack/VPC/PublicSubnet2/DefaultRoute
  VPCPublicSubnet2EIP4947BC00:
    Type: AWS::EC2::EIP
    Properties:
      Domain: vpc
    Metadata:
      aws:cdk:path: CdkWorkshopStack/VPC/PublicSubnet2/EIP
  VPCPublicSubnet2NATGateway3C070193:
    Type: AWS::EC2::NatGateway
    Properties:
      AllocationId:
        Fn::GetAtt:
          - VPCPublicSubnet2EIP4947BC00
          - AllocationId
      SubnetId:
        Ref: VPCPublicSubnet2Subnet74179F39
      Tags:
        - Key: Name
          Value: CdkWorkshopStack/VPC/PublicSubnet2
    Metadata:
      aws:cdk:path: CdkWorkshopStack/VPC/PublicSubnet2/NATGateway
  VPCPrivateSubnet1Subnet8BCA10E0:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: 10.0.128.0/18
      VpcId:
        Ref: VPCB9E5F0B4
      AvailabilityZone:
        Fn::Select:
          - 0
          - Fn::GetAZs: ""
      MapPublicIpOnLaunch: false
      Tags:
        - Key: Name
          Value: CdkWorkshopStack/VPC/PrivateSubnet1
        - Key: aws-cdk:subnet-name
          Value: Private
        - Key: aws-cdk:subnet-type
          Value: Private
    Metadata:
      aws:cdk:path: CdkWorkshopStack/VPC/PrivateSubnet1/Subnet
  VPCPrivateSubnet1RouteTableBE8A6027:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId:
        Ref: VPCB9E5F0B4
      Tags:
        - Key: Name
          Value: CdkWorkshopStack/VPC/PrivateSubnet1
    Metadata:
      aws:cdk:path: CdkWorkshopStack/VPC/PrivateSubnet1/RouteTable
  VPCPrivateSubnet1RouteTableAssociation347902D1:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId:
        Ref: VPCPrivateSubnet1RouteTableBE8A6027
      SubnetId:
        Ref: VPCPrivateSubnet1Subnet8BCA10E0
    Metadata:
      aws:cdk:path: CdkWorkshopStack/VPC/PrivateSubnet1/RouteTableAssociation
  VPCPrivateSubnet1DefaultRouteAE1D6490:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId:
        Ref: VPCPrivateSubnet1RouteTableBE8A6027
      DestinationCidrBlock: 0.0.0.0/0
      NatGatewayId:
        Ref: VPCPublicSubnet1NATGatewayE0556630
    Metadata:
      aws:cdk:path: CdkWorkshopStack/VPC/PrivateSubnet1/DefaultRoute
  VPCPrivateSubnet2SubnetCFCDAA7A:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: 10.0.192.0/18
      VpcId:
        Ref: VPCB9E5F0B4
      AvailabilityZone:
        Fn::Select:
          - 1
          - Fn::GetAZs: ""
      MapPublicIpOnLaunch: false
      Tags:
        - Key: Name
          Value: CdkWorkshopStack/VPC/PrivateSubnet2
        - Key: aws-cdk:subnet-name
          Value: Private
        - Key: aws-cdk:subnet-type
          Value: Private
    Metadata:
      aws:cdk:path: CdkWorkshopStack/VPC/PrivateSubnet2/Subnet
  VPCPrivateSubnet2RouteTable0A19E10E:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId:
        Ref: VPCB9E5F0B4
      Tags:
        - Key: Name
          Value: CdkWorkshopStack/VPC/PrivateSubnet2
    Metadata:
      aws:cdk:path: CdkWorkshopStack/VPC/PrivateSubnet2/RouteTable
  VPCPrivateSubnet2RouteTableAssociation0C73D413:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId:
        Ref: VPCPrivateSubnet2RouteTable0A19E10E
      SubnetId:
        Ref: VPCPrivateSubnet2SubnetCFCDAA7A
    Metadata:
      aws:cdk:path: CdkWorkshopStack/VPC/PrivateSubnet2/RouteTableAssociation
  VPCPrivateSubnet2DefaultRouteF4F5CFD2:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId:
        Ref: VPCPrivateSubnet2RouteTable0A19E10E
      DestinationCidrBlock: 0.0.0.0/0
      NatGatewayId:
        Ref: VPCPublicSubnet2NATGateway3C070193
    Metadata:
      aws:cdk:path: CdkWorkshopStack/VPC/PrivateSubnet2/DefaultRoute
  VPCIGWB7E252D3:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: CdkWorkshopStack/VPC
    Metadata:
      aws:cdk:path: CdkWorkshopStack/VPC/IGW
  VPCVPCGW99B986DC:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId:
        Ref: VPCB9E5F0B4
      InternetGatewayId:
        Ref: VPCIGWB7E252D3
    Metadata:
      aws:cdk:path: CdkWorkshopStack/VPC/VPCGW
  CDKMetadata:
    Type: AWS::CDK::Metadata
    Properties:
      Modules: aws-cdk=1.18.0,@aws-cdk/aws-cloudwatch=1.18.0,@aws-cdk/aws-ec2=1.18.0,@aws-cdk/aws-iam=1.18.0,@aws-cdk/aws-ssm=1.18.0,@aws-cdk/core=1.18.0,@aws-cdk/cx-api=1.18.0,@aws-cdk/region-info=1.18.0,jsii-runtime=node.js/v11.15.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
```

リソース図は以下です。

![new-designer.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458187/925444f8-633a-32d9-8aad-86ddf9168b21.png)

数行のコードで、多くのリソースを生成してくれることが分かります。

# Subnetをカスタマイズしてみる
先ほど生成したリソースではサブネットマスクが"/18"のPrivate SubnetとPublic Subnetがそれぞれ2つずつ生成されていましたが、この部分をカスタマイズして、
「サブネットマスクが"/24"のPublic Subnetを2つ生成する」
ようにしてみます。

```lib/cdk-workshop-stack.ts
import { App, Stack, StackProps } from '@aws-cdk/core'
import { Vpc, SubnetType } from '@aws-cdk/aws-ec2' //SubnetTypeを追記

export class CdkWorkshopStack extends Stack {
  constructor(scope: App, id: string, props?: StackProps) {
    super(scope, id, props)
    const vpc = new Vpc(this, 'VPC', {
      subnetConfiguration: [ //subnetConfigurationの定義を追記
        {
          cidrMask: 24,
          name: 'Public',
          subnetType: SubnetType.PUBLIC,
        },
      ],
    })
  }
}
```
これで出力されたテンプレートは以下です。

```cdk-synth-result.yml
Resources:
  VPCB9E5F0B4:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      EnableDnsHostnames: true
      EnableDnsSupport: true
      InstanceTenancy: default
      Tags:
        - Key: Name
          Value: CdkWorkshopStack/VPC
    Metadata:
      aws:cdk:path: CdkWorkshopStack/VPC/Resource
  VPCPublicSubnet1SubnetB4246D30:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: 10.0.0.0/24
      VpcId:
        Ref: VPCB9E5F0B4
      AvailabilityZone:
        Fn::Select:
          - 0
          - Fn::GetAZs: ""
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: CdkWorkshopStack/VPC/PublicSubnet1
        - Key: aws-cdk:subnet-name
          Value: Public
        - Key: aws-cdk:subnet-type
          Value: Public
    Metadata:
      aws:cdk:path: CdkWorkshopStack/VPC/PublicSubnet1/Subnet
  VPCPublicSubnet1RouteTableFEE4B781:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId:
        Ref: VPCB9E5F0B4
      Tags:
        - Key: Name
          Value: CdkWorkshopStack/VPC/PublicSubnet1
    Metadata:
      aws:cdk:path: CdkWorkshopStack/VPC/PublicSubnet1/RouteTable
  VPCPublicSubnet1RouteTableAssociation0B0896DC:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId:
        Ref: VPCPublicSubnet1RouteTableFEE4B781
      SubnetId:
        Ref: VPCPublicSubnet1SubnetB4246D30
    Metadata:
      aws:cdk:path: CdkWorkshopStack/VPC/PublicSubnet1/RouteTableAssociation
  VPCPublicSubnet1DefaultRoute91CEF279:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId:
        Ref: VPCPublicSubnet1RouteTableFEE4B781
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId:
        Ref: VPCIGWB7E252D3
    DependsOn:
      - VPCVPCGW99B986DC
    Metadata:
      aws:cdk:path: CdkWorkshopStack/VPC/PublicSubnet1/DefaultRoute
  VPCPublicSubnet2Subnet74179F39:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: 10.0.1.0/24
      VpcId:
        Ref: VPCB9E5F0B4
      AvailabilityZone:
        Fn::Select:
          - 1
          - Fn::GetAZs: ""
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: CdkWorkshopStack/VPC/PublicSubnet2
        - Key: aws-cdk:subnet-name
          Value: Public
        - Key: aws-cdk:subnet-type
          Value: Public
    Metadata:
      aws:cdk:path: CdkWorkshopStack/VPC/PublicSubnet2/Subnet
  VPCPublicSubnet2RouteTable6F1A15F1:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId:
        Ref: VPCB9E5F0B4
      Tags:
        - Key: Name
          Value: CdkWorkshopStack/VPC/PublicSubnet2
    Metadata:
      aws:cdk:path: CdkWorkshopStack/VPC/PublicSubnet2/RouteTable
  VPCPublicSubnet2RouteTableAssociation5A808732:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId:
        Ref: VPCPublicSubnet2RouteTable6F1A15F1
      SubnetId:
        Ref: VPCPublicSubnet2Subnet74179F39
    Metadata:
      aws:cdk:path: CdkWorkshopStack/VPC/PublicSubnet2/RouteTableAssociation
  VPCPublicSubnet2DefaultRouteB7481BBA:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId:
        Ref: VPCPublicSubnet2RouteTable6F1A15F1
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId:
        Ref: VPCIGWB7E252D3
    DependsOn:
      - VPCVPCGW99B986DC
    Metadata:
      aws:cdk:path: CdkWorkshopStack/VPC/PublicSubnet2/DefaultRoute
  VPCIGWB7E252D3:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: CdkWorkshopStack/VPC
    Metadata:
      aws:cdk:path: CdkWorkshopStack/VPC/IGW
  VPCVPCGW99B986DC:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId:
        Ref: VPCB9E5F0B4
      InternetGatewayId:
        Ref: VPCIGWB7E252D3
    Metadata:
      aws:cdk:path: CdkWorkshopStack/VPC/VPCGW
  CDKMetadata:
    Type: AWS::CDK::Metadata
    Properties:
      Modules: aws-cdk=1.18.0,@aws-cdk/aws-cloudwatch=1.18.0,@aws-cdk/aws-ec2=1.18.0,@aws-cdk/aws-iam=1.18.0,@aws-cdk/aws-ssm=1.18.0,@aws-cdk/core=1.18.0,@aws-cdk/cx-api=1.18.0,@aws-cdk/region-info=1.18.0,jsii-runtime=node.js/v11.15.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

```
リソース図は以下のようになります。
![new-designer (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458187/0793e1d8-d23c-1ccb-408d-773c5fa51ead.png)
定義したPublic Subnetのみが生成されていますね。
（Public Subnetは自動的に2つのAZに生成されています。）

不便なポイントはSubnetのCidr Blockを明示的に割り当てにくいところです。
今回、SubnetのCidr Blockは自動的に"10.0.0.0/24"と"10.0.1.0/24"に割り当てられています。
`subnetConfiguration`では`cidrMask`しか定義できないので、
「Cidr Blockを"10.0.1.0/24"と"10.0.2.0/24"に明示的に割り当てたい！」
みたいなカスタマイズをするのはちょっと不便そうです。

# Cfnコンストラクタ群を使ってCloudFormationのようにネットワークリソースを作ってみる
CDKにはCloudFormationと同様にリソースを定義できるコンストラクタ群があります。（例えば[CfnVPC](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.CfnVPC.html)）
今度はこのコンストラクタ群を使ってネットワークリソースを作っていきます。

```lib/cdk-workshop-stack.ts
import { App, Stack, StackProps, Tag } from '@aws-cdk/core'
import { CfnVPC, CfnInternetGateway, CfnVPCGatewayAttachment, CfnSubnet, CfnRouteTable, CfnRoute, CfnSubnetRouteTableAssociation } from '@aws-cdk/aws-ec2'

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

    // VPC
    const vpc = new CfnVPC(this, 'VPC', {
      cidrBlock: '10.0.0.0/16',
      enableDnsHostnames: true,
      enableDnsSupport: true,
      instanceTenancy: 'default',
    })

    // InternetGateway
    const igw = new CfnInternetGateway(this, 'igw', {
    })
    new CfnVPCGatewayAttachment(this, 'igwAttachment', {
      internetGatewayId: igw.ref,
      vpcId: vpc.ref
    })

    // Subnet
    const publicSubnet1 = new CfnSubnet(this, 'PublicSubnet1', {
      cidrBlock: '10.0.1.0/24',
      vpcId: vpc.ref,
      availabilityZone: this.availabilityZones[0]
    })
    const publicSubnet2 = new CfnSubnet(this, 'PublicSubnet2', {
      cidrBlock: '10.0.2.0/24',
      vpcId: vpc.ref,
      availabilityZone: this.availabilityZones[1]
    })

    //RouteTable
    const publicRouteTable = new CfnRouteTable(this, 'PublicRouteTable', {
      vpcId: vpc.ref,
    })
    new CfnRoute(this, 'PublicRoute', {
      routeTableId: publicRouteTable.ref,
      destinationCidrBlock: '0.0.0.0/0',
      gatewayId: igw.ref,
    })
    new CfnSubnetRouteTableAssociation(this, 'PublicSubnet1RouteTableAssociation', {
      routeTableId: publicRouteTable.ref,
      subnetId: publicSubnet1.ref
    })
    new CfnSubnetRouteTableAssociation(this, 'PublicSubnet2RouteTableAssociation', {
      routeTableId: publicRouteTable.ref,
      subnetId: publicSubnet2.ref
    })

    // Tag
    ;[
      vpc,
      igw,
      publicSubnet2,
      publicSubnet1,
      publicRouteTable
    ].forEach(construct => {
      Tag.add(construct, 'Application', id)
      Tag.add(construct, 'Name', construct.node.id)
    })
  }
}

```

出力されたテンプレートは以下の通りです。

```cdk-synth-result.yml
Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      EnableDnsHostnames: true
      EnableDnsSupport: true
      InstanceTenancy: default
      Tags:
        - Key: Application
          Value: CdkWorkshopStack
        - Key: Name
          Value: VPC
    Metadata:
      aws:cdk:path: CdkWorkshopStack/VPC
  igw:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Application
          Value: CdkWorkshopStack
        - Key: Name
          Value: igw
    Metadata:
      aws:cdk:path: CdkWorkshopStack/igw
  igwAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId:
        Ref: VPC
      InternetGatewayId:
        Ref: igw
    Metadata:
      aws:cdk:path: CdkWorkshopStack/igwAttachment
  PublicSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: 10.0.1.0/24
      VpcId:
        Ref: VPC
      AvailabilityZone:
        Fn::Select:
          - 0
          - Fn::GetAZs: ""
      Tags:
        - Key: Application
          Value: CdkWorkshopStack
        - Key: Name
          Value: PublicSubnet1
    Metadata:
      aws:cdk:path: CdkWorkshopStack/PublicSubnet1
  PublicSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: 10.0.2.0/24
      VpcId:
        Ref: VPC
      AvailabilityZone:
        Fn::Select:
          - 1
          - Fn::GetAZs: ""
      Tags:
        - Key: Application
          Value: CdkWorkshopStack
        - Key: Name
          Value: PublicSubnet2
    Metadata:
      aws:cdk:path: CdkWorkshopStack/PublicSubnet2
  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId:
        Ref: VPC
      Tags:
        - Key: Application
          Value: CdkWorkshopStack
        - Key: Name
          Value: PublicRouteTable
    Metadata:
      aws:cdk:path: CdkWorkshopStack/PublicRouteTable
  PublicRoute:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId:
        Ref: PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId:
        Ref: igw
    Metadata:
      aws:cdk:path: CdkWorkshopStack/PublicRoute
  PublicSubnet1RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId:
        Ref: PublicRouteTable
      SubnetId:
        Ref: PublicSubnet1
    Metadata:
      aws:cdk:path: CdkWorkshopStack/PublicSubnet1RouteTableAssociation
  PublicSubnet2RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId:
        Ref: PublicRouteTable
      SubnetId:
        Ref: PublicSubnet2
    Metadata:
      aws:cdk:path: CdkWorkshopStack/PublicSubnet2RouteTableAssociation
  CDKMetadata:
    Type: AWS::CDK::Metadata
    Properties:
      Modules: aws-cdk=1.18.0,@aws-cdk/aws-cloudwatch=1.18.0,@aws-cdk/aws-ec2=1.18.0,@aws-cdk/aws-iam=1.18.0,@aws-cdk/aws-ssm=1.18.0,@aws-cdk/core=1.18.0,@aws-cdk/cx-api=1.18.0,@aws-cdk/region-info=1.18.0,jsii-runtime=node.js/v11.15.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

```
リソース図は以下のようになります。
![new-designer (4).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458187/d43e929b-7bf2-b161-6276-e179a316b13b.png)

目標と同様の構成のネットワークリソースを生成することができました。
コード量は増えますが、現状Cfnコンストラクタ群を使った方がカスタマイズはしやすそうな感じがしますね。

# まとめ
AWS CDKを使って、既存のCloudFormationテンプレートのネットワークリソース部分を再現してみました。

最初に使ってみたVpcのようなコンストラクタが上手く使えると、一気にコード量を減らせそうですが、カスタマイズにやや制限があるので、そこにちょっと不便は感じます。
ただ、厳しいところはCfnコンストラクタで補うことができることが分かりました。

今回はネットワーク関連のリソースのみを再現しましたが、今後残りのリソースも再現してみます。
その中で、「リソース群ごとに子コンポーネントを分けて作成し、親に渡す」といったことも試していこうと思います。