Imran Sandozi
Imran Sandozi

Reputation: 255

JSON Syntax error in Terraform aws_iam_role_policy

So with Terraform, I'm creating an IAM policy and attaching it to a role. I am currently running:

Terraform v0.12.16
provider.aws v2.40.0
provider.template v2.1.2

When executing the code, I am able to initialize terraform with no issue. When running terraform plan, I am being presented with the following error:

Error: "policy" contains an invalid JSON: invalid character '}' looking for beginning of value

  on ec2-iam.tf line 8, in resource "aws_iam_role_policy" "s3_ec2_policy":
   8: resource "aws_iam_role_policy" "s3_ec2_policy" {

I am getting stuck with this error. Any advice would be helpful. Below is my code:

 data "template_file" "s3_web_policy" {
  template = file("scripts/iam/web-ec2-policy.json")
  vars = {
    s3_bucket_arn = "arn:aws:s3:::${var.my_app_s3_bucket}/*"
  }
}

resource "aws_iam_role_policy" "s3_ec2_policy" {
  name = "s3_ec2_policy"
  role = aws_iam_role.s3_ec2_role.id

  policy = data.template_file.s3_web_policy.rendered
}

resource "aws_iam_role" "s3_ec2_role" {
  name = "s3_ec2_role"

  assume_role_policy = file("scripts/iam/web-ec2-assume-role.json")
}

Upvotes: 3

Views: 10451

Answers (1)

Martin Atkins
Martin Atkins

Reputation: 74209

It's common to encounter syntax errors when generating JSON from string templates, because the template language isn't aware of JSON syntax and so you as the tempate author must take care to ensure that brackets are all nested correctly, there are no missing or extra commas, etc.

You can usually avoid problems of this type by generating JSON with Terraform's jsonencode function instead:

resource "aws_iam_role_policy" "s3_ec2_policy" {
  name = "s3_ec2_policy"
  role = aws_iam_role.s3_ec2_role.id

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      # etc, etc
    ]
  })
}

If the policy definition seems too large to include inline in your resource block, you can still factor it out into a separate template file if desired:

resource "aws_iam_role_policy" "s3_ec2_policy" {
  name = "s3_ec2_policy"
  role = aws_iam_role.s3_ec2_role.id

  policy = templatefile("${path.module}/scripts/iam/web-ec2-policy.json.tmpl", {
    s3_bucket_arn = "arn:aws:s3:::${var.my_app_s3_bucket}/*"
  })
}

...but inside the template, rather than using individual template interpolations, just write the entire template as a single call to jsonencode, like this:

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

Note that the template_file data source is for Terraform 0.11 and earlier, and is in Terraform 0.12 only for backward compatibility. You should use the templatefile function instead, which serves the same purpose but is integrated directly into the Terraform language.

Upvotes: 7

Related Questions