【AWS】CloudFormationでよく使われる関数をわかりやすく解説する

CloudFormationテンプレートを作成するにあたって関数の理解は必須です。私が自分で環境を構築して、実際に利用したものをご紹介します。

序盤で紹介する３つの関数、**Ref、Sub、GetAtt**を理解すれば、基本的にCloudFormationテンプレート作成は問題ないかと思います:sparkles:

## 組み込み関数とは
CloudFormationテンプレート内で使用できる特殊な関数です。これらの関数を使用することで、テンプレート内で生成されるリソースの情報を取得することができるようになったり、またその値に対して加工したりすることができます。たとえば基本になる**Ref関数**では、リソース作成時に出力される値を取得することができます。

上記ではVPCが作成されるときに生成されるVPCIDを同じResource内で生成するパブリックサブネットの作成元として参照することができます。
![スクリーンショット 2023-07-19 23.28.06.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/984662/789e5622-ebb3-7f8d-7736-35143b8022eb.jpeg)
## Ref
上記の例で説明した通りです。他のリソースの値を参照することができます。
```yml:network.yaml
Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.1.0.0/16
      Tags:
        - Key: Name
          Value: vpc-cfn

 PubSub1:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: ap-northeast-1a
      VpcId: !Ref VPC
      CidrBlock: 10.1.1.0/24
      Tags:
        - Key: Name
          Value: pub-sub1-cfn
```

## Sub
Refと同様、値を参照しますが、さらに加工して文字列を追加することができます。下記の例ではバケットポリシーを設定する際、ポリシー内の記述でバケット（オブジェクト）を指定しています。

ポリシーを適用するバケットではなく、ポリシー内に記述する対象バケットです。単純なArnではなく /* という指定も必要なため、**Sub**で記述しています。

```yml:s3.yaml
Parameters:
  BucketName:
    Type: String
    Description: A name for the XX bucket.

Resources:
  S3:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Ref BucketName

  S3ALBPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref S3
      PolicyDocument:
        Version: "2012-10-17"
        Statement: 
          - Effect: Allow
            Principal: 
              AWS: arn:aws:iam::XXX:root
            Action: s3:PutObject
            Resource: !Sub arn:aws:s3:::${BucketName}/*
```

## GetAtt
Subよりもより細かいパラメータを取得できます。Subでとれない...って時はこのGetAtt使ってみるといいです。**Arn**に使われることが多いです。**リソース名.XXX**という表記で具体的なパラメータを指定します。下記の例ではサブスクリプションフィルタ自体に付与するネストされたIAMロールと、送信先の取得で使用しています。
```yaml:cloudwatch.yaml
Resources:
  SubscriptionFileter01:
    Type: AWS::Logs::SubscriptionFilter
    Properties:
      DestinationArn: !GetAtt DeliveryStream01.Arn
      FilterPattern: ""
      LogGroupName: !Ref LogGroupName01
      RoleArn: !GetAtt SubscriptionFileterRole.Outputs.SubscriptionFileterRole
```
## ImportValue
**クロススタック**で、他リソースで出力した値を取得するときに使います。この関数は短縮系なしです。

```yaml:network.yaml
...
Outputs:
  PriSub:
    Value: !Ref PriSub
    Export:
      Name: prisub-cfn-id
```
```yaml:ec2.yaml
  EC2:
    Type: AWS::EC2::Instance
    Properties:
      Tags:
        - Key: Name
          Value: ec2-cfn
      InstanceType: t3.nano 
      NetworkInterfaces:
        - AssociatePublicIpAddress: false
          DeviceIndex: 0 
          GroupSet:
            - !Ref EC2SG
          SubnetId: {Fn::ImportValue: prisub-cfn-id}
```
クロススタックの詳細はこちら

https://qiita.com/hiyanger/items/0881229b233f13b0914f

## Base64（あまり使わない）
表記は**Fn::Base64**です。あまり使いことはないかもですが、個人的にEC2のユーザーデータを仕込むことがあり、そのときに必須な関数だったため使用しました。
```yaml:ec2.yaml
  EC2:
    Type: AWS::EC2::Instance
    Properties:
    ...
      UserData:
        Fn::Base64: |
```

## その他関数
他にもいろいろあるので、一応紹介しておきます。頭にいれておくだけでも使える機会があるかもしれません。

**FindInMap**：Mappingセクションで定義された値を取得する。
**Transform**：テンプレート処理に使用するマクロを指定できる。
（ネストとにてますが、こちらはテンプレートにテンプレートを組み込むイメージです）
**Cidr**：CIDRアドレスブロックの配列を返す。サブネットとかで使える。
**GetAZs**：リージョンの取得。
**Join**：文字連結。Subで紹介した対象バケットはこの関数でも表現可能。
**Select**：インデックスによってオブジェクトのリストから1つのオブジェクトを返します。
**Split**：文字列を文字列値のリストに分割し、結果の文字列のリストから要素を選択できるようにする。

※その他関数はほぼこちらからの引用です

https://o2mamiblog.com/aws-cloudformation-intrinsic-function-beginner-1/

https://qiita.com/leomaro7/items/b3ca81add0036ef09e80