简体   繁体   中英

Terraform AWS IAM Role “inline_policy.0.policy” contains an invalid JSON policy using ${file xyz} and jsonencode

Please see below. First, with only the assume role policy, it works. If I remove the inline the policy, it all validates. When left in, (it looks like this.) It does not validate. I am using Terragrunt, but I believe this is a Terraform error.

resource "aws_iam_role" "test_role" {
  name   = "my_test_role"
  assume_role_policy = jsonencode("${file("..//Policies//policy_assume_role.json")}")
  inline_policy {
    name = "inline_s3_policy"
    policy = jsonencode("${file("..//Policies//policy_s3_bucket.json")}")
  }
}

Then my policy_s3_bucket.json looks like this

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:ListBucket"],
      "Resource": ["arn:aws:s3:::company-terragrunt-terraform-state-123456789-us-east-1"]
    },
    {
      "Effect": "Allow",
      "Action": ["s3:GetObject"],
      "Resource": ["arn:aws:s3:::company-terragrunt-terraform-state-123456789-us-east-1/*"]
    }
  ]
}

I get - ““inline_policy.0.policy” contains an invalid JSON policy” … but the JSON is valid. My configured user does have access to those buckets. Also, the assume role policy is working without the s3 inline in there. The assume role policy json looks to be the same format, and I'm pulling it in the same fashion.

In your configuration you seem to be passing the result of the file function into the jsonencode function.

The result of the file function is always a string representing the UTF-8-encoded contents of the file, and so if your file contains already-encoded JSON then it will return a string containing JSON.

If you pass a string to jsonencode then it will produce a JSON-formatted string, whereas an IAM policy requires a JSON object, and therefore the API will return an error as shown here.

To be more specific, your current configuration will set policy to something like the following (truncated for brevity):

"{\n  \"Version\": \"2012-10-17\"m\n  \"Statement\": ..."

If you know that your external file already contains valid JSON then you can assign the result of file directly to the policy argument, like this:

resource "aws_iam_role" "test_role" {
  name               = "my_test_role"
  assume_role_policy = file("${path.module}/../Policies/policy_assume_role.json")

  inline_policy {
    name   = "inline_s3_policy"
    policy = file("${path.module}/../Policies/policy_s3_bucket.json")
  }
}

If you'd like Terraform to parse the JSON and reencode it -- which will mean that Terraform will check whether the JSON content is valid locally first, and will always generate it in a consistent minified form, you can alternatively pass the file result to jsondecode first, and then pass that result to jsonencode , thereby "round-tripping" through the Terraform language type system and back to JSON again:

resource "aws_iam_role" "test_role" {
  name               = "my_test_role"
  assume_role_policy = jsonencode(jsondecode(file("${path.module}/../Policies/policy_assume_role.json")))

  inline_policy {
    name   = "inline_s3_policy"
    policy = jsonencode(jsondecode(file("${path.module}/../Policies/policy_s3_bucket.json")))
  }
}

However, this would be a pretty unusual approach and so if you adopt it then I would recommend including a comment explaining why you did it, so that a future reader can understand why this seemingly-redundant transformation is included.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM