Terraform12 syntax help for data "template_file"

Actually i want to rewrite from scratch code from 0.11 to 0.12 version. And cant figure out how to iterate over list that terraform creates several templates files and substitute subnet to policy file

Terraform Configuration Files
terraform 0.11

data "template_file" "this_code_build_networkinterface_policy" {
  count = "${length(var.vpc_private_subnets)}"
  template = "${file("${path.module}/codebuild_subnet_policy.json.tpl")}"
  
  vars {
    region = "${var.region}"
    user = "${data.aws_caller_identity.aws_user_info.account_id}"
    subnet = "${var.vpc_private_subnets[count.index]}"
  }
}

terraform 0.12

data "template_file" "this_code_build_networkinterface_policy" {
  count = length(var.vpc_private_subnets)
  template = file("${path.module}/codebuild_subnet_policy.json.tpl")
  
  vars = {
    region = var.region
    user = data.aws_caller_identity.aws_user_info.account_id
    subnets = var.vpc_private_subnets[count.index]
  }
}

json.tpl file

{
    "Version": "2012-10-17",
    "Statement": [
    {
      "Effect": "Allow",
      "Action": [
          "ec2:CreateNetworkInterfacePermission"
      ],
      "Resource": "arn:aws:ec2:${region}:${user}:network-interface/*",
      "Condition": {
          "StringEquals": {
              "ec2:Subnet": [
                  "arn:aws:ec2:${region}:${user}:subnet/${subnet}"
              ],
              "ec2:AuthorizedService": "codebuild.amazonaws.com"
          }
      }
    }
    
    
    ]
}

Error: Incorrect attribute value type

on modules/_ci_cd/build.tf line 30, in data “template_file” “this_code_build_networkinterface_policy”:
30: vars = {

Inappropriate value for attribute “vars”: element “subnets”: string required.

Hi! This works fine for me locally (once I renamed “subnets” to “subnet”, to match the variable used in your template). Are you getting an error?

As @mildwonkey noted, there doesn’t seem to be anything obviously incorrect here, so if you can share an error message that’d be great.

With that said, on the topic of “rewriting for 0.12” I think there are some good opportunities for simplification here once you have completed your upgrade.

The primary thing I would recommend is to move away from templating JSON using template_file and to use the jsonencode function instead. That way you don’t need to worry about the JSON syntax yourself and can just describe the values you want to encode:

locals {
  account_id = data.aws_caller_identity.aws_user_info.account_id
}

resource "aws_iam_policy" "example" {
  # ...

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Action = ["ec2:CreateNetworkInterfacePermission"]
        Resource = "arn:aws:ec2:${var.region}:${local.account_id}:network-interface/*"
        Condition = {
          StringEquals = {
            "ec2:Subnet" = [
              for s in var.vpc_private_subnets :
              "arn:aws:ec2:${var.region}:${local.account_id}:subnet/${s}"
            ]
            "ec2:AuthorizedService": "codebuild.amazonaws.com"
          }
        }
      },
    ]
  })
}

If having the policy template in a separate file is important, you can achieve a similar result using Terraform 0.12’s built in templatefile function (which is the replacement for the template_file data source) and call jsonencode from inside the template:

${jsonencode({
    Version = "2012-10-17"
    Statement = [
      # etc, etc
    ] 
})}
resource "aws_iam_policy" "example" {
  # ...

  policy = templatefile("${path.module}/codebuild_subnet_policy.json.tpl", {
    region  = var.region
    user    = data.aws_caller_identity.aws_user_info.account_id
    subnets = var.vpc_private_subnets
  })
}
2 Likes

Ok, I’ve fixed as you advised. @apparentlymart

Error: Invalid template interpolation value

  on modules/_ci_cd/build.tf line 51, in resource "aws_iam_role_policy" "this_code_build_policy_subnet":
  51:               "arn:aws:ec2:${var.region}:${local.account_id}:subnet/${s}"

Cannot include the given value in a string template: string required.

I think need to mention that var.vpc_subnets comes from another terraform state file and i referenced it via remote state call. Maybe problem is here ?

I found problem in remote state returned values
private_subnets = [
[
“subnet-03c44xxxxxxx”,
“subnet-0fb62dcxxxxx”,
“subnet-022930xxxxx”,
“subnet-09f03937xxx”,
],
]
I return list of lists. So i fixed output.tf file and seem like all is OK.