Using formatlist() keeps complaining about template interpolation value

Preformatted textOn Terraform Cloud, I am working on setting up an S3 bucket policy targeted for Cloud Trail service logging, which is why I would like to list multiple related accounts in the “Resources” section like this:

# Log bucket policy
resource "aws_s3_bucket_policy" "log-bucket-policy" {
bucket = aws_s3_bucket.log-bucket.id
policy = <<POLICY
{
"Version": "2012-10-17",
"Statement": [
    ... # Some more statements going here
    "Action": "s3:PutObject",
    "Resource": "${[formatlist("%v", ["a", "b"])]}",
  ]
}
POLICY
} 

This configuration gives me “Cannot include the given value in a string template: string required.” Any clue as to what I am doing wrong?

P.s.: Interestingly enough, if I leave out the ${...} and go with formatlist(...) directly, as I understand I should be able to in the most recent version of Terraform, it tells me that I am providing a wrong character in a json structure (“o”, while “a” is expected, hinting at the parser expecting “false” instead of “formatlist”)

The expression inside a ${ ... } must always return something that can be converted to a string, because otherwise Terraform can’t concatenate it with the literal string before and after in order to produce a single string result.

To include that result in your output would require converting it to string in some way, such as using jsonencode. However, since this entire value is JSON, I’d suggest generating the whole thing using jsonencode rather than trying to build JSON using string templates:

  policy = jsonencode({
    "Version": "2012-10-17",
    "Statement": [
      # ...some more statements going here
      "Action": "s3:PutObject",
      "Resource": ["a", "b"],
    ],
  })

By using jsonencode you can let Terraform worry about the JSON encoding and just write out the data structure you want to encode. I just used ["a", "b"] literally there because I guessed that your goal was to just generate a plain array of strings as IAM expects, but you can put any expression that returns a list of strings in that position, such as a reference to an arn attribute of some other resource that you want to grant access to/from.

1 Like

Using jsonecode() did the trick, many thanks, Martin!