CloudFormationでのAWSネットワーク構築①：VPC、サブネット、インターネットゲートウェイ、NATゲートウェイ、ルートテーブルの設定

## はじめに
AWS環境でのネットワーク設定は、各リソースを適切に構築・設定する必要があるため手動で行うとミスや負荷が発生しやすくなります。

:::note warn
**そこで、ネットワーク構築の作業を自動化する手段として、AWSのCloudFormationを利用することで効率的かつ信頼性の高い構成管理が可能です。**
:::

この記事では、VPC、サブネット、インターネットゲートウェイ、NATゲートウェイ、ルートテーブルを含む基本的なネットワーク構成をCloudFormationテンプレートで実現する方法について解説します。

## 知識整理
まず、AWSネットワークの基本コンポーネントとその役割を整理しましょう。

### VPC（Virtual Private Cloud）
AWS上で仮想ネットワークを構築するための基本的なネットワーク環境。サブネットやインターネット接続の基盤を提供します。

### インターネットゲートウェイ
VPC内のパブリックサブネットのリソースがインターネットにアクセスできるようにするコンポーネント。

### NATゲートウェイ
プライベートサブネットから外部インターネットへのアクセスを可能にし、セキュリティを高めるコンポーネント。プライベートIPを保持したまま外部リソースへのアクセスができます。

### サブネット
VPC内でのIPアドレス範囲を指定するためのセグメントで、パブリックサブネットとプライベートサブネットを定義して異なるリソースを配置します。

### ルートテーブル
サブネットの通信ルートを管理するための設定です。インターネットゲートウェイやNATゲートウェイを通じたルートを定義します。

### CloudFormation
AWS CloudFormationは、AWSリソースをコード化して自動的に管理・構築するためのサービスです。

:::note warn
インフラを「Infrastructure as Code (IaC)」として扱い、テンプレートを利用してリソースの定義・変更・削除が可能です。
:::

## 実際にやってみた
以下では、これらのリソースをCloudFormationテンプレートで実装する手順を紹介します。

### 1. VPCの設定
まず、VPCを作成します。今回はCIDRブロック「10.0.0.0/16」を使用しています。

```yaml
MyVpc:
  Type: "AWS::EC2::VPC"
  Properties:
    CidrBlock: "10.0.0.0/16"
    EnableDnsHostnames: true
    Tags:
      - Key: Name
        Value: "プロジェクト-vpc"
```

### 2. インターネットゲートウェイの作成とアタッチ
次に、インターネットアクセスを有効にするためのインターネットゲートウェイを作成し、VPCにアタッチします。 

```yaml
MyInternetGateway:
  Type: "AWS::EC2::InternetGateway"
  Properties:
    Tags:
      - Key: Name
        Value: "プロジェクト-igw"

AttachInternetGateway:
  Type: "AWS::EC2::VPCGatewayAttachment"
  Properties:
    VpcId: !Ref MyVpc
    InternetGatewayId: !Ref MyInternetGateway
```

### 3. NATゲートウェイの作成
プライベートサブネットからインターネットへのアクセスを提供するためにNATゲートウェイを作成します。

まずElastic IPを作成し、NATゲートウェイにアタッチします。

```yaml
NatElasticIp:
  Type: "AWS::EC2::EIP"
  Properties:
    Domain: "vpc"
    Tags:
      - Key: Name
        Value: "プロジェクト-eip-ap-northeast-1a"

MyNatGateway:
  Type: "AWS::EC2::NatGateway"
  Properties:
    SubnetId: !Ref PublicSubnet1
    AllocationId: !GetAtt NatElasticIp.AllocationId
    Tags:
      - Key: Name
        Value: "プロジェクト-nat-public1-ap-northeast-1a"
```

### 4. サブネットの作成
VPC内にパブリックサブネットとプライベートサブネットを作成します。

```yaml
PublicSubnet1:
  Type: "AWS::EC2::Subnet"
  Properties:
    VpcId: !Ref MyVpc
    CidrBlock: "10.0.0.0/20"
    AvailabilityZone: "ap-northeast-1a"
    Tags:
      - Key: Name
        Value: "プロジェクト-subnet-public1-ap-northeast-1a"

PrivateSubnet1:
  Type: "AWS::EC2::Subnet"
  Properties:
    VpcId: !Ref MyVpc
    CidrBlock: "10.0.128.0/20"
    AvailabilityZone: "ap-northeast-1a"
    Tags:
      - Key: Name
        Value: "プロジェクト-subnet-private1-ap-northeast-1a"
```

### 5. ルートテーブルとルート設定
サブネットの通信ルートを設定します。

まず、パブリックサブネットのルートテーブルを作成し、インターネットゲートウェイへのデフォルトルートを追加します。

```yaml
PublicRouteTable:
  Type: "AWS::EC2::RouteTable"
  Properties:
    VpcId: !Ref MyVpc
    Tags:
      - Key: Name
        Value: "プロジェクト-rtb-public"

PublicRoute:
  Type: "AWS::EC2::Route"
  Properties:
    RouteTableId: !Ref PublicRouteTable
    DestinationCidrBlock: "0.0.0.0/0"
    GatewayId: !Ref MyInternetGateway
```

プライベートサブネットのルートテーブルにはNATゲートウェイを経由するルートを設定します。

```yaml
PrivateRoute1:
  Type: "AWS::EC2::Route"
  Properties:
    RouteTableId: !Ref PrivateRouteTable1
    DestinationCidrBlock: "0.0.0.0/0"
    NatGatewayId: !Ref MyNatGateway
```

## 完成したコード

CloudFormationにアップロードしてスタックを作成することで、同様のネットワーク構成がプロビジョニングされます。

```yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: "CloudFormation template for creating VPC, Subnets, Internet Gateway, NAT Gateway, and Route Tables"

Resources:
  # VPC
  MyVpc:
    Type: "AWS::EC2::VPC"
    Properties:
      CidrBlock: "10.0.0.0/16"
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: "プロジェクト-vpc"

  # Internet Gateway
  MyInternetGateway:
    Type: "AWS::EC2::InternetGateway"
    Properties:
      Tags:
        - Key: Name
          Value: "プロジェクト-igw"

  AttachInternetGateway:
    Type: "AWS::EC2::VPCGatewayAttachment"
    Properties:
      VpcId: !Ref MyVpc
      InternetGatewayId: !Ref MyInternetGateway

  # Elastic IP for NAT Gateway
  NatElasticIp:
    Type: "AWS::EC2::EIP"
    Properties:
      Domain: "vpc"
      Tags:
        - Key: Name
          Value: "プロジェクト-eip-ap-northeast-1a"

  # NAT Gateway
  MyNatGateway:
    Type: "AWS::EC2::NatGateway"
    Properties:
      SubnetId: !Ref PublicSubnet1
      AllocationId: !GetAtt NatElasticIp.AllocationId
      Tags:
        - Key: Name
          Value: "プロジェクト-nat-public1-ap-northeast-1a"

  # Public Subnets
  PublicSubnet1:
    Type: "AWS::EC2::Subnet"
    Properties:
      VpcId: !Ref MyVpc
      CidrBlock: "10.0.0.0/20"
      AvailabilityZone: "ap-northeast-1a"
      Tags:
        - Key: Name
          Value: "プロジェクト-subnet-public1-ap-northeast-1a"

  PublicSubnet2:
    Type: "AWS::EC2::Subnet"
    Properties:
      VpcId: !Ref MyVpc
      CidrBlock: "10.0.16.0/20"
      AvailabilityZone: "ap-northeast-1c"
      Tags:
        - Key: Name
          Value: "プロジェクト-subnet-public2-ap-northeast-1c"

  # Private Subnets
  PrivateSubnet1:
    Type: "AWS::EC2::Subnet"
    Properties:
      VpcId: !Ref MyVpc
      CidrBlock: "10.0.128.0/20"
      AvailabilityZone: "ap-northeast-1a"
      Tags:
        - Key: Name
          Value: "プロジェクト-subnet-private1-ap-northeast-1a"

  PrivateSubnet2:
    Type: "AWS::EC2::Subnet"
    Properties:
      VpcId: !Ref MyVpc
      CidrBlock: "10.0.144.0/20"
      AvailabilityZone: "ap-northeast-1c"
      Tags:
        - Key: Name
          Value: "プロジェクト-subnet-private2-ap-northeast-1c"

  # Public Route Table
  PublicRouteTable:
    Type: "AWS::EC2::RouteTable"
    Properties:
      VpcId: !Ref MyVpc
      Tags:
        - Key: Name
          Value: "プロジェクト-rtb-public"

  PublicRoute:
    Type: "AWS::EC2::Route"
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: "0.0.0.0/0"
      GatewayId: !Ref MyInternetGateway

  # Associate Public Subnets with Public Route Table
  PublicSubnet1RouteTableAssociation:
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties:
      SubnetId: !Ref PublicSubnet1
      RouteTableId: !Ref PublicRouteTable

  PublicSubnet2RouteTableAssociation:
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties:
      SubnetId: !Ref PublicSubnet2
      RouteTableId: !Ref PublicRouteTable

  # Private Route Tables
  PrivateRouteTable1:
    Type: "AWS::EC2::RouteTable"
    Properties:
      VpcId: !Ref MyVpc
      Tags:
        - Key: Name
          Value: "プロジェクト-rtb-private1-ap-northeast-1a"

  PrivateRouteTable2:
    Type: "AWS::EC2::RouteTable"
    Properties:
      VpcId: !Ref MyVpc
      Tags:
        - Key: Name
          Value: "プロジェクト-rtb-private2-ap-northeast-1c"

  # Routes for Private Subnets via NAT Gateway
  PrivateRoute1:
    Type: "AWS::EC2::Route"
    Properties:
      RouteTableId: !Ref PrivateRouteTable1
      DestinationCidrBlock: "0.0.0.0/0"
      NatGatewayId: !Ref MyNatGateway

  PrivateRoute2:
    Type: "AWS::EC2::Route"
    Properties:
      RouteTableId: !Ref PrivateRouteTable2
      DestinationCidrBlock: "0.0.0.0/0"
      NatGatewayId: !Ref MyNatGateway

  # Associate Private Subnets with Private Route Tables
  PrivateSubnet1RouteTableAssociation:
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties:
      SubnetId: !Ref PrivateSubnet1
      RouteTableId: !Ref PrivateRouteTable1

  PrivateSubnet2RouteTableAssociation:
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties:
      SubnetId: !Ref PrivateSubnet2
      RouteTableId: !Ref PrivateRouteTable2
```


## まとめ
以上のCloudFormationテンプレートにより、VPCやサブネット、インターネットゲートウェイ、NATゲートウェイ、ルートテーブルといったAWSネットワークの基本構成を自動化できます。

:::note 
**CloudFormationを使うことで、手作業による設定ミスを減らし、再利用可能なテンプレートとしてネットワーク構成を管理できるようになります。**
:::

特に、ネットワーク構成が複雑になる場合や、構成管理の一環としてインフラをコード化するIaCの概念を取り入れたい場合に有効です。

## 参考文献

https://dev.classmethod.jp/articles/cloudformation-beginner01/