Amazon Web Services 基礎からのネットワーク&サーバー構築をCloudFormationで構築

## 概要
[Amazon Web Services 基礎からのネットワーク&サーバー構築 改訂3版](https://www.amazon.co.jp/Amazon-Services-E5-9F-BA-E7-A4-8E-E3-81-8B-E3-82-89-E3-81-AE-E3-83-8D-E3-83-83-E3-83-88-E3-83-AF-E/dp/4296105442/ref=dp_ob_title_bk)で作成するネットワーク＆サーバー構成をAWSのCloudFormationを使って、構築するためのテンプレートファイル

## 対象者
Amazon Web Services 基礎からのネットワーク&サーバー構築 改訂3版を読み、CloudFormationを使い、構築しようと思っている方

## 構築されるもの
- VPC
- InternetGateway
- Subnet
- RouteTable
- NATGateway
- EC2
- SecurityGroup

## 構成図
![aws.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502753/6ab74ac7-bc94-6ddb-38c2-34864fde4c9e.png)



## セクション説明
|  セクション| 意味  |備考  |
| ---- | ---- | ---- |
|  AWSTemplateFormatVersion  | テンプレートバージョン  | 2010-09-09 であり、現時点で唯一の有効な値 |
|  Description  |  テンプレートを説明するテキスト | ---- |
|  Metadata  | テンプレートバージョン  | ---- |
|  Parameters  |  パラメーターの定義| ---- |
|  Resources  | スタックに含める AWS リソースの宣言 | ---- |
|  Outputs  |  出力値を宣言| 他のスタックでインポートできる|

## 組み込み関数説明
|  組み込み関数| 意味  |備考  |
| ---- | ---- | ---- |
|  Ref  | 指定したパラメータまたはリソースの値| --- |
|  Sub  |  特定した値の入力文字列にある変数の代わりになる| 文字列内に変数を挿入する |
|  GetAtt  |  テンプレートのリソースから属性の値を返す|  --- |
|  Base64  |  入力文字列の Base64 表現を返す| 通常、UserData プロパティを介して Amazon EC2 インスタンスにエンコードされたデータを渡すために使用される |

## テンプレートファイル
下記においてあります。ご自由にお使いください
https://github.com/toyoyuto/cloudformation

## テンプレートファイル(解説付き)
``` vpc.yml
AWSTemplateFormatVersion: 
  "2010-09-09"
Description:
  Amazon Web Services Network & server construction from the basics
  
Metadata:
  # コンソールでパラメータをグループ化およびソートする方法を定義するメタデータキー
  "AWS::CloudFormation::Interface":
    # パラメーターグループとそのグループに含めるパラメーターの定義
    ParameterGroups: 
      # Project名に関するグループ
      - Label: 
          default: "Project Name Prefix"
        Parameters: 
          - PJPrefix
      # ネットワーク設定に関するグループ
      - Label: 
          default: "Network Configuration"
        # 記述された順番に表示される
        Parameters: 
          - VPCCIDR
          - PublicSubnetCIDR
          - PrivateSubnetCIDR
          - PublicIP
          - PrivateIP
          - KeyName
    # パラメーターのラベル
    ParameterLabels: 
      VPCCIDR: 
        default: "VPC CIDR"
      PublicSubnetCIDR: 
        default: "PublicSubnet CIDR"
      PrivateSubnetCIDR: 
        default: "PrivateSubnet CIDR"
      PublicIP: 
        default: "Public IP"
      PrivateIP: 
        default: "Private IP"


# ------------------------------------------------------------#
# Input Parameters
# ------------------------------------------------------------# 
Parameters:
  PJPrefix:
    Type: String

  VPCCIDR:
    Type: String
    Default: "10.0.0.0/16"

  PublicSubnetCIDR:
    Type: String
    Default: "10.0.1.0/24"

  PrivateSubnetCIDR:
    Type: String
    Default: "10.0.2.0/24"

  PublicIP:
    Type: String
    Default: "10.0.1.10"

  PrivateIP:
    Type: String
    Default: "10.0.2.10"

  KeyName:
    Type: "AWS::EC2::KeyPair::KeyName"
  
Resources: 
# ------------------------------------------------------------#
#  VPC
# ------------------------------------------------------------#
# VPC Create
  VPC: 
    Type: "AWS::EC2::VPC"
    Properties:
      CidrBlock: !Ref VPCCIDR
      # VPC に対して DNS 解決がサポートされているか
      EnableDnsSupport: "true"
      # VPC 内に起動されるインスタンスが DNS ホスト名を取得するか
      EnableDnsHostnames: "true"
      # VPC 内に起動されるインスタンスの許可されているテナンシー
      InstanceTenancy: default
      Tags: 
        - Key: Name
          Value: !Sub "${PJPrefix}-vpc"

# InternetGateway Create
  InternetGateway: 
    Type: "AWS::EC2::InternetGateway"
    Properties: 
      Tags: 
        - Key: Name
          Value: !Sub "${PJPrefix}-igw"

# IGW Attach
  InternetGatewayAttachment: 
    Type: "AWS::EC2::VPCGatewayAttachment"
    Properties: 
      InternetGatewayId: !Ref InternetGateway
      VpcId: !Ref VPC 

# ------------------------------------------------------------#
#  Subnet
# ------------------------------------------------------------#          
# Public Subnet Create
  PublicSubnet: 
    Type: "AWS::EC2::Subnet"
    Properties: 
      AvailabilityZone: "ap-northeast-1a"
      CidrBlock: !Ref PublicSubnetCIDR
      VpcId: !Ref VPC 
      Tags: 
        - Key: Name
          Value: !Sub "${PJPrefix}-public-subnet"
                    
# Private Subnet Create
  PrivateSubnet: 
    Type: "AWS::EC2::Subnet"
    Properties: 
      AvailabilityZone: "ap-northeast-1a"
      CidrBlock: !Ref PrivateSubnetCIDR
      VpcId: !Ref VPC 
      Tags: 
        - Key: Name
          Value: !Sub "${PJPrefix}-private-subnet"
                    
# ------------------------------------------------------------#
#  RouteTable
# ------------------------------------------------------------#          
# Public RouteTable Create
  PublicRouteTable: 
    Type: "AWS::EC2::RouteTable"
    Properties: 
      VpcId: !Ref VPC 
      Tags: 
        - Key: Name
          Value: !Sub "${PJPrefix}-public-route"

# Private RouteTable Create
  PrivateRouteTable: 
    Type: "AWS::EC2::RouteTable"
    Properties: 
      VpcId: !Ref VPC 
      Tags: 
        - Key: Name
          Value: !Sub "${PJPrefix}-private-route"

# ------------------------------------------------------------#
#  NAT Gateway
# ------------------------------------------------------------#
  NATGateway: 
    Type: "AWS::EC2::NatGateway"
    Properties:
      # NAT ゲートウェイに関連付ける Elastic IPアドレスの割り当て ID
      # 下記で構築する Elastic IPのIDを指定
      AllocationId: !GetAtt NATGatewayAEIP.AllocationId 
      SubnetId: !Ref PublicSubnet
      Tags: 
        - Key: Name
          Value: !Sub "${PJPrefix}-natgw"
  # NATGateway For Elastic IP Create
  NATGatewayAEIP: 
    Type: "AWS::EC2::EIP"
    Properties:
      # ------------------------------------------------------
      # Elastic IP アドレスが VPC のインスタンスで使用するか、
      # EC2-Classic のインスタンスで使用するか
      # ------------------------------------------------------
      Domain: vpc

# ------------------------------------------------------------#
# Routing
# ------------------------------------------------------------# 
# PublicRoute Create
  PublicRoute: 
    Type: "AWS::EC2::Route"
    Properties: 
      RouteTableId: !Ref PublicRouteTable 
      DestinationCidrBlock: "0.0.0.0/0"
      GatewayId: !Ref InternetGateway 
# PrivateRoute Create
  PrivateRoute: 
    Type: "AWS::EC2::Route"
    Properties: 
      RouteTableId: !Ref PrivateRouteTable 
      DestinationCidrBlock: "0.0.0.0/0"
      NatGatewayId: !Ref NATGateway 

# ------------------------------------------------------------#
# RouteTable Associate
# ------------------------------------------------------------# 
# PublicRouteTable Associate PublicSubnet
  PublicSubnetRouteTableAssociation: 
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties: 
      SubnetId: !Ref PublicSubnet
      RouteTableId: !Ref PublicRouteTable
# PrivateRouteTable Associate PrivateSubnet
  PrivateSubnetRouteTableAssociation: 
      Type: "AWS::EC2::SubnetRouteTableAssociation"
      Properties: 
        SubnetId: !Ref PrivateSubnet
        RouteTableId: !Ref PrivateRouteTable

# ------------------------------------------------------------#
# EC2
# ------------------------------------------------------------# 
  # WebServerインスタンス
  WebServer: 
    Type: AWS::EC2::Instance
    Properties: 
      ImageId: ami-00f045aed21a55240
      KeyName: !Ref KeyName
      InstanceType: t2.micro
      NetworkInterfaces: 
        # IPv4 アドレスを割り当てるか
        - AssociatePublicIpAddress: "true"
          # ------------------------------------------------------
          # アタッチの順序におけるネットワークインターフェイスの位置。
          # ネットワークインターフェイスを指定する場合必須
          # ------------------------------------------------------
          DeviceIndex: "0"
          SubnetId: !Ref PublicSubnet
          PrivateIpAddress: !Ref PublicIP
          GroupSet:
            - !Ref WebServerSG

      # インスタンスの作成時に実行するコマンドなどを記述
      UserData: !Base64 |
        #!/bin/bash
        sudo yum -y update
        sudo yum -y install httpd
        sudo systemctl start httpd.service
        sudo systemctl enable httpd.service
        
        sudo amazon-linux-extras install php7.3
        sudo yum -y install php php-mbstring
        sudo yum -y install mariadb-server
        
        cd ~
        wget https://ja.wordpress.org/latest-ja.tar.gz
        tar xzvf latest-ja.tar.gz 
        cd wordpress
        sudo cp -r * /var/www/html
        sudo chown apache:apache /var/www/html -R

        sudo systemctl restart httpd.service

      Tags:
          - Key: Name
            Value: !Sub "${PJPrefix}-web-server"

  # WebServerセキュリティグループ
  WebServerSG:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: web-sg-cf
      GroupDescription: web server sg
      VpcId: !Ref VPC
      SecurityGroupIngress:
        # ssh
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: 0.0.0.0/0
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0
        # pingコマンドで疎通確認を行うため
        # IPv4ですべてのプロトコルとすべてのポートを許可
        - IpProtocol: icmp
          FromPort : -1
          ToPort : -1
          CidrIp: 0.0.0.0/0
        # IPv6ですべてのプロトコルとすべてのポートを許可
        - IpProtocol: icmp
          FromPort : -1
          ToPort : -1
          CidrIpv6: ::/0
      Tags:
        - Key: Name
          Value: !Sub "${PJPrefix}-web-server-sg"

  # DBServerインスタンス
  DbServer: 
    Type: AWS::EC2::Instance
    Properties: 
      ImageId: ami-00f045aed21a55240
      KeyName: !Ref KeyName
      InstanceType: t2.micro
      NetworkInterfaces: 
        - AssociatePublicIpAddress: "false"
          DeviceIndex: "0"
          SubnetId: !Ref PrivateSubnet
          PrivateIpAddress: !Ref PrivateIP
          GroupSet:
            - !Ref DbServerSG

      UserData: !Base64 |
        #!/bin/bash
        sudo yum -y update
        sudo yum -y install mariadb-server
        sudo systemctl start mariadb
        sudo systemctl enable mariadb

      Tags:
          - Key: Name
            Value: !Sub "${PJPrefix}-db-server"

  # DBServerセキュリティグループ
  DbServerSG:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: db-sg-cf
      GroupDescription: db server sg
      VpcId: !Ref VPC
      SecurityGroupIngress:
        # ssh
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: 0.0.0.0/0
        - IpProtocol: tcp
          FromPort: 3306
          ToPort: 3306
          CidrIp: 0.0.0.0/0
        - IpProtocol: tcp
          FromPort: 3306
          ToPort: 3306
          CidrIpv6: ::/0
        - IpProtocol: icmp
          FromPort : -1
          ToPort : -1
          CidrIp: 0.0.0.0/0
        - IpProtocol: icmp
          FromPort : -1
          ToPort : -1
          CidrIpv6: ::/0
      Tags:
        - Key: Name
          Value: !Sub "${PJPrefix}-db-server-sg"

# ------------------------------------------------------------#
# Output Parameters
# ------------------------------------------------------------#                
Outputs:
# VPC
  VPC:
    Value: !Ref VPC
    Export:
      Name: !Sub "${PJPrefix}-vpc"

  VPCCIDR:
    Value: !Ref VPCCIDR
    Export:
      Name: !Sub "${PJPrefix}-vpc-cidr"

# Subnet
  PublicSubnet:
    Value: !Ref PublicSubnet
    Export:
      Name: !Sub "${PJPrefix}-public-subnet"

  PublicSubnetCIDR:
    Value: !Ref PublicSubnetCIDR
    Export:
      Name: !Sub "${PJPrefix}-public-subnet-cidr"

  PrivateSubnet:
    Value: !Ref PrivateSubnet
    Export:
      Name: !Sub "${PJPrefix}-private-subnet"
    
  PrivateSubnetCIDR:
    Value: !Ref PrivateSubnetCIDR
    Export:
      Name: !Sub "${PJPrefix}-private-subnet--cidr"

# Route
  PublicRouteTable:
    Value: !Ref PublicRouteTable
    Export:
      Name: !Sub "${PJPrefix}-public-route"

  PrivateRouteTable:
    Value: !Ref PrivateRouteTable
    Export:
      Name: !Sub "${PJPrefix}-private-route"

# EC2
  WebServer:
    Value: !Ref WebServer
    Export:
      Name: !Sub "${PJPrefix}-web-server"
  DbServer:
    Value: !Ref DbServer
    Export:
      Name: !Sub "${PJPrefix}-db-server"
```

## 備考
DBとWordPressの設定は各自行う

## その他用語説明
### テナンシー
インスタンスを立てるサーバを他のユーザと共有するか、自分だけで専有するかの選択。 
### AllocationId
Amazon VPC で使用するアドレスの割り当てを表すために AWS によって割り当てられた ID。

## 参考
[CloudFormationを使ってVPCを構築する](https://qiita.com/okubot55/items/b18a5dd5166f1ec2696c)
[セキュリティグループのすべてのポートを指定する方法-CloudFormation](https://www.it-swarm-ja.tech/ja/amazon-web-services/%E3%82%BB%E3%82%AD%E3%83%A5%E3%83%AA%E3%83%86%E3%82%A3%E3%82%B0%E3%83%AB%E3%83%BC%E3%83%97%E3%81%AE%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E3%83%9D%E3%83%BC%E3%83%88%E3%82%92%E6%8C%87%E5%AE%9A%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95cloudformation/826810117/)