terraform 模板 if 条件向 iam 语句添加逗号

问题描述 投票:0回答:2
❯ 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"
                },
            ]
        }
    )
terraform amazon-iam hcl terraform-template-file
2个回答
0
投票

错误在包含意外语法的

%{ 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 个元素,这将是原始列表的最后一个元素。


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 策略文档,还有一种以

aws_iam_policy_document
数据源形式存在的更高级别替代方案。这会自动为您执行 JSON 编码的类似工作,但它也了解 IAM 策略文档架构,因此它还可以保证生成有效的 IAM 策略文档结构或返回错误,解释为什么给定参数不合适为了这个目的。

© www.soinside.com 2019 - 2024. All rights reserved.