连接Terraform v1.0中的列表和资源输出



我有以下本地列表:

locals {
default_iam_policies = [
"arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy",
"arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore",
"arn:aws:iam::aws:policy/AWSDeviceFarmFullAccess"   
]
}

我计划使用以下命令将这些策略与自定义策略一起附加到角色:

resource "aws_iam_role_policy_attachment" "default-policy-attachment" {
for_each = toset(concat(
local.default_iam_policies,
[aws_iam_policy.custom-policy.arn]
))
role       = aws_iam_role.this.name
policy_arn = each.value
}

但是我得到这个错误信息:

│ Error: Invalid for_each argument
│
│   on main.tf line 113, in resource "aws_iam_role_policy_attachment" "default-policy-attachment":
│  113:   for_each = toset(concat(
│  114:     local.default_iam_policies,
│  115:     [aws_iam_policy.custom-policy.arn]
│  116:     ))
│     ├────────────────
│     │ aws_iam_policy.custom-policy.arn is a string, known only after apply
│     │ local.default_iam_policies is tuple with 3 elements
│
│ The "for_each" value depends on resource attributes that cannot be determined until apply, so Terraform cannot predict how many instances will be created.
│ To work around this, use the -target argument to first apply only the resources that the for_each depends on.

我想我可以把它分成两个aws_iam_role_policy_attachment块,但我想看看是否有可能只用一个。

如前所述,您不能使用for_each。但是在的情况下你可以使用count:


locals {
default_iam_policies = [
"arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy",
"arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore",
"arn:aws:iam::aws:policy/AWSDeviceFarmFullAccess"   
]

full_list = concat(local.default_iam_policies,[aws_iam_policy.this.arn])
}

resource "aws_iam_role_policy_attachment" "default-policy-attachment" {
count      = length(local.full_list)
role       = aws_iam_role.this.name
policy_arn = local.full_list[count.index]
}

您已经达到了Terraform的限制:

https://www.terraform.io/docs/language/meta-arguments/for_each.html limitations-on-values-used-in-for_each

for_each中使用值的限制

map的键(或字符串集合中的所有值)必须是已知的值,否则您将得到for_each有依赖关系的错误消息,在应用之前无法确定,并且可能需要-target。

表达式有相同的限制:

for_each元参数接受map或set表达式。然而,与大多数参数不同的是,for_each值必须在Terraform执行任何远程资源操作之前已知。这意味着for_each不能引用任何在应用配置之后才知道的资源属性(例如创建对象时远程API生成的唯一ID)。

在这种情况下使用for_each需要区分您在Terraform配置中给这些对象的标签和远程系统分配给它们的标签/id,因为远程系统的标识符可以随着时间的推移而改变,并且通常在应用之后才知道,但是Terraform需要这些键在这些实例的整个生命周期中保持一致,包括在最初创建它们的计划阶段。

对于这种情况,这意味着每个策略ARN都应该有一个直接在Terraform配置中决定的逻辑名称,这与AWS API为您决定的ARN是分开的。

local.default_iam_policy在配置中是静态定义的,所以从技术上讲,这些区别是不需要的,但是由于我们将与动态生成的ARNs相结合,因此更容易将相同的约定应用于两者,因此我将首先调整本地值为映射,其中键将是这些策略的本地标识符:

locals {
default_iam_policies = tomap({
CloudWatchAgentServerPolicy  = "arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy",
AmazonSSMManagedInstanceCore = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore",
AWSDeviceFarmFullAccess      = "arn:aws:iam::aws:policy/AWSDeviceFarmFullAccess"
})
}

由于您的原始示例表明,在本地和远程id之间的分裂中,这里没有真正需要捕获的任何特殊细微差别,因此我在这里保持简单,并建立了一个约定,即本地名称是策略的name,这是我们可以系统地从"custom"导出的东西;的:

resource "aws_iam_role_policy_attachment" "default-policy-attachment" {
for_each = merge(
local.default_iam_policies,
{ for p in aws_iam_policy.custom-policy.arn : p.name => p.arn },
)
role       = aws_iam_role.this.name
policy_arn = each.value
}
以上假设您的resource "aws_iam_policy" "custom-policy"块将静态name值分配给每个策略,以便在规划时Terraform将知道这些。这通常是正确的,但如果您正在派生一组"自定义策略"从其他一些动态源,那么原则上name的值也可能在apply之后是已知的,在这种情况下,我们需要一种不同的策略来为每个实例分配一个静态键。

所有这些的结果是,您的resource "aws_iam_role_policy_attachment" "default-policy-attachment"块将声明实例的键以策略名称命名:

  • aws_iam_role_policy_attachment.default-policy-attachment["CloudWatchAgentServerPolicy"]
  • aws_iam_role_policy_attachment.default-policy-attachment["AmazonSSMManagedInstanceCore"]
  • aws_iam_role_policy_attachment.default-policy-attachment["AWSDeviceFarmFullAccess"]
  • 等等,无论您的自定义策略有什么名称

最新更新