aws-cdkで実運用を意識してインフラ構築していく VPC編

## はじめに

AWSの情報はいっぱいあるんですが、実際にどうサービスに実運用していくかは、やはり自分で考えていくものなので、こんな風に考えてこうやってますという紹介します。
AWSの環境構築方法は、今たくさんあると思いますが、ここでは `aws-cdk`を使って説明します。

※ 基本的なcdkの操作方法や用語の説明などは書きません。

## cdkによるIaCメリットとか

インフラのコード化は、「いつこの設定をしたっけ」がなくなります。

cdkの設定をコード管理しておけば、履歴を簡単に作成でき、更新や戻しも簡単です。
最初はCloudFormationテンプレートを直で作成して頑張ってやっていましたが、cdkを使った作成の方が直感的でわかりやすくスタック間の連携がしやすいのでメリットの方が多いです。

また、aws-cdkは頻繁に更新されるので割とcdkの内部的な処理変更でスタック更新を余儀なくされることがあり、設定自体の変更がなくても本番にdeployすることがよくあります。作業が増えるので、これをメリットと捉えるか難しいところですが、セキュリティパッチやNodeJSやRDSなどのバージョンのエンドタイムなどをちゃんと更新していくスタイルになります。(実際なりました)

## まずはVPCを作成していく

前置きはこれぐらいにして、一番最初に作るべきVPCを作っていきます。
cdkで作成するVPCは、CIDRや任意名で自由に作成したいので、L1 Construct(CfnVPCなど)で作成します。
ただ、L1で作ることで、L2で作ってるスタック間の連携がしにくくなったので、そこだけが難点です。

作成することができるリソースは以下です。

* VPC
* サブネット(IPv4, IPv6)
* インターネットゲートウェイ(IPv4, IPv6用のEgress専用)
* ルーティングテーブル
* NAT Gateway
* NAT Gateway用のEIP

以下のサンプルコードを使って説明していきます。
最初はtypescriptで書いていましたが、pythonの勉強とpythonのほうがインフラメインの自分にはわかりやすいという点でpythonにしました。typescriptでできることはpythonでほぼできると思います。

https://github.com/keiyow/sample-aws-cdk-vpc

## VPCネットワークの検討

ネットワークにも色々形があるので、それぞれを説明したいと思います。

### Multi-AZ Publicネットワーク x 2 / Privateネットワーク x 2 / NATGW冗長

本番では、ほぼこの構成です。
NAT GatewayはAZ毎に必要かどうかはありますが、FargateやLambdaをVPC内に配置するとアプリケーション側で外部通信をするパターンが確実にあり、AZ自体のダウンがあったりしても大丈夫なようにインフラとしては本番は冗長しときたいのでこの構成です。
ただし、費用もあがるので中・大規模の構成になると思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135107/d89da75a-394e-b642-f1c9-8e7962117f91.png)

サンプルコードでは以下のような内容です。
各AZのパブリック、プライベートネットワークをそれぞれ配置し、プライベートネットワークに配置されたリソースは各パブリックネットワークに配置したNAT Gatewayを通してインターネット外に通信できます。

```yaml:multi_with_nat.yaml
vpcCidr: 10.10.0.0/16
publicSubnets:
  - name: public1
    cidr: 10.10.0.0/24
    az: ap-northeast-1c
    nat: true
  - name: public2
    cidr: 10.10.1.0/24
    az: ap-northeast-1a
    nat: true
privateSubnets:
  - name: private1
    cidr: 10.10.2.0/24
    az: ap-northeast-1c
    nat: true
    natRoute: public1
  - name: private2
    cidr: 10.10.3.0/24
    az: ap-northeast-1a
    nat: true
    natRoute: public2
```

```bash
cdk diff --context stage=multi_with_nat --context service_name=test-multi-with-nat
Stack test-multi-with-nat-VpcStack
Parameters
[+] Parameter BootstrapVersion 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]"}

Resources
[+] AWS::EC2::VPC test-multi-with-nat-VPC testmultiwithnatVPC 
[+] AWS::EC2::InternetGateway test-multi-with-nat-Gateway testmultiwithnatGateway 
[+] AWS::EC2::VPCGatewayAttachment test-multi-with-nat-GatewayAttachment testmultiwithnatGatewayAttachment 
[+] AWS::EC2::RouteTable test-multi-with-nat-Route-Public testmultiwithnatRoutePublic 
[+] AWS::EC2::Route test-multi-with-nat-PublicRoute testmultiwithnatPublicRoute 
[+] AWS::EC2::Subnet test-multi-with-nat-Subnet-public1 testmultiwithnatSubnetpublic1 
[+] AWS::EC2::SubnetRouteTableAssociation test-multi-with-nat-Subnet-public1-Association testmultiwithnatSubnetpublic1Association 
[+] AWS::EC2::EIP test-multi-with-nat-EIP-public1 testmultiwithnatEIPpublic1 
[+] AWS::EC2::NatGateway test-multi-with-nat-NatGateway-public1 testmultiwithnatNatGatewaypublic1 
[+] AWS::EC2::Subnet test-multi-with-nat-Subnet-public2 testmultiwithnatSubnetpublic2 
[+] AWS::EC2::SubnetRouteTableAssociation test-multi-with-nat-Subnet-public2-Association testmultiwithnatSubnetpublic2Association 
[+] AWS::EC2::EIP test-multi-with-nat-EIP-public2 testmultiwithnatEIPpublic2 
[+] AWS::EC2::NatGateway test-multi-with-nat-NatGateway-public2 testmultiwithnatNatGatewaypublic2 
[+] AWS::EC2::Subnet test-multi-with-nat-Subnet-private1 testmultiwithnatSubnetprivate1 
[+] AWS::EC2::RouteTable test-multi-with-nat-Route-private1 testmultiwithnatRouteprivate1 
[+] AWS::EC2::SubnetRouteTableAssociation test-multi-with-nat-Subnet-private1-Association testmultiwithnatSubnetprivate1Association 
[+] AWS::EC2::Route test-multi-with-nat-private1-nat testmultiwithnatprivate1nat 
[+] AWS::EC2::Subnet test-multi-with-nat-Subnet-private2 testmultiwithnatSubnetprivate2 
[+] AWS::EC2::RouteTable test-multi-with-nat-Route-private2 testmultiwithnatRouteprivate2 
[+] AWS::EC2::SubnetRouteTableAssociation test-multi-with-nat-Subnet-private2-Association testmultiwithnatSubnetprivate2Association 
[+] AWS::EC2::Route test-multi-with-nat-private2-nat testmultiwithnatprivate2nat 

Outputs
[+] Output VPC VPC: {"Value":{"Ref":"testmultiwithnatVPC"},"Export":{"Name":"test-multi-with-nat-VPC"}}
[+] Output Subnet-public1 Subnetpublic1: {"Value":{"Ref":"testmultiwithnatSubnetpublic1"},"Export":{"Name":"test-multi-with-nat-Subnet-public1"}}
[+] Output Subnet-public2 Subnetpublic2: {"Value":{"Ref":"testmultiwithnatSubnetpublic2"},"Export":{"Name":"test-multi-with-nat-Subnet-public2"}}
[+] Output Subnet-private1 Subnetprivate1: {"Value":{"Ref":"testmultiwithnatSubnetprivate1"},"Export":{"Name":"test-multi-with-nat-Subnet-private1"}}
[+] Output Subnet-private2 Subnetprivate2: {"Value":{"Ref":"testmultiwithnatSubnetprivate2"},"Export":{"Name":"test-multi-with-nat-Subnet-private2"}}

Other Changes
[+] Unknown 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."}]}}


✨  Number of stacks with differences: 1
```

### Multi-AZ Publicネットワーク x 2 / Privateネットワーク x 2 / NATGW冗長 / IPv6有効

最近、IPv4パブリックアドレスが課金対象になり、IPv6化を進めているところも多いと思います。
まだ本番では変更していませんが、動的に変更できるので将来確実にIPv6ネットワークとのデュアルスタックモードにする予定です。
IPv4だけのネットワークと違い、以下をIPv6用として用意する必要があります。

* Egress Only Internet Gateway
* 各サブネットのデュアルスタック有効化
* IPv6では通信できない場合のNAT64/DNS64の有効化
* IPv6用のDHCP設定

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135107/3db3ee7d-eca9-92ef-a5cf-e1fa2daa2379.png)

サンプルコードでは以下のような内容です。
各AZのパブリック、プライベートネットワークをそれぞれ配置し、プライベートネットワークに配置されたリソースは各パブリックネットワークに配置したNAT Gatewayを通してインターネット外に通信できます。
IPv6を持っているリソースがプライベートネットワークに配置された場合、Egress Only Internetgatewayを使用して、IPv6が対応しているインターネット外に出ることができます。もしIPv6に対応していないサイトへのアクセスの場合でも、IPv4に変換され、参照することもできます。 [^1]

[^1]: NAT Gatewayが必須
    https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/nat-gateway-nat64-dns64.html#nat-gateway-nat64-what-is

```yaml:multi_with_nat_ipv6_dualstack.yaml
vpcCidr: 10.10.0.0/16
ipv6: true
amazon_provided_ipv6_cidr_block: true
publicSubnets:
  - name: public1
    cidr: 10.10.0.0/24
    az: ap-northeast-1c
    nat: true
    ipv6: true
  - name: public2
    cidr: 10.10.1.0/24
    az: ap-northeast-1a
    nat: true
    ipv6: true
privateSubnets:
  - name: private1
    cidr: 10.10.2.0/24
    az: ap-northeast-1c
    nat: true
    natRoute: public1
    ipv6: true
    dns64: true
  - name: private2
    cidr: 10.10.3.0/24
    az: ap-northeast-1a
    nat: true
    natRoute: public2
    ipv6: true
    dns64: true
```

```bash
cdk diff --context stage=multi_with_nat_ipv6_dualstack --context service_name=test-multi-with-nat-ipv6-dualstack
Stack test-multi-with-nat-ipv6-dualstack-VpcStack
Parameters
[+] Parameter BootstrapVersion 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]"}

Resources
[+] AWS::EC2::VPC test-multi-with-nat-ipv6-dualstack-VPC testmultiwithnatipv6dualstackVPC 
[+] AWS::EC2::InternetGateway test-multi-with-nat-ipv6-dualstack-Gateway testmultiwithnatipv6dualstackGateway 
[+] AWS::EC2::VPCGatewayAttachment test-multi-with-nat-ipv6-dualstack-GatewayAttachment testmultiwithnatipv6dualstackGatewayAttachment 
[+] AWS::EC2::RouteTable test-multi-with-nat-ipv6-dualstack-Route-Public testmultiwithnatipv6dualstackRoutePublic 
[+] AWS::EC2::Route test-multi-with-nat-ipv6-dualstack-PublicRoute testmultiwithnatipv6dualstackPublicRoute 
[+] AWS::EC2::EgressOnlyInternetGateway test-multi-with-nat-ipv6-dualstack-EgressGateway testmultiwithnatipv6dualstackEgressGateway 
[+] AWS::EC2::VPCCidrBlock test-multi-with-nat-ipv6-dualstack-IPv6-CidrBlock testmultiwithnatipv6dualstackIPv6CidrBlock 
[+] AWS::EC2::Route test-multi-with-nat-ipv6-dualstack-PublicRoute-IPv6 testmultiwithnatipv6dualstackPublicRouteIPv6 
[+] AWS::EC2::Subnet test-multi-with-nat-ipv6-dualstack-Subnet-public1 testmultiwithnatipv6dualstackSubnetpublic1 
[+] AWS::EC2::SubnetRouteTableAssociation test-multi-with-nat-ipv6-dualstack-Subnet-public1-Association testmultiwithnatipv6dualstackSubnetpublic1Association 
[+] AWS::EC2::EIP test-multi-with-nat-ipv6-dualstack-EIP-public1 testmultiwithnatipv6dualstackEIPpublic1 
[+] AWS::EC2::NatGateway test-multi-with-nat-ipv6-dualstack-NatGateway-public1 testmultiwithnatipv6dualstackNatGatewaypublic1 
[+] AWS::EC2::Subnet test-multi-with-nat-ipv6-dualstack-Subnet-public2 testmultiwithnatipv6dualstackSubnetpublic2 
[+] AWS::EC2::SubnetRouteTableAssociation test-multi-with-nat-ipv6-dualstack-Subnet-public2-Association testmultiwithnatipv6dualstackSubnetpublic2Association 
[+] AWS::EC2::EIP test-multi-with-nat-ipv6-dualstack-EIP-public2 testmultiwithnatipv6dualstackEIPpublic2 
[+] AWS::EC2::NatGateway test-multi-with-nat-ipv6-dualstack-NatGateway-public2 testmultiwithnatipv6dualstackNatGatewaypublic2 
[+] AWS::EC2::Subnet test-multi-with-nat-ipv6-dualstack-Subnet-private1 testmultiwithnatipv6dualstackSubnetprivate1 
[+] AWS::EC2::RouteTable test-multi-with-nat-ipv6-dualstack-Route-private1 testmultiwithnatipv6dualstackRouteprivate1 
[+] AWS::EC2::SubnetRouteTableAssociation test-multi-with-nat-ipv6-dualstack-Subnet-private1-Association testmultiwithnatipv6dualstackSubnetprivate1Association 
[+] AWS::EC2::Route test-multi-with-nat-ipv6-dualstack-private1-IPv6 testmultiwithnatipv6dualstackprivate1IPv6 
[+] AWS::EC2::Route test-multi-with-nat-ipv6-dualstack-private1-nat testmultiwithnatipv6dualstackprivate1nat 
[+] AWS::EC2::Route test-multi-with-nat-ipv6-dualstack-private1-nat-ipv6 testmultiwithnatipv6dualstackprivate1natipv6 
[+] AWS::EC2::Subnet test-multi-with-nat-ipv6-dualstack-Subnet-private2 testmultiwithnatipv6dualstackSubnetprivate2 
[+] AWS::EC2::RouteTable test-multi-with-nat-ipv6-dualstack-Route-private2 testmultiwithnatipv6dualstackRouteprivate2 
[+] AWS::EC2::SubnetRouteTableAssociation test-multi-with-nat-ipv6-dualstack-Subnet-private2-Association testmultiwithnatipv6dualstackSubnetprivate2Association 
[+] AWS::EC2::Route test-multi-with-nat-ipv6-dualstack-private2-IPv6 testmultiwithnatipv6dualstackprivate2IPv6 
[+] AWS::EC2::Route test-multi-with-nat-ipv6-dualstack-private2-nat testmultiwithnatipv6dualstackprivate2nat 
[+] AWS::EC2::Route test-multi-with-nat-ipv6-dualstack-private2-nat-ipv6 testmultiwithnatipv6dualstackprivate2natipv6 

Outputs
[+] Output VPC VPC: {"Value":{"Ref":"testmultiwithnatipv6dualstackVPC"},"Export":{"Name":"test-multi-with-nat-ipv6-dualstack-VPC"}}
[+] Output Subnet-public1 Subnetpublic1: {"Value":{"Ref":"testmultiwithnatipv6dualstackSubnetpublic1"},"Export":{"Name":"test-multi-with-nat-ipv6-dualstack-Subnet-public1"}}
[+] Output Subnet-public2 Subnetpublic2: {"Value":{"Ref":"testmultiwithnatipv6dualstackSubnetpublic2"},"Export":{"Name":"test-multi-with-nat-ipv6-dualstack-Subnet-public2"}}
[+] Output Subnet-private1 Subnetprivate1: {"Value":{"Ref":"testmultiwithnatipv6dualstackSubnetprivate1"},"Export":{"Name":"test-multi-with-nat-ipv6-dualstack-Subnet-private1"}}
[+] Output Subnet-private2 Subnetprivate2: {"Value":{"Ref":"testmultiwithnatipv6dualstackSubnetprivate2"},"Export":{"Name":"test-multi-with-nat-ipv6-dualstack-Subnet-private2"}}

Other Changes
[+] Unknown 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."}]}}


✨  Number of stacks with differences: 1
```


### Multi-AZ Publicネットワーク x 2 / Privateネットワーク x 2 / NATGW１台

開発環境ではこの構成です。
基本、cdkを使って構築しているため、構成のテストという観点で本番に近い形を作っています。
欠点としてはNatGatewayは高価なので、NAT用インスタンスを用意して組んだ方がコストは安いです。
またAZの障害時に、Fargateなどのアプリケーション処理でインターネット外に繋ぐ通信がある場合は、NAT Gatewayが繋がらないことのリスクがあります。(なのでdev)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135107/c5ca8004-e6ed-4863-b554-cda510fb5eee.png)

サンプルコードでは以下のような内容です。
各AZのパブリック、プライベートネットワークをそれぞれ配置し、各プライベートネットワークに配置されたリソースは片方のパブリックネットワークに配置したNAT Gatewayを通してインターネット外に通信できます。


```yaml:multi_with_single_nat.yaml
vpcCidr: 10.10.0.0/16
publicSubnets:
  - name: public1
    cidr: 10.10.0.0/24
    az: ap-northeast-1c
    nat: true
  - name: public2
    cidr: 10.10.1.0/24
    az: ap-northeast-1a
    nat: false
privateSubnets:
  - name: private1
    cidr: 10.10.2.0/24
    az: ap-northeast-1c
    nat: true
    natRoute: public1
  - name: private2
    cidr: 10.10.3.0/24
    az: ap-northeast-1a
    nat: true
    natRoute: public1
```

```bash
cdk diff --context stage=multi_with_single_nat --context service_name=test-multi-with-single-nat
Stack test-multi-with-single-nat-VpcStack
Parameters
[+] Parameter BootstrapVersion 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]"}

Resources
[+] AWS::EC2::VPC test-multi-with-single-nat-VPC testmultiwithsinglenatVPC 
[+] AWS::EC2::InternetGateway test-multi-with-single-nat-Gateway testmultiwithsinglenatGateway 
[+] AWS::EC2::VPCGatewayAttachment test-multi-with-single-nat-GatewayAttachment testmultiwithsinglenatGatewayAttachment 
[+] AWS::EC2::RouteTable test-multi-with-single-nat-Route-Public testmultiwithsinglenatRoutePublic 
[+] AWS::EC2::Route test-multi-with-single-nat-PublicRoute testmultiwithsinglenatPublicRoute 
[+] AWS::EC2::Subnet test-multi-with-single-nat-Subnet-public1 testmultiwithsinglenatSubnetpublic1 
[+] AWS::EC2::SubnetRouteTableAssociation test-multi-with-single-nat-Subnet-public1-Association testmultiwithsinglenatSubnetpublic1Association 
[+] AWS::EC2::EIP test-multi-with-single-nat-EIP-public1 testmultiwithsinglenatEIPpublic1 
[+] AWS::EC2::NatGateway test-multi-with-single-nat-NatGateway-public1 testmultiwithsinglenatNatGatewaypublic1 
[+] AWS::EC2::Subnet test-multi-with-single-nat-Subnet-public2 testmultiwithsinglenatSubnetpublic2 
[+] AWS::EC2::SubnetRouteTableAssociation test-multi-with-single-nat-Subnet-public2-Association testmultiwithsinglenatSubnetpublic2Association 
[+] AWS::EC2::Subnet test-multi-with-single-nat-Subnet-private1 testmultiwithsinglenatSubnetprivate1 
[+] AWS::EC2::RouteTable test-multi-with-single-nat-Route-private1 testmultiwithsinglenatRouteprivate1 
[+] AWS::EC2::SubnetRouteTableAssociation test-multi-with-single-nat-Subnet-private1-Association testmultiwithsinglenatSubnetprivate1Association 
[+] AWS::EC2::Route test-multi-with-single-nat-private1-nat testmultiwithsinglenatprivate1nat 
[+] AWS::EC2::Subnet test-multi-with-single-nat-Subnet-private2 testmultiwithsinglenatSubnetprivate2 
[+] AWS::EC2::RouteTable test-multi-with-single-nat-Route-private2 testmultiwithsinglenatRouteprivate2 
[+] AWS::EC2::SubnetRouteTableAssociation test-multi-with-single-nat-Subnet-private2-Association testmultiwithsinglenatSubnetprivate2Association 
[+] AWS::EC2::Route test-multi-with-single-nat-private2-nat testmultiwithsinglenatprivate2nat 

Outputs
[+] Output VPC VPC: {"Value":{"Ref":"testmultiwithsinglenatVPC"},"Export":{"Name":"test-multi-with-single-nat-VPC"}}
[+] Output Subnet-public1 Subnetpublic1: {"Value":{"Ref":"testmultiwithsinglenatSubnetpublic1"},"Export":{"Name":"test-multi-with-single-nat-Subnet-public1"}}
[+] Output Subnet-public2 Subnetpublic2: {"Value":{"Ref":"testmultiwithsinglenatSubnetpublic2"},"Export":{"Name":"test-multi-with-single-nat-Subnet-public2"}}
[+] Output Subnet-private1 Subnetprivate1: {"Value":{"Ref":"testmultiwithsinglenatSubnetprivate1"},"Export":{"Name":"test-multi-with-single-nat-Subnet-private1"}}
[+] Output Subnet-private2 Subnetprivate2: {"Value":{"Ref":"testmultiwithsinglenatSubnetprivate2"},"Export":{"Name":"test-multi-with-single-nat-Subnet-private2"}}

Other Changes
[+] Unknown 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."}]}}


✨  Number of stacks with differences: 1
```

### Multi-AZ Publicネットワーク x 2 / Isolatedネットワーク x 2

NATを置かない構成です。
cdkで構築すると、Privateネットワークがインターネットへ繋がらない構成にすると、Isolatedネットワークとして認識されます。
CloudFront + ALB + EC2(public配置) + RDS(Isolated配置)という構成を作るなどに使っています。
ただ、LambdaやCodeBuild [^2] などをVPCに配置したい場合、インターネットに繋がらないと駄目ということがあり、あまりこの構成を使用することはありません。

[^2]: CodeBuildはパブリックネットワークに設置できないので、NATが必須
    https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/vpc-support.html

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135107/a27473a0-2d04-f6e7-ffa0-caf1a3b53529.png)

サンプルコードでは以下のような内容です。
各AZのパブリック、プライベート(Isolated)ネットワークをそれぞれ配置します。

```yaml:multi_with_no_nat.yaml
vpcCidr: 10.10.0.0/16
publicSubnets:
  - name: public1
    cidr: 10.10.0.0/24
    az: ap-northeast-1c
    nat: false
  - name: public2
    cidr: 10.10.1.0/24
    az: ap-northeast-1a
    nat: false
privateSubnets:
  - name: private1
    cidr: 10.10.2.0/24
    az: ap-northeast-1c
    nat: false
    natRoute: public1
  - name: private2
    cidr: 10.10.3.0/24
    az: ap-northeast-1a
    nat: false
    natRoute: public2
```

```bash
 cdk diff --context stage=multi_with_no_nat --context service_name=test-multi-with-no-nat
Stack test-multi-with-no-nat-VpcStack
Parameters
[+] Parameter BootstrapVersion 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]"}

Resources
[+] AWS::EC2::VPC test-multi-with-no-nat-VPC testmultiwithnonatVPC 
[+] AWS::EC2::InternetGateway test-multi-with-no-nat-Gateway testmultiwithnonatGateway 
[+] AWS::EC2::VPCGatewayAttachment test-multi-with-no-nat-GatewayAttachment testmultiwithnonatGatewayAttachment 
[+] AWS::EC2::RouteTable test-multi-with-no-nat-Route-Public testmultiwithnonatRoutePublic 
[+] AWS::EC2::Route test-multi-with-no-nat-PublicRoute testmultiwithnonatPublicRoute 
[+] AWS::EC2::Subnet test-multi-with-no-nat-Subnet-public1 testmultiwithnonatSubnetpublic1 
[+] AWS::EC2::SubnetRouteTableAssociation test-multi-with-no-nat-Subnet-public1-Association testmultiwithnonatSubnetpublic1Association 
[+] AWS::EC2::Subnet test-multi-with-no-nat-Subnet-public2 testmultiwithnonatSubnetpublic2 
[+] AWS::EC2::SubnetRouteTableAssociation test-multi-with-no-nat-Subnet-public2-Association testmultiwithnonatSubnetpublic2Association 
[+] AWS::EC2::Subnet test-multi-with-no-nat-Subnet-private1 testmultiwithnonatSubnetprivate1 
[+] AWS::EC2::RouteTable test-multi-with-no-nat-Route-private1 testmultiwithnonatRouteprivate1 
[+] AWS::EC2::SubnetRouteTableAssociation test-multi-with-no-nat-Subnet-private1-Association testmultiwithnonatSubnetprivate1Association 
[+] AWS::EC2::Subnet test-multi-with-no-nat-Subnet-private2 testmultiwithnonatSubnetprivate2 
[+] AWS::EC2::RouteTable test-multi-with-no-nat-Route-private2 testmultiwithnonatRouteprivate2 
[+] AWS::EC2::SubnetRouteTableAssociation test-multi-with-no-nat-Subnet-private2-Association testmultiwithnonatSubnetprivate2Association 

Outputs
[+] Output VPC VPC: {"Value":{"Ref":"testmultiwithnonatVPC"},"Export":{"Name":"test-multi-with-no-nat-VPC"}}
[+] Output Subnet-public1 Subnetpublic1: {"Value":{"Ref":"testmultiwithnonatSubnetpublic1"},"Export":{"Name":"test-multi-with-no-nat-Subnet-public1"}}
[+] Output Subnet-public2 Subnetpublic2: {"Value":{"Ref":"testmultiwithnonatSubnetpublic2"},"Export":{"Name":"test-multi-with-no-nat-Subnet-public2"}}
[+] Output Subnet-private1 Subnetprivate1: {"Value":{"Ref":"testmultiwithnonatSubnetprivate1"},"Export":{"Name":"test-multi-with-no-nat-Subnet-private1"}}
[+] Output Subnet-private2 Subnetprivate2: {"Value":{"Ref":"testmultiwithnonatSubnetprivate2"},"Export":{"Name":"test-multi-with-no-nat-Subnet-private2"}}

Other Changes
[+] Unknown 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."}]}}


✨  Number of stacks with differences: 1
```


### Single-AZ Publicネットワーク x 1 / Privateネットワーク x 1 / NATGW１台 

メリットがないので、この構成はすることがほぼないです。
ALBなどAZが二つ以上指定必須なので、この構成は使いません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135107/0e5f3c6a-245d-f6f1-5540-58bcaa451b7c.png)

サンプルコードでは以下のような内容です。
各AZのパブリック、プライベートネットワークを配置し、プライベートネットワークに配置されたリソースはパブリックネットワークに配置したNAT Gatewayを通してインターネット外に通信できます。

```yaml:multi_with_single_nat.yaml
vpcCidr: 10.10.0.0/16
publicSubnets:
  - name: public1
    cidr: 10.10.0.0/24
    az: ap-northeast-1c
    nat: true
privateSubnets:
  - name: private1
    cidr: 10.10.2.0/24
    az: ap-northeast-1c
    nat: true
    natRoute: public1
```

```bash
cdk diff --context stage=single_with_nat --context service_name=test-single-with-nat
Stack test-single-with-nat-VpcStack
Parameters
[+] Parameter BootstrapVersion 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]"}

Resources
[+] AWS::EC2::VPC test-single-with-nat-VPC testsinglewithnatVPC 
[+] AWS::EC2::InternetGateway test-single-with-nat-Gateway testsinglewithnatGateway 
[+] AWS::EC2::VPCGatewayAttachment test-single-with-nat-GatewayAttachment testsinglewithnatGatewayAttachment 
[+] AWS::EC2::RouteTable test-single-with-nat-Route-Public testsinglewithnatRoutePublic 
[+] AWS::EC2::Route test-single-with-nat-PublicRoute testsinglewithnatPublicRoute 
[+] AWS::EC2::Subnet test-single-with-nat-Subnet-public1 testsinglewithnatSubnetpublic1 
[+] AWS::EC2::SubnetRouteTableAssociation test-single-with-nat-Subnet-public1-Association testsinglewithnatSubnetpublic1Association 
[+] AWS::EC2::EIP test-single-with-nat-EIP-public1 testsinglewithnatEIPpublic1 
[+] AWS::EC2::NatGateway test-single-with-nat-NatGateway-public1 testsinglewithnatNatGatewaypublic1 
[+] AWS::EC2::Subnet test-single-with-nat-Subnet-private1 testsinglewithnatSubnetprivate1 
[+] AWS::EC2::RouteTable test-single-with-nat-Route-private1 testsinglewithnatRouteprivate1 
[+] AWS::EC2::SubnetRouteTableAssociation test-single-with-nat-Subnet-private1-Association testsinglewithnatSubnetprivate1Association 
[+] AWS::EC2::Route test-single-with-nat-private1-nat testsinglewithnatprivate1nat 

Outputs
[+] Output VPC VPC: {"Value":{"Ref":"testsinglewithnatVPC"},"Export":{"Name":"test-single-with-nat-VPC"}}
[+] Output Subnet-public1 Subnetpublic1: {"Value":{"Ref":"testsinglewithnatSubnetpublic1"},"Export":{"Name":"test-single-with-nat-Subnet-public1"}}
[+] Output Subnet-private1 Subnetprivate1: {"Value":{"Ref":"testsinglewithnatSubnetprivate1"},"Export":{"Name":"test-single-with-nat-Subnet-private1"}}

Other Changes
[+] Unknown 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."}]}}


✨  Number of stacks with differences: 1
```

## 終わりに

cdkを使えば、後からでも動的に変更できるのが利点です
ここではVPCだけを説明しましたが、スタック間連携して別のリソースを作っていく説明も書ければと思います。