【小ネタ】CloudFormationでNAT GWをRouteTableに割り当てると失敗する【CloudFormation】

# はじめに
VPCおよびSubnet/RouteTable等をCloudFormationで作成するにあたり、NAT Gatewayの利用が上手くいきませんでした。
結構誰でも見落としてハマりがちなポイントのように思えましたので、記録しておきます。

# 事象
CloudFormationのStack作成中、NAT GatewayをRouteTableに割り当てた際に失敗する。

具体的には「AWS::EC2::Route」Resourceの作成中に動きが止まり、5分後（恐らくStack作成時のタイムアウト）に下記のように、「Route did not stabilize in expected time」というメッセージが出力され、StackがRollbackします。

![2018-09-08_21h52_32.png](https://qiita-image-store.s3.amazonaws.com/0/137777/815ffd33-48d5-a415-ed9a-e69159435560.png)


# 原因
templateの記述間違いです。
Internet GatewayをRouteTableに割り当てる場合と、NAT Gatewayを割り当てる場合とで、指定するProperty名が違います。

公式のナレッジセンターにも情報がありました。

[CloudFormation のルートが安定しない](https://aws.amazon.com/jp/premiumsupport/knowledge-center/cloudformation-route-did-not-stabilize/)

# 詳細
## 正しい設定
### Internet Gateway
まず、Internet Gatewayをデフォルトルート（0.0.0.0/0宛）として割り当てる場合の定義を示します。
以下のResourceはすでに定義済みであるものとします。

- VPC
- InternetGateway
- InternetGatewayAttachment

ここで、「AWS::EC2::Route」であるDefaultPublicRouteに指定するPropertyは「**GatewayId**」です。

```yaml
Resources:
# 途中省略
  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC

  DefaultPublicRoute:
    Type: AWS::EC2::Route
    DependsOn: InternetGatewayAttachment
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway

```

### NAT Gateway
次に、NAT Gatewayをデフォルトルート（0.0.0.0/0宛）として割り当てる場合の定義を示します。
以下のResourceはすでに定義済みであるものとします。

- NatGateway1

ここで、「AWS::EC2::Route」であるDefaultPrivateRouteに指定するPropertyは「**NatGatewayId**」です。

```yaml
Resources:
# 途中省略
  PrivateRouteTable:
    Type: AWS::EC2::RouteTable
    Condition: enableNatGw
    Properties:
      VpcId: !Ref VPC

  DefaultPrivateRoute:
    Type: AWS::EC2::Route
    Condition: enableNatGw
    Properties:
      RouteTableId: !Ref PrivateRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      NatGatewayId: !Ref NatGateway1
```

## 間違った設定
うっかり下記のような設定をしてしまいがちなので注意しましょう。
「AWS::EC2::Route」でNAT Gatewayを指定する場合は、「**GatewayId**」ではなく「**NatGatewayId**」が正しいです。

```yaml
Resources:
# 途中省略
  PrivateRouteTable:
    Type: AWS::EC2::RouteTable
    Condition: enableNatGw
    Properties:
      VpcId: !Ref VPC

  DefaultPrivateRoute:
    Type: AWS::EC2::Route
    Condition: enableNatGw
    Properties:
      RouteTableId: !Ref PrivateRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref NatGateway1 # ←間違い
```


# 公式ドキュメント

AWS::EC2::Route - AWS CloudFormation
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-route.html#cfn-ec2-route-natgatewayid

## GatwayId
GatewayIdを指定する場合は、Internet GatewayかVirtual Private Gateway（VPN接続の時に利用する仮想ルータのようなもの）のみです。

> GatewayId
> The ID of an internet gateway or virtual private gateway that is attached to your VPC. For example: igw-eaad4883.
> 
> For route entries that specify a gateway, you must specify a dependency on the gateway attachment resource. For more information, see DependsOn Attribute.
> 
> Required: Conditional. You must specify only one of the following properties: EgressOnlyInternetGatewayId, GatewayId, InstanceId, NatGatewayId, NetworkInterfaceId, or VpcPeeringConnectionId.
> 
> Type: String
> 
> Update requires: No interruption

## NatGatwayId
NAT Gatewayを利用する場合は、NatGatewayIdを指定します。

> NatGatewayId
> The ID of a NAT gateway. For example, nat-0a12bc456789de0fg.
> 
> Required: Conditional. You must specify only one of the following properties: EgressOnlyInternetGatewayId, GatewayId, InstanceId, NatGatewayId, NetworkInterfaceId, or VpcPeeringConnectionId.
> 
> Type: String
> 
> Update requires: No interruption