Reputation: 255
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
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