CloudFormationの組み込み関数の使い方


CloudFormationのテンプレートはJSON形式で記述しますが、その中で使える組み込み関数というものがとても便利だったので使い方を紹介します。

リファレンスなどは公式ドキュメントを参照してください。

[組み込み関数リファレンス - AWS CloudFormation](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference.html)

# Fn::GetAZs

指定されたリージョンで使用可能なアベイラビリティゾーン（以下、AZ）の配列を返します。

使用可能なAZはアカウントごとに異なる（例えば、東京リージョンは全部で3つのリージョンがあり、その中からアカウントごとにリージョンを2つまで割り振られる[^1]）ので、AZをベタ書きしてしまうと他のアカウントでは使えない場合があります。この関数を使うことで汎用的なテンプレートを書くことができます。

例: VPCで2つのAZにサブネットを作る

```
  "Resources": {
    "VPC": {
      "Type": "AWS::EC2::VPC",
      "Properties": {
        "CidrBlock": "172.31.0.0/16",
        "InstanceTenancy": "default",
        "EnableDnsSupport": "true",
        "EnableDnsHostnames": "true"
      }
    },
    "SubnetTrustAZ1": {
      "Type": "AWS::EC2::Subnet",
      "Properties": {
        "CidrBlock": "172.31.1.0/24",
        "AvailabilityZone": { "Fn::Select" : ["0", { "Fn::GetAZs" : { "Ref" : "AWS::Region" } } ] },
        "VpcId": {
          "Ref": "VPC"
        }
      }
    },
    "SubnetTrustAZ2": {
      "Type": "AWS::EC2::Subnet",
      "Properties": {
        "CidrBlock": "172.31.2.0/24",
        "AvailabilityZone": { "Fn::Select" : ["1", { "Fn::GetAZs" : { "Ref" : "AWS::Region" } } ] },
        "VpcId": {
          "Ref": "VPC"
        }
      }
    },
```

この例では

```
"AvailabilityZone": { "Fn::Select" : ["0", { "Fn::GetAZs" : { "Ref" : "AWS::Region" } } ] }
```

が

```
"AvailabilityZone": { "Fn::Select" : ["0", { "Fn::GetAZs" : "ap-northeast-1" } ] }
```

こうなって

```
"AvailabilityZone": { "Fn::Select" : ["0", ["ap-northeast-1a","ap-northeast-1b"] ] }
```

こうなって（ここからはアカウントごとに異なる）

```
"AvailabilityZone": "ap-northeast-1a"
```

こうなります。

# Fn::Select

先ほどの例でも登場した関数です。配列の中から指定したインデックスの値を返します。

# Ref

先ほどの例でも登場した関数です。指定したパラメータまたはリソースの値を返します。

値はリソースによって名前だったりIDだったり変わりますがだいたい一意な値が返ります。また、テンプレートのパラメータの値を取得するのにも使います。

例: パラメータで入力した値を取得する

```
  "Parameters" : {
    "UserPassword": {
      "Type": "String",
      "Description" : "user account password"
    }
  },
  "Resources" : {
  "User" : {
    "Type" : "AWS::IAM::User",
    "Properties" : {
      "LoginProfile": {
        "Password": { "Ref" : "UserPassword" }
      }
    }
  }
```

# Fn::Join

指定された配列を、指定された連結文字列で結合します。

連結文字列を空文字にすれば、単なる文字列連結にも使えます。

例: パラメータで入力された配列を、カンマ区切りの文字列に変換する

```
  "Parameters" : {
    "DMZSubnets": {
      "Type": "List<AWS::EC2::Subnet::Id>",
      "Description" : "Select Trust subnets"
    },

  "Resources": {
    "curationConfigurationTemplate": {
      "Type": "AWS::ElasticBeanstalk::ConfigurationTemplate",
      "Properties": {
        "OptionSettings": [          {
            "Namespace": "aws:ec2:vpc",
            "OptionName": "Subnets",
            "Value": { "Fn::Join" : [ ",", { "Ref": "DMZSubnets" } ] }
          },
```

かなり省略してしまっていますが、やりたいことはパラメータで入力された配列`List<AWS::EC2::Subnet::Id>`を`Value`の値にカンマ区切りに変換して渡しています。

例えば、パラメータの`DMZSubnets`が`["subnet-aaaaaa","subnet-bbbbbb"]`だとすると、

```
"Value": { "Fn::Join" : [ ",", { "Ref": "DMZSubnets" } ] }
```

これが

```
"Value": { "Fn::Join" : [ ",", ["subnet-aaaaaa","subnet-bbbbbb"] ] }
```

こうなって

```
"Value": "subnet-aaaaaa,subnet-bbbbbb"
```

こうです。

# Fn::GetAtt

指定されたオブジェクトから特定の属性値を取得します。

例: 作成したRDS（AWS::RDS::DBInstance）から、ポート番号とエンドポイントをOutPutする。

```
  "Resources": {
    "MySQL" : {
      "Type" : "AWS::RDS::DBInstance",
      "Properties" : {
        (省略)
      }
    }
  },
  "Outputs": {
    "EndpointAddress": {
      "Value": { "Fn::GetAtt" : [ "MySQL" , "Endpoint.Address" ] }
    },
    "EndpointPort": {
      "Value": { "Fn::GetAtt" : [ "MySQL" , "Endpoint.Port" ] }
    }
  }
```

# その他

まだ他にもいくつかありますので、実際に使った時に書こうと思います。

Fn::Base64, Fn::FindInMap, 条件関数,,,

# 参考

似たような記事があるんじゃないかなと思って検索したらおもいっきりありましたね。。。

[AWS CloudFormation テンプレートリファレンス – 組み込み関数(Intrinsic Function) ｜ Developers.IO](http://dev.classmethod.jp/cloud/aws/cloudformation-tempate-reference-intrinsic-function)


[^1]: 2015/07/04時点