❯ terraform version
Terraform v1.6.3
on darwin_amd64
+ provider registry.terraform.io/hashicorp/aws v5.29.0
我致力于改造 AWS IAM 信任策略,并正在模板化信任 IAM 策略,如下所示
{
"Statement": [
%{ for oidc in oidcs ~}
{
"${oidc}:aud": "sts.amazon.com",
"${oidc}:sub": "system:serviceaccount:${sa}"
},
%{ endfor ~}
]
}
我将此模板与 terraform 模板函数一起使用,如下所示
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
}
唯一的事情是我试图找出如何删除循环结束之前的逗号(如果它是列表中的最后一项),否则它不是可以添加到 AWS IAM 的有效策略。
我尝试添加以下 if 语句
{
"Statement": [
%{ for oidc in oidcs ~}
{
"${oidc}:aud": "sts.amazon.com",
"${oidc}:sub": "system:serviceaccount:${sa}"
} %{ "," if not loop.last ~}
%{ endfor ~}
]
}
但这样做我得到一个错误说
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..
还尝试了以下方法
{
"Statement": [
%{ for oidc in oidcs ~}
{
"${oidc}:aud": "sts.amazon.com",
"${oidc}:sub": "system:serviceaccount:${sa}"
}%{ if not loop.last ~}
,
%{ endif ~}
%{ endfor ~}
]
}
给我错误
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 我已尝试按照您的建议进行操作,已完全复制并粘贴,但仍然得到最后的逗号
下面是地形计划的输出
❯ 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"
},
]
}
)
错误在包含意外语法的
%{ if not loop.last ~}
上抛出,并且它确实在各种方面在语法上无效。最初的目标是如果迭代当前不是列表的最终元素,则渲染 ,
。我们可以通过以下方式实现这一点:
%{ if oidc != oidcs[length(oidcs) - 1]},%{ endif }
本质上,该算法检查当前 lambda 作用域变量
oidc
是否等于 oidcs
的最终元素,如果不等于,则渲染 ,
。 oidcs[length(oidcs) - 1]
相当于另一种语言中的函数或方法,它解析列表/集合/数组等类型集合的最终元素,因为它返回最终元素的值(最终元素是列表的长度减去顺序从 0 开始加 1)。
请注意,人们还可以:
%{ if oidc != reverse(oidcs[0])},%{ endif }
因为这会反转列表,然后返回第 0 个元素,这将是原始列表的最后一个元素。
您似乎遇到了从模板生成 JSON 或 YAML中警告的问题:
如果您要生成的字符串采用 JSON 或 YAML 语法,则编写一个模板来生成有效的 JSON 或 YAML 通常会很棘手且乏味,而在使用大量单独的插值序列和指令时,这些 JSON 或 YAML 会被正确解释。
相反,您可以[...]
我建议放弃通过字符串连接构造 JSON 的尝试,而是遵循使用 Terraform 的
jsonencode
函数部分中的建议,这可以保证结果始终是有效的 JSON,而无需担心尾随逗号等烦人的细节.
您在问题中包含的模板不是完整且有效的 IAM 策略,因此我无法显示完整且有效的示例,但这里有一个模板,它应该生成与您在示例中显示的子集类似的结果,并希望从这里您可以看到如何扩展它以生成完整指定的 IAM 策略文档:
${jsonencode({
Statement = [
for oidc in oidcs : {
"${oidc}:aud" = "sts.amazon.com"
"${oidc}:sub" = "system:serviceaccount:${sa}"
}
]
})}
这是通过使用普通 Terraform 表达式构造一个值,然后使用
jsonencode
对该值进行编码来实现的。 jsonencode
函数知道如何在对象属性和数组元素之间正确插入逗号,因此只要您描述的值与有效的 IAM 策略文档具有相同的结构,结果就应该有效。
aws_iam_policy_document
数据源形式存在的更高级别替代方案。这会自动为您执行 JSON 编码的类似工作,但它也了解 IAM 策略文档架构,因此它还可以保证生成有效的 IAM 策略文档结构或返回错误,解释为什么给定参数不合适为了这个目的。