CloudFormationによるAWSネットワーク構築②：VPC環境の構築とパブリックサブネット内への踏み台サーバー設置

## はじめに
AWS (Amazon Web Services) の CloudFormation は、インフラストラクチャの構成をコード化するためのサービスです。

:::note
**これを使用することで、インフラを手動で設定する代わりに、コード（テンプレート）を記述してリソースのプロビジョニングや管理を自動化できます。**
:::

この記事では、CloudFormationを使用してAWS上にVPC（仮想プライベートクラウド）、サブネット、NATゲートウェイ、インターネットゲートウェイ、踏み台サーバーなどのインフラを構築するためのYAMLテンプレートを解説します。

## CloudFormationとは
CloudFormationは、AWSのリソースをコードとして記述し、これをもとにインフラを自動で構築、更新、管理するためのサービスです。

**CloudFormationでは、リソースの作成に必要な情報をYAMLまたはJSON形式のテンプレートとして記述します。**

このテンプレートを基にAWSがリソースを作成し、指定された設定に従ってインフラを整備します。

:::note warn
**CloudFormationを使用することのメリットには、インフラの再現性、バージョン管理、環境間の一貫性、運用の自動化などが挙げられます。**
:::

これにより、開発者や運用者は手動で設定を行う手間を省き、迅速かつ効率的にインフラの構築を行うことができます。

https://qiita.com/Nightley_dev/items/9ba1cf1744d8ae9fe021

## yamlファイルの中身について
次に、CloudFormationテンプレートのYAMLファイルの内容について詳細に解説します。

### VPCの作成
このセクションでは、AWSに仮想ネットワークであるVPC（Virtual Private Cloud）を作成します。

VPCは、AWS上で他のリソースと隔離された環境を提供するため、アプリケーションやサービスが安全に動作する基盤となります。

```yaml
HondaVpc:
  Type: AWS::EC2::VPC
  Properties:
    CidrBlock: 10.0.0.0/16
    EnableDnsSupport: true
    EnableDnsHostnames: true
    InstanceTenancy: default
    Tags:
      - Key: Name
        Value: ホンダ-vpc
```

ここでは ``10.0.0.0/16`` としています。``EnableDnsSupport`` と ``EnableDnsHostnames`` は、DNSサポートを有効にし、インスタンスにホスト名を付与できるように設定しています。

### パブリックサブネットの作成
次に、VPC内にパブリックサブネットを作成します。パブリックサブネットはインターネットゲートウェイと接続され、インターネットと通信できるリソースが配置されます。

ここでは2つのパブリックサブネット（``PublicSubnet1、PublicSubnet2``）が作成されます。

```yaml
PublicSubnet1:
  Type: AWS::EC2::Subnet
  Properties:
    VpcId: !Ref HondaVpc
    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 HondaVpc
    CidrBlock: 10.0.16.0/20
    AvailabilityZone: ap-northeast-1c
    Tags:
      - Key: Name
        Value: ホンダ-subnet-public2-ap-northeast-1c
```

これらのサブネットは、VPC HondaVpc内で作成され、``CidrBlock``はそれぞれ``10.0.0.0/20と10.0.16.0/20``となっており、それぞれ異なる可用性ゾーン（``ap-northeast-1a`` と ``ap-northeast-1c``）に配置されます。

これにより、冗長性と高可用性が確保されます。

### プライベートサブネットの作成
プライベートサブネットは、外部インターネットと直接接続せず、NATゲートウェイを通じてインターネットと通信します。VPC内に複数のプライベートサブネットを作成します。

```yaml
PrivateSubnet1:
  Type: AWS::EC2::Subnet
  Properties:
    VpcId: !Ref HondaVpc
    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 HondaVpc
    CidrBlock: 10.0.144.0/20
    AvailabilityZone: ap-northeast-1c
    Tags:
      - Key: Name
        Value: ホンダ-subnet-private2-ap-northeast-1c
```

ここでは、``PrivateSubnet1``と``PrivateSubnet2``が作成され、それぞれのCIDRブロックは``10.0.128.0/20``と``10.0.144.0/20``です。

プライベートサブネットは、インターネットから直接アクセスされないため、セキュリティが強化されます。

### インターネットゲートウェイとNATゲートウェイの設定
インターネットゲートウェイは、VPC内のリソースとインターネットを接続するためのゲートウェイです。

このゲートウェイを使用することで、VPC内のパブリックサブネットに配置されたインスタンスがインターネットにアクセスできるようになります。

```yaml
InternetGateway:
  Type: AWS::EC2::InternetGateway
  Properties:
    Tags:
      - Key: Name
        Value: ホンダ-igw
```

このInternetGatewayリソースはVPCの外部との接続を可能にし、パブリックサブネットからインターネットにアクセスできるようにします。

### NATゲートウェイの作成
NATゲートウェイは、プライベートサブネット内のインスタンスがインターネットにアクセスするために使用されます。

プライベートサブネットは直接インターネットと接続せず、NATゲートウェイを通じて通信します。

```yaml
NatGateway:
  Type: AWS::EC2::NatGateway
  Properties:
    SubnetId: !Ref PublicSubnet1
    AllocationId: !GetAtt ElasticIP1.AllocationId
    Tags:
      - Key: Name
        Value: ホンダ-nat-public1-ap-northeast-1a
```

NatGatewayは、パブリックサブネットに配置され、``Elastic IP（ElasticIP1）``が割り当てられています。

これにより、プライベートサブネット内のインスタンスが外部のリソース（例えば、ソフトウェアアップデート）にアクセスできるようになります。

### 踏み台サーバー（Bastion）用セキュリティグループの作成
踏み台サーバーは、インターネットからプライベートサブネット内のリソースにアクセスするための安全な中継サーバーです。

これにアクセスするためのセキュリティグループを作成します。

```yaml
BastionSecurityGroup:
  Type: AWS::EC2::SecurityGroup
  Properties:
    GroupDescription: "Allow SSH access"
    VpcId: !Ref HondaVpc
    SecurityGroupIngress:
      - IpProtocol: tcp
        FromPort: 22
        ToPort: 22
        CidrIp: 0.0.0.0/0
    Tags:
      - Key: Name
        Value: ホンダ-sg-bastion
```

このセキュリティグループは、``SSH（ポート22）``によるアクセスを許可しています。

これにより、インターネットから踏み台サーバーにアクセスし、その後プライベートサブネット内のインスタンスにアクセスできます。

### 踏み台サーバーのEC2インスタンスの作成
最後に、踏み台サーバーとなるEC2インスタンスを作成します。

このインスタンスは、パブリックサブネット内に配置され、セキュリティグループを通じてSSHでアクセスできるようになります。

```yaml
BastionInstance:
  Type: AWS::EC2::Instance
  Properties:
    InstanceType: t2.micro
    SubnetId: !Ref PublicSubnet1
    ImageId: ami-0b6fe957a0eb4c1b9
    KeyName: "honda"
    SecurityGroupIds:
      - !Ref BastionSecurityGroup
    Tags:
      - Key: Name
        Value: "踏み台サーバー"
```

このEC2インスタンスは、t2.microインスタンスタイプで作成され、``AMI（Amazon Machine Image）ami-0b6fe957a0eb4c1b9``を使用して起動します。

また、KeyNameにはSSH接続用のキー名が指定されており、セキュリティグループ``BastionSecurityGroup``が適用されています。

## 完成したコード

ここまでのコードを組み合わせて、最終的に以下のコードとなりました。

```yaml
Resources:
  # VPCの作成
  HondaVpc:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      EnableDnsSupport: true
      EnableDnsHostnames: true
      InstanceTenancy: default
      Tags:
        - Key: Name
          Value: ホンダ-vpc

  # パブリックサブネットの作成
  PublicSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref HondaVpc
      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 HondaVpc
      CidrBlock: 10.0.16.0/20
      AvailabilityZone: ap-northeast-1c
      Tags:
        - Key: Name
          Value: ホンダ-subnet-public2-ap-northeast-1c

  # プライベートサブネットの作成
  PrivateSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref HondaVpc
      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 HondaVpc
      CidrBlock: 10.0.144.0/20
      AvailabilityZone: ap-northeast-1c
      Tags:
        - Key: Name
          Value: ホンダ-subnet-private2-ap-northeast-1c

  PrivateSubnet3:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref HondaVpc
      CidrBlock: 10.0.160.0/20
      AvailabilityZone: ap-northeast-1a
      Tags:
        - Key: Name
          Value: ホンダ-subnet-private3-ap-northeast-1a

  PrivateSubnet4:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref HondaVpc
      CidrBlock: 10.0.176.0/20
      AvailabilityZone: ap-northeast-1c
      Tags:
        - Key: Name
          Value: ホンダ-subnet-private4-ap-northeast-1c

  # インターネットゲートウェイの作成
  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: ホンダ-igw

  # インターネットゲートウェイをVPCにアタッチ
  AttachGateway:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref HondaVpc
      InternetGatewayId: !Ref InternetGateway

  # パブリックルートテーブルの作成とパブリックサブネットとの関連付け
  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref HondaVpc
      Tags:
        - Key: Name
          Value: ホンダ-rtb-public

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

  PublicSubnet1RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnet1
      RouteTableId: !Ref PublicRouteTable

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

  # Elastic IP の作成
  ElasticIP1:
    Type: AWS::EC2::EIP
    Properties:
      Domain: vpc
      Tags:
        - Key: Name
          Value: ホンダ-eip-ap-northeast-1a

  # NATゲートウェイの作成
  NatGateway:
    Type: AWS::EC2::NatGateway
    Properties:
      SubnetId: !Ref PublicSubnet1
      AllocationId: !GetAtt ElasticIP1.AllocationId
      Tags:
        - Key: Name
          Value: ホンダ-nat-public1-ap-northeast-1a

  # プライベートルートテーブルの作成と各サブネットとの関連付け
  PrivateRouteTable1:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref HondaVpc
      Tags:
        - Key: Name
          Value: ホンダ-rtb-private1-ap-northeast-1a

  PrivateRoute1:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PrivateRouteTable1
      DestinationCidrBlock: 0.0.0.0/0
      NatGatewayId: !Ref NatGateway

  PrivateSubnet1RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnet1
      RouteTableId: !Ref PrivateRouteTable1

  # 踏み台サーバー（Bastion）用のセキュリティグループの作成
  BastionSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: "Allow SSH access"
      VpcId: !Ref HondaVpc
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: 0.0.0.0/0
      Tags:
        - Key: Name
          Value: ホンダ-sg-bastion

  # Elastic IP の作成（別のElastic IP）
  ElasticIP2:
    Type: AWS::EC2::EIP
    Properties:
      Domain: vpc
      Tags:
        - Key: Name
          Value: ホンダ-eip-ap-northeast-1c

  # 踏み台サーバーのEC2インスタンスの作成
  BastionInstance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: t2.micro
      SubnetId: !Ref PublicSubnet1
      ImageId: ami-0b6fe957a0eb4c1b9
      KeyName: "honda"
      SecurityGroupIds:
        - !Ref BastionSecurityGroup
      Tags:
        - Key: Name
          Value: "踏み台サーバー"
```

## 実際に使ってみた

CloudFormationのサービス画面からスタックの作成に進み、作成した``yamlファイル``をアップロードします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/1f238e06-6895-82e7-2628-fa85366f6ac7.png)

スタック名は任意で設定できます。ここでは私の名前「``honda``」としています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/1c75259d-d21d-c09a-f4ca-e962527617fb.png)

画面遷移後のスタックオプション設定については、個々の設定に依存するため、私は設定せずに進めていきます。

最後に確認を行い、問題がなければ最下部までスクロールし、「``送信``」をクリックして完了です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/0f0a08f4-d6e4-cf96-b900-11e27e0176db.png)

スタックを実行後、イベントタブで成功したことが確認できました（しばらく時間がかかります）。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/3fa62920-cabb-95ed-f925-a1937081aa80.png)

また、パブリックサブネットに踏み台サーバーがコードにより構築されていることも確認できました。自宅での検証は大成功と言えます！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/35fc8656-9fc0-9610-e9e3-7a58dfd49df4.png)

:::note alert
**注意点として、CloudFormationで作成したリソースはスタックを削除すれば一括で削除されますが、削除操作を行う際には、依存関係のあるリソースが他に影響を与えないかを確認し、慎重に操作を行うことが重要です。**
:::

## まとめ

CloudFormationを使ったAWSネットワーク構築は、最初はリソース間の依存関係や設定に時間がかかり、大変でした。

特に、パブリックサブネットに踏み台サーバーを配置するためのセキュリティグループやルート設定の調整に手間取ることもありました。

今後も積極的にハンズオンによる検証を進めていきます。

## 関連記事

今回と似た記事として、インフラのコード化に関する記事も参考にしてみてください。

https://qiita.com/free-honda/items/5a8c69df40c631549663

https://qiita.com/free-honda/items/e972710ed65c5c4afb4e

https://qiita.com/free-honda/items/4cadfd1bafa6c71c85fb