JSON文字列を必要とする引数

Terraformのリソースやデータソースの引数にはJSON文字列の指定必要とする場合がある。

例えばaws_iam_policyリソースのpolicy引数には以下のようなJSON文字列を指定する。

resource "aws_iam_policy" "example" {
  name   = "example"
  policy = <<-JSON
    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Action": "s3:*",
          "Resource": "*"
        }
      ]
    }
  JSON
}

上記のようにヒアドキュメントで直接文字列として記述した場合、カッコを忘れるなどの構文エラーがある場合でもterraform planなどのコマンドで検出できない。
terraform applyの実行時にはじめてエラーが発生する。

jsonencode関数

jsonencode関数を使うと、JSON文字列を構文エラー無く記述できる。

jsoneoncode(オブジェクト)

terraform consoleで確認すると以下のようになる。

> jsonencode({a = 1, b = 2})
"{\"a\":1,\"b\":2}"

{a = 1, b = 2}という文字列を"{\"a\":1,\"b\":2}"というJSON文字列に変換できる。

jsonencode関数の利用例

上記のaws_iam_policyリソースのpolicy引数にjsonencode関数を使うと以下のようになる。

resource "aws_iam_policy" "example" {
  name   = "example"
  policy = jsonencode({
    Version   = "2012-10-17",
    Statement = [
      {
        Effect   = "Allow",
        Action   = "s3:*",
        Resource = "*"
      }
    ]
  })
}

jsonencode関数の引数{...}の部分はTerraformのHCLのオブジェクト。
そのため、カッコを忘れるなど構文エラーがある場合にterraform planで構文エラーを検出できる。

試しに一箇所カッコを削除してterraform planを実行すると以下のようなエラーが表示され、エラーとして検出できる。

$ terraform plan
│ Error: "policy" contains an invalid JSON policy: invalid character ']' after object key:value pair, at byte offset 126
│   with aws_iam_policy.sample,
│   on main.tf line 55, in resource "aws_iam_policy" "sample":
│   55:   policy = <<-JSON
│   56:     {
│   57:       "Version": "2012-10-17",
│   58:       "Statement": [
│   59:         {
│   60:           "Effect": "Allow",
│   61:           "Action": "s3:*",
│   62:           "Resource": "*"
│   63:       ]
│   64:     }
│   65:   JSON

オブジェクトの代わりにJSON記法で記述する

Terraformのオブジェクトは{ 引数 = 値 }の形式だけでなくJSON記法({ "キー": 値 })でも記述できる。
そのためjsonencode関数の引数に指定するオブジェクトをJSON記法で記述するとさらに自然となる。

上記の例をJSON記法で記述すると以下のようになる。

resource "aws_iam_policy" "example" {
  name   = "example"
  policy = jsonencode({
    "Version": "2012-10-17",
    "Statement": [
      {
        "Effect": "Allow",
        "Action": "s3:*",
        "Resource": "*"
      }
    ]
  })
}