※この記事はTerraform v0.12系で検証してます。
はじめに
まずはこちらをご覧ください。AssumeRoleを定義したこのコード、assume_role_policyにはjsonencode関数を使っていてその引数としてJSONをベタ書きしています。
resource "aws_iam_role" "test_role" {
name = "test_role"
assume_role_policy = jsonencode({
"Version" : "2012-10-17",
"Statement" : [
{
"Effect" : "Allow",
"Principal" : {
"Service" : "ecs-tasks.amazonaws.com"
},
"Action" : "sts:AssumeRole"
}
]
})
}
なんとこのコード、ちゃんとApplyできるんです!!
引数にはJSONを渡していますが、これはTerraformのMap型として解釈され、その上でJSONにエンコードされます。
何が便利か?
上述の例だと便利さがいまいちなので少しだけマシな例を挙げると
resource "aws_iam_role_policy" "test_role_policy" {
name = "test_role_policy"
role = aws_iam_role.test_role.id
policy = jsonencode({
"Version" : "2012-10-17",
"Statement" : [
{
"Effect" : "Allow",
"Action" : [
"s3:ListBucket"
],
# コメントも書けるし当然変数も埋め込める
"Resource" : [
aws_s3_bucket.this.arn
]
},# ケツカンマがあっても動く
]
})
}
このような感じでJSONといいつつTerraformのMap型なのでコメントが書けたり変数が埋め込めたり、ケツカンマをつけたりできます。(もちろんカンマなしもOKです)
Terraformのリソースの引数にJSONを入れる方法は幾つかありますが、それぞれ大小問題があります。
- ヒアドキュメントでJSON文字列を定義する
- コメントを書けない
- カンマをつけ忘れたりつけすぎるとエラー
- ネストが崩れて見にくい
- 別ファイルとして定義してfileやtemplate関数で呼ぶ
- コメントを書けない
- カンマをつけ忘れたりつけすぎるとエラー
- テンプレートで変数を埋め込んでるケースだと場合によってはリンターに怒られる
- aws_iam_policy_documentのように専用のデータソースで書く
- JSONからは離れてしまうのでAWSのドキュメントなどにあるJSONサンプルをコピペできない
- container_definitionsのようにデータソースが無い場合もある
jsonencode関数にJSONを渡す方法はそれらをいい感じに解決できます。(多分)
- 公式ドキュメントのJSONサンプルをコピペできる
- コメント書ける
- カンマなくてもあってもOK
- ちゃんとネストされる
- どんなリソースでも使える
(多分)と書いたのは、私自身、まだそんなにこの書き方を使っていないので思わぬところでハマりどころがあるかもしれなかもと思ったからです。が、この記事で書いたようなサンプルはちゃんと動くので多分大丈夫でしょう。なんかハマったら追記します!
なんで動くか
そもそもjsonencode関数はTerraformの値をJSON文字列にエンコードする関数です。
TerraformのMap型はKeyとValueの区切りに=を使いますが、実は=の代わりにコロンを使うこともできます。
コロン区切りのネスト可能な{}で囲まれたKey Value、つまりJSONのフォーマットはTerraformの構文中ではMapとして解釈されjsonencode関数によって再びJSON文字列に戻されるのでこの書き方が機能します。
- jsonencode関数のドキュメント
- Map型のドキュメント
おわりに
Terraformのjsonencode関数にはJSONを入れても動いてHappy!!やったね。