【私の懺悔を聞いてくれ】パブリックサブネットとプライベートサブネット

# 本記事の内容
いろいろな参考書等で間違ったまま覚えてしまっていたがため、一日を無駄にしたので
同じ間違いを繰り返して欲しくないために記載しています。

# 本記事の対象者
AWSを始めたばっかりの人向け

# 本記事の概要
サブネットがパブリックになるかプライベートになるかを決めるのはルートテーブルだ！！

# あらまし
https://qiita.com/kazumasamatsumo/items/7013cd312bd5c0967fe1
この記事みなさん読んでくださってありがとうございます。

このお仕事の続きで結構ハマった部分を懺悔もかねてお話ししていきます。

## まず今回したかったことは
CloudFormationで
パブリックにアクセスできるサブネットを作るパターンと
プライベートにして外部アクセスできないパターンと
NAT Gatewayにして構築するパターンの3つを依頼されています。

僕自身最初に出した結論は
「サブネットを作り直せばいいやん」

という結論でした。

だって
「プライベートサブネット」
「パブリックサブネット」

って習ってきたので、そう思うではないですか。

## けど違った・・・
サブネットをパブリックにするかプライベートにするかは
「ルートテーブル」
だったのです。

特にここが本当にややこしかった。
ざっくり説明すると

「RouteTable」に
「Gateway ID」を紐付けると外部との接続ができる。

そのGateway IDが
Publicの場合は「インターネットゲートウェイ」になります。

Gateway IDが
Privateサブネット内部からインターネットに出たい場合は
Privateなんだけど「NAT Gateway」になります。

Gateway IDを設定しない場合は
完全なるPrivate サブネットになります。

## つまりサブネットは作り直す必要はないのです。
必要なのはRouteTableの構成のみ
WorkSpaces専用のサブネットを作ろうとしています。

```yaml
AWSTemplateFormatVersion: "2010-09-09"
Description: 
  VPC and Subnet Create
# ------------------------------------------------------------#
# Metadata
# ------------------------------------------------------------# 
Metadata: 
  "AWS::CloudFormation::Interface": 
    ParameterGroups: 
      - Label: 
          default: "Project Name Prefix"
        Parameters: 
          - PJPrefix
      - Label: 
          default: "Network Configuration"
        Parameters: 
          - WorkSpacesSubnetACIDR
          - WorkSpacesSubnetCCIDR
    ParameterLabels: 
      WorkSpacesSubnetACIDR: 
        default: "WorkSpaces PublicSubnetA CIDR"
      WorkSpacesSubnetCCIDR: 
        default: "WorkSpaces PublicSubnetC CIDR"
# ------------------------------------------------------------#
# Input Parameters
# ------------------------------------------------------------# 
Parameters:
  PJPrefix:
    Description: Enter a prefix of this system.
    Type: String
    Default: "test"
    AllowedPattern: "[a-zA-Z][a-zA-Z0-9][ -~]*"
    ConstraintDescription: must begin with a letter and contain only alphanumeric characters.

  WorkSpacesSubnetACIDR:
    Type: String
    Default: "10.3.100.0/24"
    MinLength: 9
    MaxLength: 18
    AllowedPattern: (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})
    ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x. Min characters 9, Max characters 18.

  WorkSpacesSubnetCCIDR:
    Type: String
    Default: "10.3.101.0/24"
    MinLength: 9
    MaxLength: 18
    AllowedPattern: (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})
    ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x. Min characters 9, Max characters 18.

Resources:
# ------------------------------------------------------------#
#  Subnet
# ------------------------------------------------------------#          
# Public SubnetA Create
  WorkSpacesSubnetA: 
    Type: "AWS::EC2::Subnet"
    Properties: 
      AvailabilityZone: "ap-northeast-1a"
      CidrBlock: !Ref WorkSpacesSubnetACIDR
      VpcId: { "Fn::ImportValue": !Sub "${PJPrefix}-vpc" }
      Tags: 
        - Key: Name
          Value: !Sub "${PJPrefix}-workspaces-subnet-a"

# Public SubnetC Create
  WorkSpacesSubnetC: 
    Type: "AWS::EC2::Subnet"
    Properties: 
      AvailabilityZone: "ap-northeast-1c"
      CidrBlock: !Ref WorkSpacesSubnetCCIDR
      VpcId: { "Fn::ImportValue": !Sub "${PJPrefix}-vpc" }
      Tags: 
        - Key: Name
          Value: !Sub "${PJPrefix}-workspaces-subnet-c"

# ------------------------------------------------------------#
#  NetworkACL 事前に作成していてsubnetに対してアクセスコントロールを実施したい時に設定する
# ------------------------------------------------------------#
# PublicNetworkAcl Create
  WorkSpacesNetworkAcl:
    Type: "AWS::EC2::NetworkAcl"
    Properties:
      VpcId: { "Fn::ImportValue": !Sub "${PJPrefix}-vpc" }
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-workspaces-network-acl
# ------------------------------------------------------------#
#  NetworkACL Entry
# ------------------------------------------------------------#          
# PublicNetworkAclEntryTrue Create
  WorkSpacesNetworkAclEntryTrue:
    Type: "AWS::EC2::NetworkAclEntry"
    Properties:
      CidrBlock: "0.0.0.0/0"
      Egress: true
      NetworkAclId: !Ref WorkSpacesNetworkAcl
      Protocol: -1
      RuleAction: "allow"
      RuleNumber: 100

# PublicNetworkAclEntryFalse Create
  WorkSpacesNetworkAclEntryFalse:
    Type: "AWS::EC2::NetworkAclEntry"
    Properties:
      CidrBlock: "0.0.0.0/0"
      Egress: false
      NetworkAclId: !Ref WorkSpacesNetworkAcl
      Protocol: -1
      RuleAction: "allow"
      RuleNumber: 100

# ------------------------------------------------------------#
# Network Association
# ------------------------------------------------------------#
# PublicSubnetANetworkAssociation Create
  WorkSpacesSubnetANetworkAssociation:
    Type: "AWS::EC2::SubnetNetworkAclAssociation"
    Properties:
      SubnetId: !Ref WorkSpacesSubnetA
      NetworkAclId: !Ref WorkSpacesNetworkAcl

# PublicSubnetCNetworkAssociation Create
  WorkSpacesSubnetCNetworkAssociation:
    Type: "AWS::EC2::SubnetNetworkAclAssociation"
    Properties:
      SubnetId: !Ref WorkSpacesSubnetC
      NetworkAclId: !Ref WorkSpacesNetworkAcl


# ------------------------------------------------------------#
# Output Parameters
# ------------------------------------------------------------#
Outputs:
# Subnet
  WorkSpacesSubnetA:
    Value: !Ref WorkSpacesSubnetA
    Export:
      Name: !Sub "${PJPrefix}-workspaces-subnet-a"

  WorkSpacesSubnetC:
    Value: !Ref WorkSpacesSubnetC
    Export:
      Name: !Sub "${PJPrefix}-workspaces-subnet-c"
```

この時点で作成されるのは
これらのリソース
![スクリーンショット 2020-08-27 18.56.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253981/d95c542b-2858-394c-9326-1a01cc93c31c.png)


NetWorkAclを作成している理由はあとで作るより先に作っていてあとでマネジメントコンソールで編集すればいいやという発想です。
NetWorkAclを制御したい時がSubnetのネットワーク全体を制御したい時なので何かあった時にスタックを作って制御より先に作っておいて何かあったら制御すればいいや。みたいな感じです。

## さて作られたサブネットをみてみよう

![スクリーンショット 2020-08-27 18.57.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253981/6cc619c3-b60a-788b-b734-898f16eedce1.png)
![スクリーンショット 2020-08-27 18.57.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253981/88860309-d4fd-f0e2-6547-eb9c85fcd923.png)

二つともルートテーブルが作られている
けどこのルートテーブルは外に対して何もアクセスできないのでPrivateというわけ。

## PublicRouteTableを作成してInternetGatewayに紐づけてみる

```yaml
AWSTemplateFormatVersion: "2010-09-09"
Description: 
  Routing Create

Parameters:
  PJPrefix:
    Description: Enter a prefix of this system.
    Type: String
    Default: "test"
    AllowedPattern: "[a-zA-Z][a-zA-Z0-9][ -~]*"
    ConstraintDescription: must begin with a letter and contain only alphanumeric characters.

Resources:
  # ------------------------------------------------------------#
#  RouteTable
# ------------------------------------------------------------#
# Public RouteTableA Create
  WorkSpacesPublicRouteTableA:
    Type: "AWS::EC2::RouteTable"
    Properties:
      VpcId: { "Fn::ImportValue": !Sub "${PJPrefix}-vpc" }
      Tags:
        - Key: Name
          Value: !Sub "${PJPrefix}-workspaces-public-route-a"

  WorkSpacesPublicRouteTableC:
    Type: "AWS::EC2::RouteTable"
    Properties:
      VpcId: { "Fn::ImportValue": !Sub "${PJPrefix}-vpc" }
      Tags:
        - Key: Name
          Value: !Sub "${PJPrefix}-workspaces-public-route-c"
# ------------------------------------------------------------#
# Routing
# ------------------------------------------------------------# 
# PublicRouteA Create
  WorkSpacesPublicRouteA:
    Type: "AWS::EC2::Route"
    Properties:
      RouteTableId: !Ref WorkSpacesPublicRouteTableA
      DestinationCidrBlock: "0.0.0.0/0"
      GatewayId: { "Fn::ImportValue": !Sub "${PJPrefix}-internet-gateway" }

# PublicRouteA Create
  WorkSpacesPublicRouteC:
    Type: "AWS::EC2::Route"
    Properties:
      RouteTableId: !Ref WorkSpacesPublicRouteTableC
      DestinationCidrBlock: "0.0.0.0/0"
      GatewayId: { "Fn::ImportValue": !Sub "${PJPrefix}-internet-gateway" }
# ------------------------------------------------------------#
# RouteTable Associate
# ------------------------------------------------------------# 
# PublicRouteTable Associate SubnetA
  PublicSubnetARouteTableAssociation: 
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties: 
      SubnetId: { "Fn::ImportValue": !Sub "${PJPrefix}-workspaces-subnet-a" }
      RouteTableId: !Ref WorkSpacesPublicRouteTableA

# PublicRouteTable Associate SubnetC
  PublicSubnetCRouteTableAssociation: 
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties: 
      SubnetId: { "Fn::ImportValue": !Sub "${PJPrefix}-workspaces-subnet-c" }
      RouteTableId: !Ref WorkSpacesPublicRouteTableC
```

InternetGatewayは事前に作っています。
こちらのスタックを実行すると

リソースはこんな感じ
RouteTableを編集するのではなく新たに作ろうという発想です。
![スクリーンショット 2020-08-27 19.02.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253981/76aaa53e-9203-de60-fafd-06fac61dcff7.png)

確認してみましょう。
![スクリーンショット 2020-08-27 19.03.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253981/58ad235b-05b6-82ed-ad9e-7d07fae6e069.png)
![スクリーンショット 2020-08-27 19.04.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253981/1f937713-954e-f87a-f40a-990e8eca62fc.png)

この状態でRouteTableにInternetGatewayが紐づいているので、ようやくこのサブネットは外部と接続ができる状態になったというわけです。

次に外に繋げないオリジナルのRouteTableを作成します。（外部接続をシャットダウンする時とNAT Gatewayを使う時のために作成します）

```yaml
AWSTemplateFormatVersion: "2010-09-09"
Description: 
  Routing Create

Parameters:
  PJPrefix:
    Description: Enter a prefix of this system.
    Type: String
    Default: "test"
    AllowedPattern: "[a-zA-Z][a-zA-Z0-9][ -~]*"
    ConstraintDescription: must begin with a letter and contain only alphanumeric characters.

Resources:
# ------------------------------------------------------------#
#  RouteTable
# ------------------------------------------------------------#
# Public RouteTableA Create
  WorkSpacesPrivateRouteTableA:
    Type: "AWS::EC2::RouteTable"
    Properties:
      VpcId: { "Fn::ImportValue": !Sub "${PJPrefix}-vpc" }
      Tags:
        - Key: Name
          Value: !Sub "${PJPrefix}-workspaces-public-route-a"

  WorkSpacesPrivateRouteTableC:
    Type: "AWS::EC2::RouteTable"
    Properties:
      VpcId: { "Fn::ImportValue": !Sub "${PJPrefix}-vpc" }
      Tags:
        - Key: Name
          Value: !Sub "${PJPrefix}-workspaces-public-route-c"

# ------------------------------------------------------------#
# RouteTable Associate
# ------------------------------------------------------------#
# PublicRouteTable Associate SubnetA
  PublicSubnetARouteTableAssociation:
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties:
      SubnetId: { "Fn::ImportValue": !Sub "${PJPrefix}-workspaces-subnet-a" }
      RouteTableId: !Ref WorkSpacesPrivateRouteTableA

# PublicRouteTable Associate SubnetC
  PublicSubnetCRouteTableAssociation:
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties:
      SubnetId: { "Fn::ImportValue": !Sub "${PJPrefix}-workspaces-subnet-c" }
      RouteTableId: !Ref WorkSpacesPrivateRouteTableC

Outputs:
  WorkSpacesPrivateRouteTableA:
    Value: !Ref WorkSpacesPrivateRouteTableA
    Export:
      Name: !Sub "${PJPrefix}-workspaces-private-route-a"

  WorkSpacesPrivateRouteTableC:
    Value: !Ref WorkSpacesPrivateRouteTableC
    Export:
      Name: !Sub "${PJPrefix}-workspaces-private-route-c"
```

ちなみにVPCは他のスタックで作成しているので、あしからず

![スクリーンショット 2020-08-27 19.07.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253981/53fa0af2-ade1-5c71-8206-f26052832803.png)

完成したリソース

subnetをみてみるとRouteTableの名前に「kazumasa0509」とは入っているが
IGWは接続されていないことを確認できます。
![スクリーンショット 2020-08-27 19.08.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253981/37e593b0-692a-3e14-5fad-8f380c0bcd68.png)
![スクリーンショット 2020-08-27 19.09.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253981/c5f41089-edb0-e7d7-d977-66f0c3a58abd.png)

## NAT Gatewayに紐づけてみます

```yaml
AWSTemplateFormatVersion: "2010-09-09"
Description: 
  NAT Gateway Create

Parameters:
  PJPrefix:
    Description: Enter a prefix of this system.
    Type: String
    Default: "test"
    AllowedPattern: "[a-zA-Z][a-zA-Z0-9][ -~]*"
    ConstraintDescription: must begin with a letter and contain only alphanumeric characters.


# ------------------------------------------------------------#
# NAT Gateway AZ:A
# ------------------------------------------------------------#                
# NATGatewayA Create
Resources:
  NATGatewayA:
    Type: "AWS::EC2::NatGateway"
    Properties:
      AllocationId: !GetAtt NATGatewayAEIP.AllocationId
      SubnetId:
       Fn::ImportValue:
        !Sub "${PJPrefix}-workspaces-subnet-a"
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-natgw-a

# NATGateway For EIP Create
  NATGatewayAEIP:
    Type: "AWS::EC2::EIP"
    Properties:
      Domain: vpc

# PrivateRouteA Create
  PrivateRouteA:
    Type: "AWS::EC2::Route"
    Properties:
      RouteTableId:
       Fn::ImportValue:
         !Sub "${PJPrefix}-workspaces-private-route-a"
      DestinationCidrBlock: "0.0.0.0/0"
      NatGatewayId: !Ref NATGatewayA

# ------------------------------------------------------------#
# NAT Gateway AZ:C
# ------------------------------------------------------------#                
# NATGatewayC Create
  NATGatewayC:
    Type: "AWS::EC2::NatGateway"
    Properties:
      AllocationId: !GetAtt NATGatewayCEIP.AllocationId
      SubnetId:
       Fn::ImportValue:
        !Sub "${PJPrefix}-workspaces-subnet-c"
      Tags:
        - Key: Name
          Value: !Sub ${PJPrefix}-natgw-c

# NATGateway For EIP Create
  NATGatewayCEIP:
    Type: "AWS::EC2::EIP"
    Properties:
      Domain: vpc

# PrivateRouteC Create
  PrivateRouteC:
    Type: "AWS::EC2::Route"
    Properties:
      RouteTableId:
       Fn::ImportValue:
         !Sub "${PJPrefix}-workspaces-private-route-c"
      DestinationCidrBlock: "0.0.0.0/0"
      NatGatewayId: !Ref NATGatewayC

# ------------------------------------------------------------#
# Output Parameters
# ------------------------------------------------------------#                
Outputs:
  # NATGateway EIP
  NATGatewayAEIP:
    Value: !Ref NATGatewayAEIP
    Export:
      Name: !Sub "${PJPrefix}-natgw-a-eip"

  NATGatewayCEIP:
    Value: !Ref NATGatewayCEIP
    Export:
      Name: !Sub "${PJPrefix}-natgw-c-eip"
```

出力されたリソース
![スクリーンショット 2020-08-27 19.14.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253981/3c625834-55a4-0de3-c905-c3543f9379f0.png)

サブネットを確認する
![スクリーンショット 2020-08-27 19.14.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253981/8f9ccfb4-5eb9-9c5e-e650-f3ea060a33fd.png)
![スクリーンショット 2020-08-27 19.14.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253981/dde9c40b-6ce4-d3fa-b8f9-732cce32df31.png)

ルートテーブルの名前が紛らわしいのでややこしいのだが、
しっかりとNATに切り替わっている。

もちろんルートテーブルの関連付けの編集でそれぞれ選択できる

![スクリーンショット 2020-08-27 19.19.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253981/3bb8129c-ce3c-cf47-22b0-4c323adda68a.png)

## もう一度
サブネットはサブネット。
サブネットに紐づくルートテーブルにどのゲートウェイを接続させるかでそのサブネットの特性が変わります。
参考資料
https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/VPC_Subnets.html


# 編集後記
この記事を一旦限定公開にして社内共有しました！！
そうするとたくさんのアドバイスがもらえました！！

## Kさんからのアドバイス
・Cloudformationテンプレ見て気になったこと
　・NetworkACLは不要(デフォルトのまま)
　・サブネット名に pub or pri を明示的につけると何のサブネットなのか後から分かりやすい
　・Dzone用のサブネットも作った方が良い
　・ルートテーブルとサブネットは明示的に紐づけた方がいい（以下参考にしてください）

```yaml
AWSTemplateFormatVersion: 2010-09-09
Metadata:
    Generator: former2
Description: ""
Parameters: 
    Prefix:
        Type: String
        Default: office-network
        Description: Prefix of this system generic name.
    Environment:
        Type: String
        Default: prd
        Description: Type of this environment.
        AllowedValues:
            - prd
            - stg
            - dev

Resources:
    EC2EIP:
        Type: AWS::EC2::EIP
        Properties:
            Domain: vpc
            Tags: 
              - 
                Key: Name
                Value: !Sub ${Environment}-${Prefix}-ngw-a

    EC2VPC:
        Type: AWS::EC2::VPC
        Properties:
            CidrBlock: 172.16.0.0/16
            EnableDnsSupport: true
            EnableDnsHostnames: false
            InstanceTenancy: default
            Tags: 
              - 
                Key: Name
                Value: !Sub ${Environment}-${Prefix}

    EC2PubSubnet:
        Type: AWS::EC2::Subnet
        Properties:
            AvailabilityZone: !Sub ${AWS::Region}a
            CidrBlock: 172.16.0.0/24
            VpcId: !Ref EC2VPC
            MapPublicIpOnLaunch: false
            Tags: 
              - 
                Key: Name
                Value: !Sub ${Environment}-${Prefix}-public-a

    EC2PubSubnet2:
        Type: AWS::EC2::Subnet
        Properties:
            AvailabilityZone: !Sub ${AWS::Region}c
            CidrBlock: 172.16.1.0/24
            VpcId: !Ref EC2VPC
            MapPublicIpOnLaunch: false
            Tags: 
              - 
                Key: Name
                Value: !Sub ${Environment}-${Prefix}-public-c

    EC2PubSubnet3:
        Type: AWS::EC2::Subnet
        Properties:
            AvailabilityZone: !Sub ${AWS::Region}d
            CidrBlock: 172.16.2.0/24
            VpcId: !Ref EC2VPC
            MapPublicIpOnLaunch: false
            Tags: 
              - 
                Key: Name
                Value: !Sub ${Environment}-${Prefix}-public-d

    EC2PriSubnet:
        Type: AWS::EC2::Subnet
        Properties:
            AvailabilityZone: !Sub ${AWS::Region}a
            CidrBlock: 172.16.100.0/24
            VpcId: !Ref EC2VPC
            MapPublicIpOnLaunch: false
            Tags: 
              - 
                Key: Name
                Value: !Sub ${Environment}-${Prefix}-private-a

    EC2PriSubnet2:
        Type: AWS::EC2::Subnet
        Properties:
            AvailabilityZone: !Sub ${AWS::Region}c
            CidrBlock: 172.16.101.0/24
            VpcId: !Ref EC2VPC
            MapPublicIpOnLaunch: false
            Tags: 
              - 
                Key: Name
                Value: !Sub ${Environment}-${Prefix}-private-c

    EC2PriSubnet3:
        Type: AWS::EC2::Subnet
        Properties:
            AvailabilityZone: !Sub ${AWS::Region}d
            CidrBlock: 172.16.102.0/24
            VpcId: !Ref EC2VPC
            MapPublicIpOnLaunch: false
            Tags: 
              - 
                Key: Name
                Value: !Sub ${Environment}-${Prefix}-private-d

    EC2PubRouteTable:
        Type: AWS::EC2::RouteTable
        Properties:
            VpcId: !Ref EC2VPC
            Tags: 
              - 
                Key: Name
                Value: !Sub ${Environment}-${Prefix}-public-route

    EC2PriRouteTable:
        Type: AWS::EC2::RouteTable
        Properties:
            VpcId: !Ref EC2VPC
            Tags: 
              - 
                Key: Name
                Value: !Sub ${Environment}-${Prefix}-private-route

    EC2PubSubnetAssociation:
        Type: AWS::EC2::SubnetRouteTableAssociation
        Properties: 
            RouteTableId: !Ref EC2PubRouteTable
            SubnetId: !Ref EC2PubSubnet

    EC2PubSubnetAssociation2:
        Type: AWS::EC2::SubnetRouteTableAssociation
        Properties: 
            RouteTableId: !Ref EC2PubRouteTable
            SubnetId: !Ref EC2PubSubnet2

    EC2PubSubnetAssociation3:
        Type: AWS::EC2::SubnetRouteTableAssociation
        Properties: 
            RouteTableId: !Ref EC2PubRouteTable
            SubnetId: !Ref EC2PubSubnet3

    EC2PriSubnetAssociation:
        Type: AWS::EC2::SubnetRouteTableAssociation
        Properties: 
            RouteTableId: !Ref EC2PriRouteTable
            SubnetId: !Ref EC2PriSubnet

    EC2PriSubnetAssociation2:
        Type: AWS::EC2::SubnetRouteTableAssociation
        Properties: 
            RouteTableId: !Ref EC2PriRouteTable
            SubnetId: !Ref EC2PriSubnet2

    EC2PriSubnetAssociation3:
        Type: AWS::EC2::SubnetRouteTableAssociation
        Properties: 
            RouteTableId: !Ref EC2PriRouteTable
            SubnetId: !Ref EC2PriSubnet3

    EC2VPCDHCPOptionsAssociation:
        Type: AWS::EC2::VPCDHCPOptionsAssociation
        Properties:
            DhcpOptionsId: !Ref EC2VPCDHCPOptions
            VpcId: !Ref EC2VPC

    EC2InternetGateway:
        Type: AWS::EC2::InternetGateway
        Properties: 
            Tags: 
              -
                Key: Name
                Value: !Sub ${Environment}-${Prefix}-igw

    EC2VPCGatewayAttachment:
        Type: AWS::EC2::VPCGatewayAttachment
        Properties:
            InternetGatewayId:  !Ref EC2InternetGateway
            VpcId: !Ref EC2VPC

    EC2NatGateway:
        Type: AWS::EC2::NatGateway
        Properties:
            SubnetId: !Ref EC2PubSubnet
            AllocationId: !GetAtt EC2EIP.AllocationId
            Tags: 
              - 
                Key: Name
                Value: !Sub ${Environment}-${Prefix}-ngw

    EC2NGWRoute:
        Type: AWS::EC2::Route
        Properties:
            DestinationCidrBlock: 0.0.0.0/0
            NatGatewayId: !Ref EC2NatGateway
            RouteTableId: !Ref EC2PriRouteTable

    EC2IGWRoute:
        Type: AWS::EC2::Route
        Properties:
            DestinationCidrBlock: 0.0.0.0/0
            GatewayId: !Ref EC2InternetGateway
            RouteTableId: !Ref EC2PubRouteTable
```

なるほど確かにPubとPriを書くだけでもなんのサブネットなのかわかりやすくなります！！
ただルートテーブルが決めるということは忘れないでおこうと思います。
サブネット自体にプライベートやパブリックがあると1年近く勘違いしていたので。。。

あとDzone用のサブネットも作った方が良いというのは初めてでした。
こちらの記事を是非とも読んでいただきたいです。
https://www.itmedia.co.jp/news/articles/1908/28/news127.html

## Gさんからのアドバイス

```
そもそもprivate subnetって必要ですか？
security gorup で適切に管理していればよいのでは？
※nat gateway 高いし！
という観点があるかと思うのです！
```

( ﾟдﾟ)ﾊｯ!
確かに・・・

さらに

```
private subnetについてですが、今回の案件に限らず
そもそもとしてAWSを使う際、private subnetが本当に必要なのか？　は疑問です（個人的に）
調べるとprivate subnetを使う理由は出るのですが、常にクリティカルになる条件はなさそうなんですよね。
※要件によってはprivate subnetでないと難しいパターンもありますが。
```

怖い、文字から伝わってくる圧がすごい。
というわけなので、ここはしっかり先輩に聞いて記事にしようかなと思います。