CloudFormationのテンプレートをYAMLで書く時の文字列の書き方について

## はじめに

CloudFormationのテンプレートは、JSONまたはYAMLで記述できます。

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/template-formats.html

テンプレートを読むだけならJSONでもYAMLでも良いのですが、自分でテンプレートを書くとなるとYAMLの方が書きやすいと思っています。

ただ、YAMLで書いていると文字列の記述に困ることがあります。本記事ではそのことに触れたいと思います。

## YAMLで文字列を書くときにありがちな状況

YAMLで書いていると、以下の状況が混在することがあります。

* 文字列をシングルクォーテーション( `'` )で囲んでいる
* 文字列をダブルクォーテーション( `"` )で囲んでいる
* 文字列を上記のいずれでも囲んでいない

正確には、テンプレートを書いている人がテンプレートを書いているうちに混在させてしまうことがあると考えています。一通り書き終えたら文字列をシングルクォーテーションやダブルクォーテーションで囲んでいる、そうかと思えば文字列を囲んでいないことがあるといった状況です。

## だが、記述方法が混在していてもスタックは作れる

先に述べておくと、文字列の記述方法が混在していても、スタックは作れます。

* `'`または`"`で囲む
* どちらでも囲まない

更に、以下の記述を加えてしまったとしても、スタックは作れます。

* 数値を'または"で囲む
    * 整数や浮動小数点など、数値として認識させるなら何も囲まないのが仕様のようだが、囲んでも認識される
* true・falseを`'`または`"`で囲む
    * 整数や浮動小数点などと同様で、真偽値は何も囲まないのが仕様のようだが、囲んでも認識される

記述した結果で出来上がったテンプレートが上記の状態になってしまっていたとしても、そのテンプレートでCloudFormationでスタックを作ることが出来るのであれば、それは使えるテンプレートということになります。

ですが、これで良いかどうかということはまた別問題です。一人でテンプレートを書き、一人で使っている分には問題にはならないかもしれませんが、複数人で作業をしている場合は問題になってもおかしくはありません。むしろ、問題にされがちなことになると思います。

## 何故こんなことになるのか？

公式のドキュメントを含め、テンプレートを書くためにネット上で参考になると思われる記事を見ていると、文字列の書き方が混在しているからだと考えています。

そもそも、公式のドキュメントでも「シングルクォーテーションで囲む」「ダブルクォーテーションで囲む」「どちらでも囲んでいない」記述が混在しています。

下記の例は、リソースタイプの記述例を抜き出してみたものです。

### 例: シングルクォーテーションで囲む

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/quickref-ecs.html

```YAML
ECSCluster:
  Type: 'AWS::ECS::Cluster'
```

### 例: ダブルクォーテーションで囲む

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/template-formats.html

```YAML
MyEC2Instance: #An inline comment
  Type: "AWS::EC2::Instance"
```

### 例: どちらでも囲んでいない

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/quickref-autoscaling.html

```YAML
mySimpleConfig:
  Type: AWS::AutoScaling::LaunchConfiguration
```

公式のドキュメントでもこうなっていますので、いろいろな記事を参考にしてテンプレートを書いているうちに記述がぶれてしまっても不思議はなさそうです。

## YAMLの仕様と、実際にYAMLでテンプレートを記述したことから認識している事柄について

ここで、YAMLの仕様について触れてみます。

YAMLでは、シングルクォーテーション（引用符、「'」）またはダブルクォーテーション（二重引用符、「"」）で囲むとそれは強制的に文字列として扱うという仕様があります。

私が最初にYAMLでテンプレートを書くことにした際、以下の文献を参考にさせてもらいました。今でも参考にさせてもらっています。

https://magazine.rubyist.net/articles/0009/0009-YAML.html#%E3%82%B9%E3%82%AB%E3%83%A9%E3%83%BC%E3%81%A8%E3%83%87%E3%83%BC%E3%82%BF%E5%9E%8B

このことからすると

* 文字列としたい部分はシングルクォーテーションまたはダブルクォーテーションで囲めば良い
* だが、どちらでも囲まなかったとしても、それが数値系の型や真偽値などに該当しない、いわゆる文字列型として認識できる記述であれば、文字列として認識される

と解釈して良さそうです。上記の文献のほか、この後で提示する各種の文献を読み込んで調査をしたのですが、正直なところ、混乱しました。

それと、以下の点は経験した事柄から認識しています（CloudFormationのテンプレートをYAMLで書く上での事柄に限定します）。

* 20や5.7などの値をシングルクォーテーションまたはダブルクォーテーションで囲んでも、スタックは正しく作られる
* true・falseの真偽値をシングルクォーテーションまたはダブルクォーテーションで囲んでも、スタックは正しく作られる
* アスタリスクだけを書く場合は、`'*'`または`"*"`とする
    * `Resouces:`を書く際によくある
    * `Resouces: '*'`または`Resouces: "*"`とする

また、YAMLのバージョンは複数あり、1.0から始まって1.1、1.2があります。現在の最新は1.2.2となっていました。

https://yaml.org/

CloudFormationでは1.1をサポートしているとのことです。

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/template-formats.html

> YAML
>    AWS CloudFormation は、いくつかの例外を除き、YAML バージョン 1.1 の仕様をサポートしています。

YAMLバージョン1.1の公式な仕様については、以下になります。

https://yaml.org/spec/1.1/

## CloudFormationの組み込み関数について

ここまでの考察で「文字列型として認識される文字列であれば、`'`または`"`で囲んでも囲まなくても同じ」としてきましたが、CloudFormationのテンプレート内で使える組み込み関数を記述する際には、組み込み関数の仕様に沿って`'`または`"`で囲むことを意識したほうが良さそうです。

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

一例として、`Fn::Sub`という組み込み関数を挙げます。

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

YAMLで`Fn::Sub`関数を使う場合は、以下のように書けます。「マッピングなしの Fn::Sub」という書き方です。

```
!Sub 'arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:vpc/${vpc}'
```

ただ、書き方は書いてあるのですけれど、仕様については明言されていないようです（`'`または`"`で囲むようにとは書かれていない。もしそのような記述を見つけたら、加筆する）。ですが、組み込み関数においてはドキュメントに記載されている内容に沿うのが正しいと思います。

ちなみに私は、CloudFormationの組み込み関数を記述する場合は`"`で囲んでいます。そのため、文字列において混在した状況を自分で作り出してしまうことがあったとしても、`"`で囲んでいるケースが多いです。

## まとめ

これまでの経緯で、以下のように認識して良いと考えています。

* 文字列の書き方は複数あり、`'`や`"`を混在させても、またどちらも書かなくてもテンプレートは作れてしまう
    * 必ず作れるとまでは言い切れないが、経験上は単純な文字列であれば混在を理由にスタックが作れないということはない
    * しかし、経験上というのは厄介な話で、自分の経験したことが全てだとしてしまうと、他人と話をする際に認識が合わないことがある
* 整数や真偽値などは`'`や`"`で囲まないのがYAMLとしての仕様のようだが、囲んだとしてもスタックは作れる
* アスタリスクだけを値として書く場合は、`'*'`または`"*"`とする

ただ、テンプレートを記述するにあたって、一定の基準は設けた方が良いと思います。私は、今後は以下のように記述していくことを進めていき、複数人でテンプレートを記述する際のばらつきを減らしていこうと考えています。

* 単純な文字列は、`'`や`"`で囲まない
* 整数や真偽値も囲まない
* 組み込み関数を書く場合には、組み込み関数のドキュメントに書かれている内容に沿って記述する。
    * `'`・`"`のどちらで囲むかを決めておく

YAMLの仕様により、文字列として記述できる方法が複数あるので、テンプレートを書く側としては自分達でルールを決め、それに沿って書いていくことが望ましい、となると思います。