When you are using the JSON variant of the Terraform language, there are various different mapping rules for how Terraform will interpret JSON in difference parts of the configuration, due to JSON having fewer distinct syntax constructs than the native syntax does.
When you are defining an argument in a resource configuration that would normally use the name = expression
syntax, the expression mapping is the rule that applies to the “expression” part.
The documentation says that you can write a JSON string, in which case:
Parsed as a string template and then evaluated as described below.
(The rule “described below” that text is only relevant when producing a result that isn’t a string. Since policy_document
is a string argument, those details are not relevant.)
Therefore I think you have two main options for expressing this as JSON:
-
Write a JSON string containing a literal JSON document, with all of the necessary escaping to make the outer document valid. That’s too long to write out here in full, but it would start like this:
"policy_document": "{\"Version\":\"2021-10-17\",...}"
-
Write an inline string template that has an interpolation sequence which calls jsonencode
. Again, too long to write out in full, but here’s the start:
"policy_document": "${jsonencode({\"Version\" = \"2021\", /*...*/})}"
If you are asking for a way to write the policy document directly as a JSON object, rather than as a string containing JSON syntax, then I’m afraid there is no way to do that. The provider declares that this argument expects a string and so Terraform requires you to write something that produces a string. The fact that the string happens to include more JSON is not something Terraform is aware of.
The JSON variant of the Terraform language is available primarily so that it can be generated by other software and fed directly to Terraform, rather than written by and maintained by humans. Therefore it’s not optimized for hand-writing or hand-maintenance by humans. If I were writing a program to generate a JSON-based Terraform configuration file containing a resource of this type then I expect I would use the JSON encoder of the language where I wrote the generator. For example, in JavaScript:
JSON.stringify({
"resource": {
"aws_iam_role": {
"test_role": {
// ...
"assume_role_policy": JSON.stringify({
"Version": "2012-10-17",
// ...
}),
},
},
},
})
This would be sufficient as long as the policy document is entirely static. If the policy document needs to include values that come from other resources in the same module then there’d be no way to avoid using Terraform’s own jsonencode
in a template interpolation as I showed earlier, because if the JSON result contains dynamic data from Terraform then Terraform must be the one to actually create the JSON string.