在 Terraform v1.0 中连接列表和资源输出
Concatenate a list and resource output in 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
块,但我想看看是否可以只使用一个。
您已达到 Terraform 的限制:
Limitations on values used in for_each
The keys of the map (or all the values in the case of a set of strings) must be known values, or you will get an error message that for_each has dependencies that cannot be determined before apply, and a -target may be needed.
表达式具有相同的限制:
The for_each meta-argument accepts map or set expressions. However, unlike most arguments, the for_each value must be known before Terraform performs any remote resource actions. This means for_each can't refer to any resource attributes that aren't known until after a configuration is applied (such as a unique ID generated by the remote API when an object is created).
如前所述,您不能使用 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]
}
在这种情况下使用 for_each
需要区分您在 Terraform 配置中给这些对象的标签和远程系统分配给它们的 labels/ids,因为远程系统的标识符会随着时间的推移而改变,并且通常在应用之后才知道,但是 Terraform 需要这些密钥在这些实例的整个生命周期中保持一致,包括在最初创建它们的计划阶段。
具体说明这种情况,这意味着这些策略 ARN 中的每一个都应该有一个直接在 Terraform 配置中决定的逻辑名称,它与 AWS API 决定的 ARN 分开你.
local.default_iam_policy
值 是在配置中静态定义的 ,因此从技术上讲,这些区别并不需要,但由于我们将把它与动态生成的 ARN 对两者应用相同的约定会更容易,因此我首先将本地值调整为一个映射,其中键将是这些策略的本地标识符:
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 和远程 ID 之间的拆分中实际上没有任何特殊的细微差别需要捕捉,因此我在这里保持简单并建立了一个约定,即本地名称是 name
的政策,这也是我们可以从“自定义”政策中系统地推导出来的东西:
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
值也可能“在应用后已知”,在这种情况下我们会需要不同的策略来为每个实例分配静态密钥。
所有这一切的结果是您的 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"]
- 以此类推,无论您的自定义策略有什么名称
我有以下本地列表:
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
块,但我想看看是否可以只使用一个。
您已达到 Terraform 的限制:
Limitations on values used in for_each
The keys of the map (or all the values in the case of a set of strings) must be known values, or you will get an error message that for_each has dependencies that cannot be determined before apply, and a -target may be needed.
表达式具有相同的限制:
The for_each meta-argument accepts map or set expressions. However, unlike most arguments, the for_each value must be known before Terraform performs any remote resource actions. This means for_each can't refer to any resource attributes that aren't known until after a configuration is applied (such as a unique ID generated by the remote API when an object is created).
如前所述,您不能使用 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]
}
在这种情况下使用 for_each
需要区分您在 Terraform 配置中给这些对象的标签和远程系统分配给它们的 labels/ids,因为远程系统的标识符会随着时间的推移而改变,并且通常在应用之后才知道,但是 Terraform 需要这些密钥在这些实例的整个生命周期中保持一致,包括在最初创建它们的计划阶段。
具体说明这种情况,这意味着这些策略 ARN 中的每一个都应该有一个直接在 Terraform 配置中决定的逻辑名称,它与 AWS API 决定的 ARN 分开你.
local.default_iam_policy
值 是在配置中静态定义的 ,因此从技术上讲,这些区别并不需要,但由于我们将把它与动态生成的 ARN 对两者应用相同的约定会更容易,因此我首先将本地值调整为一个映射,其中键将是这些策略的本地标识符:
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 和远程 ID 之间的拆分中实际上没有任何特殊的细微差别需要捕捉,因此我在这里保持简单并建立了一个约定,即本地名称是 name
的政策,这也是我们可以从“自定义”政策中系统地推导出来的东西:
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
值也可能“在应用后已知”,在这种情况下我们会需要不同的策略来为每个实例分配静态密钥。
所有这一切的结果是您的 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"]
- 以此类推,无论您的自定义策略有什么名称