LoginSignup
4
4

More than 3 years have passed since last update.

Terraform で AWS のポリシー JSON にリストを埋め込みたいとき

Posted at

AWS のポリシーを書くときに JSON を heredoc で書くことがあると思います:

elastic_search_domain_policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowSpecificIpAddresses",
      "Effect": "Allow",
      "Principal": {
        "AWS": "*"
      },
      "Action": [
        "es:*"
      ],
      "Condition": {
        "IpAddress": {
          "aws:SourceIp": [
            "9.8.7.6",
            "10.11.12.13",
            "100.101.102.103",
            "11.22.33.44"
          ]
        }
      },
      "Resource": "arn:aws:es:ap-northeast-1:000000000000:domain/my-aws-elasticsearch/*"
    }
  ]
}

このなかで特定の IP のリストに対して、たとえば

allow.tf
locals {
  allowed_ips = ["9.8.7.6", "10.11.12.13", "100.101.102.103", "11.22.33.44"]
}

のように Allow 対象の IP をリストで持っている + リストは variable とかで渡ってくるという場合、この list を埋め込む必要があります。

Interpolation?

これに対し普通に Interpolation とかを使うとエラーになりますね:

allow.tf
resource "aws_elasticsearch_domain_policy" "elasticsearch_policy" {
  domain_name = "${aws_elasticsearch_domain.elasticsearch.domain_name}"

  access_policies = <<POLICY
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowSpecificIpAddresses",
      "Effect": "Allow",
      "Principal": {
        "AWS": "*"
      },
      "Action": [
        "es:*"
      ],
      "Condition": {
        "IpAddress": {
          "aws:SourceIp": "${local.allowed_ips}"
        }
      },
      "Resource": "${aws_elasticsearch_domain.elasticsearch.arn}/*"
    }
  ]
}
  POLICY
}

Error: Invalid template interpolation value
local.ngw_public_ips is list of string with 2 elements

どうするか

この場合、リソース + heredoc で書くのをやめて、データソースで定義する方法があります

aws_iam_role_policy リソースに対して
aws_iam_policy_document データソースを使えるように:
https://www.terraform.io/docs/providers/aws/guides/iam-policy-documents.html

ただ、aws_elasticsearch_domain_policy のようにデータソースで記述できないケースがあります:
https://www.terraform.io/docs/providers/aws/r/elasticsearch_domain_policy.html

jsonencode を使う

その場合 join を駆使して……とか考えますが、
そうしなくとも jsonencode を使うのが楽です:

allow.tf
resource "aws_elasticsearch_domain_policy" "elasticsearch_policy" {
  domain_name = "${aws_elasticsearch_domain.elasticsearch.domain_name}"

  access_policies = <<POLICY
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowSpecificIpAddresses",
      "Effect": "Allow",
      "Principal": {
        "AWS": "*"
      },
      "Action": [
        "es:*"
      ],
      "Condition": {
        "IpAddress": {
          "aws:SourceIp": ${jsonencode(local.allowed_ips)}
        }
      },
      "Resource": "${aws_elasticsearch_domain.elasticsearch.arn}/*"
    }
  ]
}
  POLICY
}

こうすることで ${jsonencode(local.allowed_ips)}
["9.8.7.6", "10.11.12.13", ...] と JSON の Array に展開されるので、
そのまま書くことができます。

余談

もし各要素に対して map 的な操作が必要であれば、
バージョン 0.12 から List Comprehension が使えるようになったので、
簡単に各要素を変更することができるようになりました:
https://github.com/hashicorp/terraform/issues/8439


そもそも IP 制限とかではなく IAM ロールを使ったほうがいいってのはあります……

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4