🔧

AWS CloudFormation で VPC とサブネットを作ってみる

2021/04/09に公開
4

こんにちは、Masuyama です。

AWS 上に作成する時に CloudFormation を使うことがありますが、
毎回書き方を忘れては調べての繰り返しになってしまっているので、基本的な構成についてまとめてみます。

今回用意する構成

  • VPC x 1
  • サブネット x 2
    • パブリックサブネット x 1
    • プライベートサブネット x 2
  • インターネットゲートウェイ x 1
  • NAT ゲートウェイ (プライベートサブネット用)

テンプレートファイルの準備

任意のフォルダに yml ファイルを任意の名前で作成していきます。
項目ごとに一つひとつ載せていきますが、一番最後に全文も載せていきますのでご安心ください。

今回はとりあえず cf-vpc-subnet-test.yml という名前にしておきます。

フォーマットバージョンの指定

それではテンプレートファイルを作成していきます。
冒頭ではテンプレートのフォーマットバージョンを指定します。
指定できるのは "2010-09-09" のみですので、そのように書いていきます。

AWSTemplateFormatVersion: 2010-09-09

VPC の設定

次から次へとテンプレートファイルに書き足していきしょう。
テンプレートファイルでは Resources 配下に作りたいリソースや、テンプレート内で一意の名前 (Logical ID)、CIDR Block 等をを設定していきます。

...
Resources:
  CfVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.1.0.0/16
      Tags:
        -
          Key: Name
          Value: CfVPC

タグ付けも CloudFormation テンプレートファイルの中で指定できます。

サブネットの設定

続いて、先ほど指定した VPC の中にサブネットを 2 つ作っていきます。
一つはパブリックサブネット、もう一つはプライベートサブネットと、よくある構成です。

...
  CfPublicSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: 10.1.1.0/24
      MapPublicIpOnLaunch: true
      VpcId: !Ref CfVPC
      AvailabilityZone: 
        Fn::Select: 
          - 0
          - Fn::GetAZs: ""
      Tags:
        - Key: Name
          Value: CfPublicSubnet
  CfPrivateSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: 10.1.2.0/24
      MapPublicIpOnLaunch: false
      VpcId: !Ref CfVPC
      AvailabilityZone: 
        Fn::Select: 
          - 1
          - Fn::GetAZs: ""
      Tags:
        - Key: Name
          Value: CfPrivateSubnet

新しく出てきたものがいくつかありますが、VpcId 欄の !Ref はとても重要な組み込み関数です。
どの VPC内にサブネットを作成するかを VPC ID で指定しますが、CloudFormation で VPC が作られないと ID は分かりませんよね。
そんな時は、同テンプレート内で設定した Logical ID (リソースの論理ID)を !Ref で参照してあげることで、VPC ID が自動的に当てはまるのです。
なお、!Ref を使用すると参照される側(ここでは VPC)が作成されてからサブネットを作成するといったような、依存関係も自動的に処理されます。

また、MapPublicIpOnLaunch は AWS マネジメントコンソールにおける「パブリックIPv4アドレスの自動割り当てを有効にする」にチェックを入れるかどうかに相当しています。
パブリックサブネットでは true、プライベートサブネットでは false を指定しています。

インターネットゲートウェイ の設定

インターネットゲートウェイ の定義

リソースタイプで指定してあげるだけなので簡単です。

...
  CfInternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: CfInternetGateway

インターネットゲートウェイy を VPC へアタッチ

上記で作成される インターネットゲートウェイ を CfVPC へアタッチします。
ここでも組み込み関数 !Ref を使って VPC ID と InterngetGateway ID を指定しましょう。

...
  AttachCfInternetGateway:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      InternetGatewayId : !Ref CfInternetGateway
      VpcId: !Ref CfVPC

なお、ここで !Ref で CfInterngetGateway を指定しているので、ちゃんとインターネットゲートウェイ が作成されてからアタッチの動作を行ってくれます。

インターネットへのルート設定(パブリックサブネット)

続いてルートを準備していきます。まずはパブリックサブネット側からです。

ルートテーブルの作成(パブリックサブネット)

リソースタイプを指定してあげるだけなので簡単です。

...
  CfRouteTableForPublicSubnet:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref CfVPC
      Tags:
        - Key: Name
          Value: CfRouteTableForPublicSubnet

ルートの定義(パブリックサブネット)

上記で作成するルートテーブルを !Ref で指定しつつ、デフォルトゲートウェイ 0.0.0.0/0 の宛先としてインターネットゲートウェイを指定します。

...
  CfRouteForPublicSubnet:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref CfRouteTableForPublicSubnet
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref CfInternetGateway

ルートテーブルとサブネットの紐付け(パブリックサブネット)

上記で作成したルートテーブルはどのサブネットにも紐付いていないので、ルートテーブルとパブリックサブネットを紐づけてあげます。

...
  CfAssocciateRouteTableForPublicSubnet:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref CfRouteTableForPublicSubnet
      SubnetId: !Ref CfPublicSubnet

インターネットへのルートの設定(プライベートサブネット)

プライベートサブネットに置いてあるサーバがアップデート等のためにインターネットに出る必要がある場合を想定します。
ただし、プライベートサブネットは直接インターネットには出さず、NAT ゲートウェイ経由で出るようにします。

NAT ゲートウェイ用 Elasic IP の設定

NAT ゲートウェイに割り当てる Elasic IP を確保します。

...
  NatGatewayEIP:
    Type: AWS::EC2::EIP
    Properties:
      Domain: vpc

NAT ゲートウェイの作成

先ほど指定した Elastic IP を設定しつつ、パブリックサブネット内に NAT ゲートウェイを作成します。

...
  CfNatGateway:
    Type: AWS::EC2::NatGateway
    Properties:
      AllocationId:
        Fn::GetAtt:
          - NatGatewayEIP
          - AllocationId
      SubnetId: !Ref CfPublicSubnet
      Tags:
        - Key: Name
          Value: CfNatGateway

ルートテーブルの作成(パブリックサブネット)

パブリックサブネットの時と同じく、リソースタイプを指定してあげるだけです。

...
  CfRouteTableForPrivateSubnet:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref CfVPC
      Tags:
        - Key: Name
          Value: CfRouteTableForPrivateSubnet

ルートの定義(プライベートサブネット)

プライベートサブネットのデフォルトゲートとして、上記で設定した NAT ゲートウェイを指定します。
Ref! での参照の仕方などはパブリックサブネットと同じで、NAT ゲートウェイの Logical ID を参照してあげます。

...
  CfRouteForPrivateSubnet:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref CfRouteTableForPrivateSubnet
      DestinationCidrBlock: 0.0.0.0/0
      NatGatewayId: !Ref CfNatGateway

ルートテーブルとサブネットの紐付け(プライベートサブネット)

こちらもパブリックサブネットの時と同じく、ルートテーブルとルートを紐付けてあげます。

...
  CfAssocciateRouteTableForPrivateSubnet:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref CfRouteTableForPrivateSubnet
      SubnetId: !Ref CfPrivateSubnet

テンプレートファイルの全文

テンプレートファイルはここまでですので、全文として再掲しておきます。

AWSTemplateFormatVersion: 2010-09-09

Resources:
  CfVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.1.0.0/16
      Tags:
        -
          Key: Name
          Value: CfVPC

  CfPublicSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: 10.1.1.0/24
      MapPublicIpOnLaunch: true
      VpcId: !Ref CfVPC
      AvailabilityZone: 
        Fn::Select: 
          - 0
          - Fn::GetAZs: ""
      Tags:
        - Key: Name
          Value: CfPublicSubnet
  CfPrivateSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: 10.1.2.0/24
      MapPublicIpOnLaunch: false
      VpcId: !Ref CfVPC
      AvailabilityZone: 
        Fn::Select: 
          - 1
          - Fn::GetAZs: ""
      Tags:
        - Key: Name
          Value: CfPrivateSubnet

  CfInternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: CfInternetGateway

  AttachCfInternetGateway:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      InternetGatewayId : !Ref CfInternetGateway
      VpcId: !Ref CfVPC

  CfRouteTableForPublicSubnet:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref CfVPC
      Tags:
        - Key: Name
          Value: CfRouteTableForPublicSubnet

  CfRouteForPublicSubnet:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref CfRouteTableForPublicSubnet
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref CfInternetGateway

  CfAssocciateRouteTableForPublicSubnet:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref CfRouteTableForPublicSubnet
      SubnetId: !Ref CfPublicSubnet

  NatGatewayEIP:
    Type: AWS::EC2::EIP
    Properties:
      Domain: vpc

  CfNatGateway:
    Type: AWS::EC2::NatGateway
    Properties:
      AllocationId:
        Fn::GetAtt:
          - NatGatewayEIP
          - AllocationId
      SubnetId: !Ref CfPublicSubnet
      Tags:
        - Key: Name
          Value: CfNatGateway

  CfRouteTableForPrivateSubnet:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref CfVPC
      Tags:
        - Key: Name
          Value: CfRouteTableForPrivateSubnet

  CfRouteForPrivateSubnet:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref CfRouteTableForPrivateSubnet
      DestinationCidrBlock: 0.0.0.0/0
      NatGatewayId: !Ref CfNatGateway

  CfAssocciateRouteTableForPrivateSubnet:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref CfRouteTableForPrivateSubnet
      SubnetId: !Ref CfPrivateSubnet

CloudFormation のテスト

スタックの作成

ではいよいよコンソールからテンプレートファイルをアップロードし、CloudFormation でリソースを作成していきましょう。

CloudFormation のコンソールに移動し [スタックの作成] を選択します。

選択したら [新しいリソースを使用(標準)] を選択します。

画面に指示に従い、テンプレートファイルをアップロードします。

次の画面で任意のスタック名を指定します。
このテンプレートファイルで作成される リソースのセット を識別する名前となります。

次の画面で詳細な設定をできます。
タグ、IAM ロールなどを個別に設定できますが、今回はテストですので空欄のままで次へ進んでいただいて問題ありません。

最後に確認画面が出ますので [スタックの作成] を選択します。

スタックの作成開始後

作成が開始されるとステータスが更新され、リソースが自動的にどんどん作られていきます。
(記述ミスなどによりリソースが作成できなかった場合には、自動ですべてのリソースが削除されてロールバックしますのでご安心ください)

画面右側の円環矢印(タブ内の更新ボタン)を押すとリソースの作成状況が更新されていき、
最終的に指定したスタック名、つまりスタックが CREATE_COMPLETE となれば作成は完
了です。

[リソース] タブ内からも作成されたリソースが一覧で表示されていますが、もちろん各サービスのコンソールからでも確認できます。
例えば VPC は、指定したタグ Name で作成されていることを確認できます。

スタックの削除

テストが終わったら、余計な料金がかからないようにリソースを削除しておきましょう。
CloudFormation で作られたリソースは、スタックという一つのセットになっているので一括で削除することもできるので便利です。

CloudFormation のコンソール画面から [削除] を選択すれば、今回テストで作ったリソースを全部削除することができます。

まとめ

一つひとつのリソースをコードで管理できるようになることは工程を楽にするだけでなく、リソースの設定や構成を誰がみても理解できるようにする上で非常に重要なので、活用していきたいですね。

今回は IP アドレスは固定値にしていましたが、スタック作成時にコンソールで入力させるようにもできます。
また、タグについても固定値でしたが、例えばバージョン名などを入力して一括で毎回少しずつ変更することもできますので、そのあたりも別な機会に紹介します。

Discussion

shun198shun198
CfPublicSubnet:
 Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: 10.1.1.0/24
      MapPublicIpOnLaunch: true
      VpcId: !Ref CfVPC
      AvailabilityZone: ap-northeast-1a
      Tags:
        - Key: Name
          Value: CfPrivateSubnet

のタグのvalueについてですがCfPrivateSubnetではなく、CfPublicSubnetが正しいと思います

shun198shun198

AZのハードコーディングをAWSは推奨してないとのことですので以下のコード例のようにAZをGetAZ配列内から取得できるようにすべきだと思います

mySubnet: 
  Type: "AWS::EC2::Subnet"
  Properties: 
    VpcId: 
      !Ref VPC
    CidrBlock: 10.0.0.0/24
    AvailabilityZone: 
      Fn::Select: 
        - 0
        - Fn::GetAZs: ""

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-getavailabilityzones.html