【初学者必見】はじめてのAWS CloudFormation(Ref: "○○"　Fn::Select　Fn::GetAZs　DependsOn 属性 Fn::GetAtt )

## はじめに
Cludformationを使い始めようと考えている方々向けに、記事を作成しました。実際に動作確認済みのテンプレートの解説をする事で、理解を深めてもらえれば幸いです。

__今回は、「Ref: "○○"　Fn::Select　Fn::GetAZs DependsOn 属性　Fn::GetAtt 」についての説明を中心に取り上げます。__

:::note info
- **`Ref` 関数**: 他のリソースやパラメータの値を参照するために使用されます。
- **`Fn::Select` 関数**: リストから特定の要素を選択するために使用されます。
- **`Fn::GetAZs` 関数**: 指定されたリージョン内のアベイラビリティゾーンのリストを取得するために使用されます。
- **`DependsOn` 属性**: リソースの作成順序を制御するために使用され、依存関係があるリソースが正しい順序で作成されることを保証します。
- **`Fn::GetAtt 関数` 関数**:テンプレート内でリソースの特定の属性を取得するために活用します。リソース間の依存関係を管理し、動的に設定を行うことができます。
:::

#### **`DependsOn` 属性**は、ソリューションアーキテクト認定試験でよく問われる観点ですね。
<font color="rgb(107, 142, 35)">緑色の箇所</font>を確認する事で、ポイントが理解できるように工夫しています。動作確認は、下記のサイトのリソースをご利用下さい。

https://pages.awscloud.com/JAPAN-event-OE-Hands-on-for-Beginners-systems-manager-2022-reg-event.html

## 早速、見ていきましょう！
:::note info
ここで、指定しているパラメータの"VPCCidr"は、後程、 "Ref": "VPCCidr" といった形で、Ref 関数を使い、パラメータの値を参照するために使用される。(その他のパラメータ"PublicSubnetCidr""PrivateSubnetCidr"も同様に参照するために使用される。 )
:::
        
```json
  "Parameters": {
    "VPCCidr": {
      "Type": "String",
      "Default": "10.0.0.0/16",
      "Description": "VPCCidr"
    },
    "PublicSubnetCidr": {
      "Type": "String",
      "Default": "10.0.0.0/24",
      "Description": "PublicSubnetCidr"
    },
    "PrivateSubnetCidr": {
      "Type": "String",
      "Default": "10.0.1.0/24",
      "Description": "PrivateSubnetCidr"
```  
:::note info
CloudFormationテンプレートの`Parameters`セクションは、テンプレートをデプロイする際に __ユーザーが入力する値を定義__ します。
:::

### Parametersセクションの詳細

#### VPCCidr
- **Type**: `String`
  - パラメータのデータ型を指定します。ここでは文字列型（`String`）を指定しています。
- **Default**: `10.0.0.0/16`
  - パラメータのデフォルト値を指定します。ここでは `10.0.0.0/16` を指定しています。
- **Description**: `VPCCidr`
  - パラメータの説明を指定します。ここでは「VPCCidr」としています。この説明は、テンプレートをデプロイする際にユーザーに表示されます。


- **CIDRブロック**: `10.0.0.0/16` は、VPC内で使用可能なIPアドレスの範囲を示します。`/16` はサブネットマスクの長さを示し、これは65,536個のIPアドレスを提供します（10.0.0.0から10.0.255.255まで）。

- **CIDRブロック**: `10.0.0.0/24` は、パブリックサブネット内で使用可能なIPアドレスの範囲を示します。`/24` はサブネットマスクの長さを示し、これは256個のIPアドレスを提供します（10.0.0.0から10.0.0.255まで）。

- **CIDRブロック**: `10.0.1.0/24` は、プライベートサブネット内で使用可能なIPアドレスの範囲を示します。`/24` はサブネットマスクの長さを示し、これは256個のIPアドレスを提供します（10.0.1.0から10.0.1.255まで）。


#### VPCリソースの定義
```json
"Resources": {
  "VPC": {
    "Type": "AWS::EC2::VPC",
    "Properties": {
      "CidrBlock": {
        "Ref": "VPCCidr"
      },
      "EnableDnsSupport": true,
      "EnableDnsHostnames": true,
      "Tags": [
        {
          "Key": "Name",
          "Value": "h4b-vpc"
```

**Type**: `AWS::EC2::VPC`
   - **説明**: このリソースのタイプを指定します。ここでは、VPC（Virtual Private Cloud）を作成するために `AWS::EC2::VPC` を指定しています。

**Properties**:
   - **CidrBlock**:

:::note info
VPCのCIDRブロックを指定します。ここでは、 __`Ref` を使用してパラメータ `VPCCidr` の値を参照しています。__ これにより、テンプレートのデプロイ時にユーザーが指定したCIDRブロックが使用されます。
:::

   - **EnableDnsSupport**:
     - **説明**: VPC内でDNS解決を有効にするかどうかを指定します。`true` に設定すると、VPC内のリソースはDNS解決を利用できます。

   - **EnableDnsHostnames**:
     - **説明**: VPC内のインスタンスにDNSホスト名を割り当てるかどうかを指定します。`true` に設定すると、インスタンスにDNSホスト名が割り当てられます。

   - **Tags**:
     - **説明**: VPCにタグを付けます。タグはキーと値のペアで構成され、リソースの識別や管理に役立ちます。

       - **Key**: タグのキーを指定します。ここでは `Name` を指定しています。
       - **Value**: タグの値を指定します。ここでは `h4b-vpc` を指定しています。

```json
    "PublicSubnet": {
      "Type": "AWS::EC2::Subnet",
      "Properties": {
        "VpcId": {
          "Ref": "VPC"
        },
        "CidrBlock": {
          "Ref": "PublicSubnetCidr"
        },
        "AvailabilityZone": {
          "Fn::Select": [
            "0",
            {
              "Fn::GetAZs": {
                "Ref": "AWS::Region"
              }
            }
          ]
        },
        "MapPublicIpOnLaunch": true,

```
**Type**: `AWS::EC2::Subnet`
   - **説明**: このリソースのタイプを指定します。ここでは、サブネットを作成するために `AWS::EC2::Subnet` を指定しています。

**Properties**:
   - **VpcId**:
     - **説明**: サブネットを作成するVPCのIDを指定します。ここでは、`Ref` を使用してVPCリソースのIDを参照しています。

   - **CidrBlock**:
     - **説明**: サブネットのCIDRブロックを指定します。ここでは、`Ref` を使用してパラメータ `PublicSubnetCidr` の値を参照しています。これにより、テンプレートのデプロイ時にユーザーが指定したCIDRブロックが使用されます。

:::note info
   - **AvailabilityZone**:
サブネットを配置するアベイラビリティゾーンを指定します。ここでは、`Fn::Select` と `Fn::GetAZs` を使用して、リージョン内の最初のアベイラビリティゾーンを選択しています。

**Fn::Select**: リストから特定の要素を選択します。ここでは、最初のアベイラビリティゾーン（インデックス0）を選択しています。
**Fn::GetAZs**: 指定されたリージョン内のアベイラビリティゾーンのリストを取得します。ここでは、`Ref` を使用して現在のリージョンを参照しています。
:::
   - **MapPublicIpOnLaunch**:
     - **説明**: インスタンス起動時にパブリックIPを自動的に割り当てるかどうかを指定します。`true` に設定すると、インスタンスにパブリックIPが自動的に割り当てられます。




### PrivateSubnetリソースの詳細解説

#### PrivateSubnetリソースの定義
```json
"PrivateSubnet": {
  "Type": "AWS::EC2::Subnet",
  "Properties": {
    "VpcId": {
      "Ref": "VPC"
    },
    "CidrBlock": {
      "Ref": "PrivateSubnetCidr"
    },
    "AvailabilityZone": {
      "Fn::Select": [
        "1",
        {
          "Fn::GetAZs": {
            "Ref": "AWS::Region"

```

#### 各プロパティの詳細

**Type**: `AWS::EC2::Subnet`
   - **説明**: このリソースのタイプを指定します。ここでは、サブネットを作成するために `AWS::EC2::Subnet` を指定しています。

:::note info
**Properties**:

   - **VpcId**:
     - サブネットを作成するVPCのIDを指定します。ここでは、`Ref` を使用してVPCリソースのIDを参照しています。
   - **CidrBlock**:
     - サブネットのCIDRブロックを指定します。ここでは、`Ref` を使用してパラメータ `PrivateSubnetCidr` の値を参照しています。これにより、テンプレートのデプロイ時にユーザーが指定したCIDRブロックが使用されます。

   - **AvailabilityZone**:
     - サブネットを配置するアベイラビリティゾーンを指定します。ここでは、`Fn::Select` と `Fn::GetAZs` を使用して、リージョン内の2番目のアベイラビリティゾーンを選択しています。

     - **詳細**:
       - **Fn::Select**: リストから特定の要素を選択します。ここでは、2番目のアベイラビリティゾーン（インデックス1）を選択しています。
       - **Fn::GetAZs**: 指定されたリージョン内のアベイラビリティゾーンのリストを取得します。ここでは、`Ref` を使用して現在のリージョンを参照しています。
:::


### EIPリソースの定義
NATゲートウェイ用のElastic IPを作成します。
```json
"EIP": {
  "Type": "AWS::EC2::EIP"
```




### InternetGatewayリソースの定義
インターネットゲートウェイを作成します。
```json
"InternetGateway": {
  "Type": "AWS::EC2::InternetGateway"
```

#### AttachGateway
インターネットゲートウェイをVPCにアタッチします。
```json
"AttachGateway": {
  "Type": "AWS::EC2::VPCGatewayAttachment",
  "Properties": {
    "VpcId": {
      "Ref": "VPC"
    },
    "InternetGatewayId": {
      "Ref": "InternetGateway"
```

### NATGatewayリソースの定義
パブリックサブネット内にNATゲートウェイを作成し、Elastic IPを割り当てます。
```json
"NATGateway": {
  "Type": "AWS::EC2::NatGateway",
  "Properties": {
    "AllocationId": {
      "Fn::GetAtt": [
        "EIP",
        "AllocationId"
      ]
    },
    "ConnectivityType": "public",
    "SubnetId": {
      "Ref": "PublicSubnet"
```
#### NATGateway
- **Type**: `AWS::EC2::NatGateway`
:::note info
- **Properties**:
  - **AllocationId**: Elastic IPの割り当てIDを指定します。ここでは、`Fn::GetAtt` を使用してEIPリソースの割り当てIDを取得しています。
  - **ConnectivityType**: 接続タイプを指定します。ここでは `public` を指定しています。
  - **SubnetId**: NATゲートウェイを配置するサブネットのIDを指定します。ここでは、`Ref` を使用してパブリックサブネットリソースのIDを参照しています。

#### Fn::GetAtt 関数は、テンプレート内でリソースの属性を取得するために使用されます
:::
### RouteTableforPublicリソースの定義
```json
"RouteTableforPublic": {
  "Type": "AWS::EC2::RouteTable",
  "Properties": {
    "VpcId": {
      "Ref": "VPC"
```
#### RouteTableforPublic
パブリックサブネット用のルートテーブルを作成します。
- **Type**: `AWS::EC2::RouteTable`
- **Properties**:
  - **VpcId**: VPCのIDを指定します。ここでは、`Ref` を使用してVPCリソースのIDを参照しています。

### RouteTableforPrivateリソースの定義
プライベートサブネット用のルートテーブルを作成します。
```json
"RouteTableforPrivate": {
  "Type": "AWS::EC2::RouteTable",
  "Properties": {
    "VpcId": {
      "Ref": "VPC"
```
#### RouteTableforPrivate
プライベートサブネット用のルートテーブルを作成します。
- **Type**: `AWS::EC2::RouteTable`
- **Properties**:
  - **VpcId**: VPCのIDを指定します。ここでは、`Ref` を使用してVPCリソースのIDを参照しています。

### RouteForPublicリソースの定義
パブリックルートテーブルにデフォルトルートを追加し、インターネットゲートウェイを経由するように設定します。
```json
"RouteForPublic": {
  "Type": "AWS::EC2::Route",
  "DependsOn": "AttachGateway",
  "Properties": {
    "RouteTableId": {
      "Ref": "RouteTableforPublic"
    },
    "DestinationCidrBlock": "0.0.0.0/0",
    "GatewayId": {
      "Ref": "InternetGateway"
```
#### RouteForPublic
- **Type**: `AWS::EC2::Route`
- **DependsOn**: `AttachGateway`
- **Properties**:
  - **RouteTableId**: パブリックルートテーブルのIDを指定します。ここでは、`Ref` を使用してパブリックルートテーブルリソースのIDを参照しています。
  - **DestinationCidrBlock**: デフォルトルート（`0.0.0.0/0`）を指定します。これは、すべての外部トラフィックをインターネットゲートウェイにルーティングすることを意味します。
  - **GatewayId**: インターネットゲートウェイのIDを指定します。ここでは、`Ref` を使用してインターネットゲートウェイリソースのIDを参照しています。
:::note info
DependsOn 属性は、CloudFormationテンプレート内で __リソースの作成順序を制御__ するために使用されます。特定のリソースが他のリソースに依存している場合、そのリソースが作成される前に依存するリソースが作成されることを保証します。この属性は、RouteForPublic リソースが作成される前に AttachGateway リソースが作成されることを保証します。これにより、インターネットゲートウェイが正しく設定されてからルートが作成されることが保証されます。DependsOn 属性を使用することで、リソースの作成順序を明示的に指定し、依存関係があるリソースが正しい順序で作成されることを保証します。
:::

### RouteForPrivateリソースの定義
プライベートルートテーブルにデフォルトルートを追加し、NATゲートウェイを経由するように設定します。
```json
"RouteForPrivate": {
  "Type": "AWS::EC2::Route",
  "DependsOn": "NATGateway",
  "Properties": {
    "RouteTableId": {
      "Ref": "RouteTableforPrivate"
    },
    "DestinationCidrBlock": "0.0.0.0/0",
    "NatGatewayId": {
      "Ref": "NATGateway"
```
#### RouteForPrivate
- **Type**: `AWS::EC2::Route`
- **DependsOn**: `NATGateway`
- **Properties**:
  - **RouteTableId**: プライベートルートテーブルのIDを指定します。ここでは、`Ref` を使用してプライベートルートテーブルリソースのIDを参照しています。
  - **DestinationCidrBlock**: デフォルトルート（`0.0.0.0/0`）を指定します。これは、すべての外部トラフィックをNATゲートウェイにルーティングすることを意味します。
  - **NatGatewayId**: NATゲートウェイのIDを指定します。ここでは、`Ref` を使用してNATゲートウェイリソースのIDを参照しています。

### SubnetRouteTableAssociation1リソースの定義
パブリックサブネットをパブリックルートテーブルに関連付けます。
```json
"SubnetRouteTableAssociation1": {
  "Type": "AWS::EC2::SubnetRouteTableAssociation",
  "Properties": {
    "SubnetId": {
      "Ref": "PublicSubnet"
    },
    "RouteTableId": {
      "Ref": "RouteTableforPublic"
```
#### SubnetRouteTableAssociation1
- **Type**: `AWS::EC2::SubnetRouteTableAssociation`
- **Properties**:
  - **SubnetId**: パブリックサブネットのIDを指定します。ここでは、`Ref` を使用してパブリックサブネットリソースのIDを参照しています。
  - **RouteTableId**: パブリックルートテーブルのIDを指定します。ここでは、`Ref` を使用してパブリックルートテーブルリソースのIDを参照しています。

### SubnetRouteTableAssociation2リソースの定義
プライベートサブネットをプライベートルートテーブルに関連付けます。
```json
"SubnetRouteTableAssociation2": {
  "Type": "AWS::EC2::SubnetRouteTableAssociation",
  "Properties": {
    "SubnetId": {
      "Ref": "PrivateSubnet"
    },
    "RouteTableId": {
      "Ref": "RouteTableforPrivate"
```
#### SubnetRouteTableAssociation2
プライベートサブネットをプライベートルートテーブルに関連付けます。
- **Type**: `AWS::EC2::SubnetRouteTableAssociation`
- **Properties**:
  - **SubnetId**: プライベートサブネットのIDを指定します。ここでは、`Ref` を使用してプライベートサブネットリソースのIDを参照しています。
  - **RouteTableId**: プライベートルートテーブルのIDを指定します。ここでは、`Ref` を使用してプライベートルートテーブルリソースのIDを参照しています。


### EC2SecurityGroupリソースの定義
インバウンドルールがないEC2インスタンス用のセキュリティグループを作成します。
```json
"EC2SecurityGroup": {
  "Type": "AWS::EC2::SecurityGroup",
  "Properties": {
    "VpcId": {
      "Ref": "VPC"
    },
    "GroupDescription": "No Inbound Rule Security Group",
    "GroupName": "h4b-ec2-sg",
```

#### EC2SecurityGroup
- **Type**: `AWS::EC2::SecurityGroup`
- **Properties**:
  - **VpcId**: VPCのIDを指定します。ここでは、`Ref` を使用してVPCリソースのIDを参照しています。
  - **GroupDescription**: セキュリティグループの説明を指定します。ここでは「No Inbound Rule Security Group」としています。
  - **GroupName**: セキュリティグループの名前を指定します。ここでは `h4b-ec2-sg` としています。


#### 読んで頂きまして、ありがとうございました。