如何在terraform中为tpl文件传递复杂的vars



我正在尝试创建一个tpl文件。所以我可以赋予我的角色,访问多个k8s集群。但是我得到了一个元组错误。

当tpl文件有一些插值时,我们应该如何将vars传递给它?还请让我知道这个错误是什么意思以及我错在哪里。

Terraform版本:0.12.28

locals.tf

federated = [
"xxxxxxxxxxxxxxxx",
"yyyyyyyyyyyyyyyy"
]
federatedList1 = [for oidc in local.federated : "arn:aws:iam::11111111111:oidc-provider/oidc.eks.us-east-1.amazonaws.com/id/${oidc}"]
federatedList2 = join("", [for oidc in local.federated : ""oidc.eks.us-east-1.amazonaws.com/id/${oidc}:sub:", "system:serviceaccount:%s:%s""])

eks_assume_policy.json.tpl

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "${federatedList1}"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"${federatedList2}"
}
}
}
]
}

IAM角色

resource "aws_iam_role" "route53_role" {
name = "xxxxx"
assume_role_policy = format(templatefile("./eks_assume_policy.json.tpl", {
federatedList1 = [for oidc in local.federated : "arn:aws:iam::1111111111:oidc-provider/oidc.eks.us-east-1.amazonaws.com/id/${oidc}"]
federatedList2 = join("", [for oidc in local.federated : ""oidc.eks.us-east-1.amazonaws.com/id/${oidc}:sub:", "system:serviceaccount:%s:%s""])
}), "namespace", local.name)
tags = {
terraform = "true"
owner     = "test"
}
}

错误:函数调用出错

on main.tf line 49, in resource "aws_iam_role" "route_53_role":
49:   assume_role_policy = format(templatefile("./eks_assume_policy.json.tpl", {
50:
51:
52:
|----------------
| local.federated is tuple with 2 elements
Call to function "templatefile" failed: ./eks_assume_policy.json.tpl:7,25-39:
Invalid template interpolation value; Cannot include the given value in a
string template: string required..

更新1:

我正在尝试eks_assume_policy.json.tpl访问两个集群

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": [
"arn:aws:iam::111111111:oidc-provider/oidc.eks.us-east-1.amazonaws.com/id/xxxxxxxxxxxx",
"arn:aws:iam::111111111:oidc-provider/oidc.eks.us-east-1.amazonaws.com/id/yyyyyyyyyyy"
]
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"oidc.eks.us-east-1.amazonaws.com/id/xxxxxxxxxxxx:sub": "system:serviceaccount:%s:%s",
"oidc.eks.us-east-1.amazonaws.com/id/yyyyyyyyy:sub": "system:serviceaccount:%s:%s"
}
}
}
]
}

通常,用于解决此问题的模式是通过jsonencode。在这种情况下,模板文件将是:

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": ${jsonencode(federatedList1)}
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": 
${jsonencode(federatedList2)}
}
}
]
}

federatedList1现在应该是正确的。我不确定您试图用federatedList2实现什么,因此对federatedList2的修改可能需要更多的修改。

templatefile文档中有一节专门介绍了这种情况,标题为"从模板生成JSON或YAML",开头是:

如果您想要生成的字符串是JSON或YAML语法,那么编写一个模板来生成有效的JSON或YAML通常是棘手而乏味的,当使用大量单独的插值序列和指令时,该模板将被正确解释。

相反,您可以编写一个模板,该模板仅由对jsonencodeyamlencode的单个插值调用组成,指定要使用普通Terraform表达式语法进行编码的值。

文档接着给出了一些模板的简单示例,该模板的整个内容都是对jsonencodeyamldecode的调用,但由于您在这里给出了一个特定的模板作为示例,我可以显示将模板转换为文档建议的形式的结果:

${jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Principal = {
Federated = federatedList1
}
Action = "sts:AssumeRoleWithWebIdentity"
Condition = {
StringEquals = federatedList2
}
},
]
})}

请注意,在本例中,整个模板是单个插值序列${ ... },其结果将是作为jsonencode参数给出的Terraform表达式的JSON等价物。这意味着您可以使用所有正常的Terraform语言表达式功能,包括直接引用从主配置传入的值,Terraform将自动将结果转换为合适的JSON语法。

在这种情况下,由于federatedList1federatedList2都是由for表达式产生的元组,因此根据jsonencode函数文档中显示的类型映射表,结果将是JSON数组。

最新更新