❯ terraform version
Terraform v1.6.3
on darwin_amd64
+ provider registry.terraform.io/hashicorp/aws v5.29.0
I working on terraforming AWS IAM trust policies and am tempalating the trust IAM policy which looks like this
{
"Statement": [
%{ for oidc in oidcs ~}
{
"${oidc}:aud": "sts.amazon.com",
"${oidc}:sub": "system:serviceaccount:${sa}"
},
%{ endfor ~}
]
}
I am using this template with the terraform template function which looks like
locals {
backend_config_content = templatefile("${path.module}/json/template.tpl", {
sa = "kube-system:ebs-csi-controller-sa",
account = "804616344559",
oidcs = [
"id/4ECE95AF53127CE866BA",
"id/9173553CA62864"
]
})
}
output "generated_trust_policy" {
value = local.backend_config_content
}
only thing is i am trying to figure out how to remove the comma just before the end of the loop if it is the last item in the list, otherwise it is not a validy policy that can be added to AWS IAM.
I tried adding the following if statement
{
"Statement": [
%{ for oidc in oidcs ~}
{
"${oidc}:aud": "sts.amazon.com",
"${oidc}:sub": "system:serviceaccount:${sa}"
} %{ "," if not loop.last ~}
%{ endfor ~}
]
}
but doing it this way i get an error saying
Call to function "templatefile" failed: ./json/template.tpl:17,14-15: Invalid template directive; A
│ template directive keyword ("if", "for", etc) is expected at the beginning of a %{ sequence..
also tried the following way
{
"Statement": [
%{ for oidc in oidcs ~}
{
"${oidc}:aud": "sts.amazon.com",
"${oidc}:sub": "system:serviceaccount:${sa}"
}%{ if not loop.last ~}
,
%{ endif ~}
%{ endfor ~}
]
}
gives me the error
Call to function "templatefile" failed: ./json/template.tpl:8,21-25: Extra characters in if marker;
│ Expected a closing brace to end the sequence, but found extra characters..
@martinatkins I have attempted to do as you suggested, have copied and pasted exactly and still am getting the the final comma
below is the output from the terraform plan
❯ terraform plan
Changes to Outputs:
+ iam = jsonencode(
{
+ Statement = [
+ {
+ "id/4ECE95AF53127CE866BA:aud" = "sts.amazon.com"
+ "id/4ECE95AF53127CE866BA:sub" = "system:serviceaccount:kube-system:ebs-csi-controller-sa"
},
+ {
+ "id/9173553CA62864:aud" = "sts.amazon.com"
+ "id/9173553CA62864:sub" = "system:serviceaccount:kube-system:ebs-csi-controller-sa"
},
]
}
)
You seem to have encountered the problem that is warned about in Generating JSON or YAML from a template:
I would suggest abandoning your attempts to construct JSON by string concatenation and instead following the advice in that section of using Terraform's
jsonencode
function, which guarantees that the result will always be valid JSON without you having to worry about pesky details like trailing commas.The template you included in your question is not a complete and valid IAM policy, so I can't show a complete and valid example, but here's a template which should generate a result similar to the subset you showed in your example, and hopefully from here you can see how to extend it to produce a fully-specified IAM policy document:
This works by constructing a value using normal Terraform expressions and then encoding that value using
jsonencode
. Thejsonencode
function knows how to insert commas correctly between object properties and array elements, and so the result should be valid as long as the value you've described has the same structure as a valid IAM policy document.For AWS IAM policy documents in particular, there's also a higher-level alternative in the form of the
aws_iam_policy_document
data source. This performs a similar job of performing the JSON encoding for you automatically, but it also has awareness of the IAM policy document schema and so it can also guarantee to produce a valid IAM policy document structure or return an error explaining why your given arguments are unsuitable for that purpose.