🦔

CloudFormation入門① VPC / Subnet / Internet Gateway

2024/03/02に公開

はじめに

今回はVPC周りの構築をやっていきます。(初めてCloudFormationを使いますが、何回か書けば少しは慣れてくるだろうということで5回連載していきます。)

目標

今回は以下のような構成を作成します。

VPCの中にパプリックサブネットとプライベートサブネットが1つずつある構成で、パブリックサブネットのルートテーブルでインターネットゲートウェイを指定します。

最終的なコード

先に最終的なコードをお見せします。

AWSTemplateFormatVersion: 2010-09-09

#  VPC
Resources:
    TestVPC:
        Type: AWS::EC2::VPC
        Properties:
            CidrBlock: 10.0.0.0/16
            Tags:
                -
                    Key: Name
                    Value: TestVPC

#  サブネット
## パブリックサブネット
    TestPublicSubnet:
        Type: AWS::EC2::Subnet
        Properties:
            CidrBlock: 10.0.10.0/24
            MapPublicIpOnLaunch: true
            VpcId: !Ref TestVPC
            AvailabilityZone:
                Fn::Select:
                    - 0
                    - Fn::GetAZs: ""
            Tags:
                -
                    Key: Name
                    Value: TestPublicSubnet

## プライベートサブネット
    TestPrivateSubnet:
        Type: AWS::EC2::Subnet
        Properties:
            CidrBlock: 10.0.20.0/24
            MapPublicIpOnLaunch: false
            VpcId: !Ref TestVPC
            AvailabilityZone:
                Fn::Select:
                    - 1
                    - Fn::GetAZs: ""
            Tags:
                -
                    Key: Name
                    Value: TestPrivateSubnet

#  インターネットゲートウェイ
## 作成
    TestInternetGateway:
        Type: AWS::EC2::InternetGateway
        Properties:
            Tags:
                - 
                    Key: Name
                    Value: TestInternetGateway
## VPCにアタッチ
    AttachInternetGateway:
        Type: AWS::EC2::VPCGatewayAttachment
        Properties:
            InternetGatewayId: !Ref TestInternetGateway
            VpcId: !Ref TestVPC
            
#  ルートテーブル(パブリック)
## 作成
    TestRouteTableForPublicSubnet:
        Type: AWS::EC2::RouteTable
        Properties:
            VpcId: !Ref TestVPC
            Tags:
                -
                    Key: Name
                    Value: TestRouteTableForPublicSubnet
## インターネットゲートウェイを指定
    RouteTableForPublicSubnet:
        Type: AWS::EC2::Route
        Properties:
            RouteTableId: !Ref TestRouteTableForPublicSubnet
            DestinationCidrBlock: 0.0.0.0/0
            GatewayId: !Ref TestInternetGateway

## ルートテーブルとパブリックサブネットを紐付け
    AssociateRouteTableForPublicSubnet:
        Type: AWS::EC2::SubnetRouteTableAssociation
        Properties:
            RouteTableId: !Ref TestRouteTableForPublicSubnet
            SubnetId: !Ref TestPublicSubnet

#  ルートテーブル(プライベート)
## 作成
    TestRouteTableForPrivateSubnet:
        Type: AWS::EC2::RouteTable
        Properties:
            VpcId: !Ref TestVPC
            Tags:
                -
                    Key: Name
                    Value: TestRouteTableForPrivateSubnet

## ルートテーブルとプライベートサブネットを紐付け
    AssociateRouteTableForPrivateSubnet:
        Type: AWS::EC2::SubnetRouteTableAssociation
        Properties:
            RouteTableId: !Ref TestRouteTableForPrivateSubnet
            SubnetId: !Ref TestPrivateSubnet

解説

ここからいくつかのパートに分けて解説していきます。

フォーマットバージョン

AWSTemplateFormatVersion: 2010-09-09

テンプレートの機能を識別するフォーマットバージョンになります。最新のバージョンが出てこない限りは脳死で書きます。

【補足】リソース定義の基本構文

今回の基本構文はこのようになっています。

Resources:
  Logical ID:
    Type: Resource type
    Properties:
      Set of properties

Resourcesセクションの基本構文は、Resourcesをキー名とします。Logical ID論理IDを指定します。論理IDはテンプレート内で一意である必要があり、他のリソースの関連付けに使用することができます。
Typeではリソースのタイプを定義します。CloudFormationで使用できるリソースタイプは公式に記載されています。
Propertiesではリソースに対して指定できる追加オプションを定義します。プロパティを宣言する必要のないリソースの場合は、省略できます。

VPC

#  VPC
Resources:
    TestVPC:
        Type: AWS::EC2::VPC
        Properties:
            CidrBlock: 10.0.0.0/16
            Tags:
                -
                    Key: Name
                    Value: TestVPC

リソースタイプはType: AWS::EC2::VPCとします。PropertiesでVPCのCidrBlockを定義する必要があります。TagsにKeyとValueを設定していますが、必須ではありません。コンソール上で識別しやすいように名前をつけました。作成後は以下のようにコンソール上で表示されます。

サブネット

#  サブネット
## パブリックサブネット
    TestPublicSubnet:
        Type: AWS::EC2::Subnet
        Properties:
            CidrBlock: 10.0.10.0/24
            MapPublicIpOnLaunch: true
            VpcId: !Ref TestVPC
            AvailabilityZone:
                Fn::Select:
                    - 0
                    - Fn::GetAZs: ""
            Tags:
                -
                    Key: Name
                    Value: TestPublicSubnet

## プライベートサブネット
    TestPrivateSubnet:
        Type: AWS::EC2::Subnet
        Properties:
            CidrBlock: 10.0.20.0/24
            MapPublicIpOnLaunch: false
            VpcId: !Ref TestVPC
            AvailabilityZone:
                Fn::Select:
                    - 1
                    - Fn::GetAZs: ""
            Tags:
                -
                    Key: Name
                    Value: TestPrivateSubnet

パブリックサブネット、プライベートサブネットの作成時はどちらもType: AWS::EC2::Subnetのリソースタイプを設定します。CidrBlockはVPCで設定した値に含まれる範囲に設定します。
サブネット作成時のポイントの一つとしてMapPublicIpOnLaunchの設定があり、trueであればパブリックサブネット、falseあればプライベートサブネットでの指定となります。

VpcId: !Ref TestVPCの指定では、先述した論理IDがTestVPCとなっているVPCを参照させています。ここで組み込み関数と呼ばれるものが使用されているので説明します。VpcIdを指定する際、VPC IDが事前に分かっている状態であれば、

VpcId: vpc-0ec2ad5f8a6ed592c

というように直接ID指定することも可能です。しかし今回のようにCloudFormationで一度に作成する際は、まだVPCが作成されておらず、VPC IDが分からないためRefを使用した指定をしています。Refは組み込み関数の一つで、指定したパラメータまたはリソースの値を返すことができます。

アベイラリティゾーン(AZ)の指定では、Fn::SelectFn::GetAZsを使用しています。これは、使用可能なAZはアカウントごとに異なるということを考慮して、CloudFromationを使用するアカウントのAZに依存させないようにしています。

  • Fn::GetAZs: 指定されたリージョンで使用可能なAZの配列を返す
  • Fn::Select: インデックスによってオブジェクトのリストから1つのオブジェクトを返す

簡単にこのあたりの挙動を説明します。

AvailabilityZone:
    Fn::Select:
        - 0
        - Fn::GetAZs: ""

この場合、Fn::GetAZs: ""でリージョンを指定していないため、デプロイされたリージョン(今回だと東京リージョン)が暗黙的に指定されたことになります。

AvailabilityZone:
    Fn::Select:
        - 0
        - ["ap-northeast-1a", "ap-northeast-1c"]

東京リージョンを指定することで、AZの配列が返されることになり、Fn::Selectで配列の0番目であるap-northeast-1aを指定できることになります。

インターネットゲートウェイ

## 作成
    TestInternetGateway:
        Type: AWS::EC2::InternetGateway
        Properties:
            Tags:
                - 
                    Key: Name
                    Value: TestInternetGateway
## VPCにアタッチ
    AttachInternetGateway:
        Type: AWS::EC2::VPCGatewayAttachment
        Properties:
            InternetGatewayId: !Ref TestInternetGateway
            VpcId: !Ref TestVPC

インターネットゲートウェイの作成にはリソースタイプAWS::EC2::InternetGatewayを使用します。作成後にAWS::EC2::VPCGatewayAttachmentでVPCのアタッチを行います。アタッチする際には、プロパティで作成したインターネットゲートウェイとVPCのIDを指定します。

ルートテーブル(パブリック)

## 作成
    TestRouteTableForPublicSubnet:
        Type: AWS::EC2::RouteTable
        Properties:
            VpcId: !Ref TestVPC
            Tags:
                -
                    Key: Name
                    Value: TestRouteTableForPublicSubnet
## インターネットゲートウェイを指定
    RouteTableForPublicSubnet:
        Type: AWS::EC2::Route
        Properties:
            RouteTableId: !Ref TestRouteTableForPublicSubnet
            DestinationCidrBlock: 0.0.0.0/0
            GatewayId: !Ref TestInternetGateway

## ルートテーブルとパブリックサブネットを紐付け
    AssociateRouteTableForPublicSubnet:
        Type: AWS::EC2::SubnetRouteTableAssociation
        Properties:
            RouteTableId: !Ref TestRouteTableForPublicSubnet
            SubnetId: !Ref TestPublicSubnet

ルートテーブルを作成する時点ではパブリックでもプライベートでもAWS::EC2::RouteTableを使用します。作成後に、AWS::EC2::Routeでルーティングの指定を行います。今回はパブリックのためインターネットゲートウェイを指定します。最後にルートテーブルとサブネットの紐付けをAWS::EC2::SubnetRouteTableAssociationを行います。

ルートテーブル(プライベート)

#  ルートテーブル(プライベート)
## 作成
    TestRouteTableForPrivateSubnet:
        Type: AWS::EC2::RouteTable
        Properties:
            VpcId: !Ref TestVPC
            Tags:
                -
                    Key: Name
                    Value: TestRouteTableForPrivateSubnet

## ルートテーブルとプライベートサブネットを紐付け
    AssociateRouteTableForPrivateSubnet:
        Type: AWS::EC2::SubnetRouteTableAssociation
        Properties:
            RouteTableId: !Ref TestRouteTableForPrivateSubnet
            SubnetId: !Ref TestPrivateSubnet

パブリックと基本的には同じです。こちらはインターネットゲートウェイとは繋ぎません。

おわりに

こちらのコードでスタックを作成した結果がこちらです。
想定通りできていそうですね!

Discussion