Jsonencode example from docs fails from console

I am trying to build a module which produces AWS IAM policy documents using templatefile() and the string template syntax. However, I am struggling to debug errors with the interpolation and directive syntax.

I am even struggling to get the examples from the docs working:

terraform console
> ${jsonencode({"backends": [for addr in ["10.0.0.1", "10.0.0.2"] : "${addr}:8080"],})}

Error: Invalid character

  on <console-input> line 1:
  (source code not available)

This character is not used within the language.


Error: Invalid expression

  on <console-input> line 1:
  (source code not available)

Expected the start of an expression, but found an invalid expression token.

Ultimately, I hope to have a policy template and allow the user to provide a list of ARNs to include in the Resource section of a statement in a policy document like this:

# file = policy.json
${jsonencode(
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:ListBucket"
            ],
            "Resource": 
              [ for bucket in buckets : "${s3_arn_prefix}${bucket}"],          
        }
    ]
  }
)}


# file = main.tf


# Create an IAM policy document based on the template
data "aws_iam_policy_document" "document" {
    source_json = templatefile("${path.module}/policy.json", {
      s3_arn_prefix = local.s3_arn_prefix, 
      buckets = var.buckets  # a list of bucket names
      })
}

UPDATE:

I was able to get the IAM policy example above to work with a simpler syntax – I just pass the list of ARNs as-is to the template:

# file = policy.json
...
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:ListBucket"
            ],
            "Resource": "${buckets}"
        }


# file = main.tf
data "aws_iam_policy_document" "document" {
    source_json = templatefile("${path.module}/policy.json", {
      buckets = var.buckets # buckets is a list
      })
}

That produces correct IAM policy JSON which can be used to create a managed policy:

...
            "Resource": [
                "arn:aws:s3:::foo",
                "arn:aws:s3:::bar"
            ]

Hi @jaknn,

The example in the docs shows the function used directly without wrapping in ${ and }:

> templatefile("${path.module}/backends.tmpl", { port = 8080, ip_addrs = ["10.0.0.1", "10.0.0.2"] })
backend 10.0.0.1:8080
backend 10.0.0.2:8080

The terraform console prompt expects Terraform language expressions, not string templates. If you want to evaluate a string template in the console then you’d also need to include quotes to indicate your intent to evaluate a template:

> "${templatefile("${path.module}/backends.tmpl", { port = 8080, ip_addrs = ["10.0.0.1", "10.0.0.2"] })}"

The template syntax isn’t adding anything in this case, though: the template consists only of a single interpolation sequence, and so it’s redundant.