Cloudformationを使用したNATゲートウェイ,VPCエンドポイントのオプション化

# 目的
題名にあるように、NATゲートウェイとVPCエンドポイント(インターフェイス型)をCloudformationの更新で手軽に作成・削除できるようにします。

# 背景
学習用の自己アカウントの場合、NATゲートウェイや、VPCエンドポイントは頻繁には使用しないけど、プライベートサブネットからの通信を試したい時とかだけに使用したいことってあると思います。

ですが、これらは作成してあるだけでお金が発生してしまうので、都度手動で作成・削除をする必要があります。
NATゲートウェイのルートテーブルの設定だったり、必要なエンドポイントが複数あったりすると、地味にめんどくさいです。

そこで、CloudformationのConditionsを使用して、使用したい時だけ作成できないかなと思い試しました。


# 実装
<details><summary>テンプレート</summary>

```yaml
AWSTemplateFormatVersion: "2010-09-09"

Parameters:
  VpcCidr:
    Type: String
  VpcId:
    Type: String
  PublicSubnetAId:
    Type: String
  PrivateVpceSubnetAId:
    Type: String
  PrivateRouteTableAId:
    Type: String
   
#Option
  NATGatewayA:
    Description: "Whether to use NAT Gateway"
    Type: String
    Default: "do not use"
    AllowedValues: 
      - "use"
      - "do not use"
  SessionManager:
    Description: "whether to use a session manager"
    Type: String
    Default: "do not use"
    AllowedValues: 
      - "use"
      - "do not use"
  
      
Metadata: 
  AWS::CloudFormation::Interface: 
    ParameterGroups: 
      - 
        Parameters: 
          - VpcCidr
          - VpcId
          - PublicSubnetAId
          - PrivateVpceSubnetAId
          - PrivateRouteTableAId
      - 
        Label: 
          default: "Option"
        Parameters: 
          - NATGatewayA
          - SessionManager

Conditions:
  IsNatGtwA: !Equals ["use", !Ref NATGatewayA]
  IsSessionManager: !Equals ["use", !Ref SessionManager]

Resources:      
# ------------------------------------------------------------# 
# NatGateway
# ------------------------------------------------------------# 
  NatGatewayA:
    Type: AWS::EC2::NatGateway
    Condition: IsNatGtwA
    Properties:
      AllocationId: !GetAtt NatGatewayEIPA.AllocationId
      SubnetId: !Ref PublicSubnetAId


# NATゲートウェイ用のEIP
  NatGatewayEIPA:
    Type: AWS::EC2::EIP
    Condition: IsNatGtwA
    Properties:
      Domain: vpc

# ------------------------------------------------------------#
# Routing
# ------------------------------------------------------------# 
# Private RouteA Create
  PrivateRouteA: 
    Type: "AWS::EC2::Route"
    Condition: IsNatGtwA
    Properties: 
      RouteTableId: !Ref PrivateRouteTableAId
      DestinationCidrBlock: "0.0.0.0/0"
      NatGatewayId: !Ref NatGatewayA  
      
# ------------------------------------------------------------#
#  SG
# ------------------------------------------------------------#          
# VPCエンドポイント用のSG
  VpceSg:
    Type: AWS::EC2::SecurityGroup
    Properties: 
      GroupDescription: "VpcEndpoint-SG"
      GroupName: "VpcEndpoint-Sg"
      SecurityGroupEgress: 
        - CidrIp: "0.0.0.0/0"
          FromPort: -1
          ToPort: -1
          IpProtocol: "-1"
      SecurityGroupIngress: 
        - CidrIp: !Ref VpcCidr
          Description: "VPC CIDR"
          FromPort: 443
          ToPort: 443
          IpProtocol: "tcp"
      VpcId: !Ref VpcId
      
      
# ------------------------------------------------------------#
#  VPC EndPoint
# ------------------------------------------------------------#
# セッションマネージャに必要なVPCエンドポイント(monitoring)
  VpcEndPointMonitoring:
    Type: AWS::EC2::VPCEndpoint
    Condition: IsSessionManager
    Properties: 
      PrivateDnsEnabled: true
      SecurityGroupIds: 
        - !Ref VpceSg
      ServiceName: !Sub "com.amazonaws.${AWS::Region}.monitoring"
      SubnetIds: 
        - !Ref PrivateVpceSubnetAId
      VpcEndpointType: "Interface"
      VpcId: !Ref VpcId

# セッションマネージャに必要なVPCエンドポイント(ssm)
  VpcEndPointSsm:
    Type: AWS::EC2::VPCEndpoint
    Condition: IsSessionManager
    Properties: 
      PrivateDnsEnabled: true
      SecurityGroupIds: 
        - !Ref VpceSg
      ServiceName: !Sub "com.amazonaws.${AWS::Region}.ssm"
      SubnetIds: 
        - !Ref PrivateVpceSubnetAId
      VpcEndpointType: "Interface"
      VpcId: !Ref VpcId

# セッションマネージャに必要なVPCエンドポイント(ssmmessages)
  VpcEndPointSsmMessege:
    Type: AWS::EC2::VPCEndpoint
    Condition: IsSessionManager
    Properties: 
      PrivateDnsEnabled: true
      SecurityGroupIds: 
        - !Ref VpceSg
      ServiceName: !Sub "com.amazonaws.${AWS::Region}.ssmmessages"
      SubnetIds: 
        - !Ref PrivateVpceSubnetAId
      VpcEndpointType: "Interface"
      VpcId: !Ref VpcId

# セッションマネージャに必要なVPCエンドポイント(ec2messages)
  VpcEndPointEc2Messege:
    Type: AWS::EC2::VPCEndpoint
    Condition: IsSessionManager
    Properties: 
      PrivateDnsEnabled: true
      SecurityGroupIds: 
        - !Ref VpceSg
      ServiceName: !Sub "com.amazonaws.${AWS::Region}.ec2messages"
      SubnetIds: 
        - !Ref PrivateVpceSubnetAId
      VpcEndpointType: "Interface"
      VpcId: !Ref VpcId

# セッションマネージャに必要なVPCエンドポイント(ec2)
  VpcEndPointEc2:
    Type: AWS::EC2::VPCEndpoint
    Condition: IsSessionManager
    Properties: 
      PrivateDnsEnabled: true
      SecurityGroupIds: 
        - !Ref VpceSg
      ServiceName: !Sub "com.amazonaws.${AWS::Region}.ec2"
      SubnetIds: 
        - !Ref PrivateVpceSubnetAId
      VpcEndpointType: "Interface"
      VpcId: !Ref VpcId
```
</details>

### 説明
- Parameters
    コメント(Option)以下でNatゲートウェイおよびセッションマネージャの使用有無を選択できるようにしています。
- Conditions
    それぞれのパラメータの値を判定する条件を定義しています。
    - 「use」と等しかった場合、true
    - 「use」以外(「do not use」)だった場合、false
- Resources
    - NatGatewayA,NatGatewayEIPAのConditionでConditionsで定義した条件を指定しています。
        IsNatGtwAの結果がtrueだった場合のみこれらのリソースは作成されます。
    - VPCエンドポイントの方も指定している条件が違うのみでやっていることは同じです。
        こちらでは条件にIsSessionManagerを指定しています。

### 作成・削除
①スタックの作成
![スクリーンショット 2023-07-15 17.34.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3472762/b1bab044-094b-8b94-8889-58d00fe269b6.png)

オプションをデフォルトの状態でスタックを作成します。
そうするとVPCエンドポイント用のSGのみ作成された状態になります。

②オプションを指定して作成
更新>現在のテンプレートの使用>オプションの値を変更
![スクリーンショット 2023-07-15 16.43.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3472762/82a99018-8f17-766c-6ca8-a4bb679906ce.png)
![スクリーンショット 2023-07-15 16.48.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3472762/3561c45f-bec5-0659-4f2f-224e63fd2e1f.png)
![スクリーンショット 2023-07-15 17.34.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3472762/47a819d6-5666-fd27-e4af-7131b23ec412.png)


更新が完了するとNATゲートウェイとセッションマネージャに必要なVPCエンドポイントが作成されます。
![スクリーンショット 2023-07-15 17.11.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3472762/085b6602-c706-5b46-3623-a32729c8fbf9.png)

③不要になったら削除
手順は作成の時と同じで、オプションの値を「do not use」に変更して、更新するだけです。

# 最後に
今回のようにプライベートサブネットにあるEC2にセッションマネージャを使用して接続したい場合、4つのVPCエンドポイントが必要になります。そんな時は更新一発で作成してくれるのはとても楽です。

自分と同じように、毎回作成・削除がめんどくさいなと感じている人の参考となれば幸いです。