Terraform 0.12嵌套循环

Vig*_*ash 4 nested-loops terraform

我正在尝试使用Terraform 0.12的新功能来实现嵌套循环,以便遍历AWS IAM用户,每个用户都可以附加一个或多个策略。用于表示此列表的变量的类型为map(list(string)),看起来像这样:

{
  "user 1" = [ "policy1", "policy2" ],
  "user 2" = [ "policy1" ]
}
Run Code Online (Sandbox Code Playgroud)

通过可以轻松地创建用户列表keys(),但是由于Terraform当前没有嵌套循环资源创建的机制,因此策略附件必须以独立于每个用户的单个循环的形式发生。因此,我正在尝试从地图输入中构建一个user:policy关联列表,该列表看起来像基于上面的示例:

[
  [ "user1", "policy1" ],
  [ "user1", "policy2" ],
  [ "user2", "policy1" ]
]
Run Code Online (Sandbox Code Playgroud)

我正在尝试构造该列表并将其存储在本地变量中,如下所示,var.iam-user-policy-map输入映射在哪里:

locals {
  ...
  association-list = [
    for user in keys(var.iam-user-policy-map):
    [
      for policy in var.iam-user-policy-map[user]:
      [user, policy]
    ]
  ]
  ...
}
Run Code Online (Sandbox Code Playgroud)

但是,尝试访问该嵌套列表中的值时出现错误。我正在尝试使用引用local.association-list[count.index][0]和策略访问关联的用户部分local.association-list[count.index][1],但是在运行时terraform plan会出错:

Error: Incorrect attribute value type

  on main.tf line 27, in resource "aws_iam_user_policy_attachment" "test-attach":
  27:   user = local.association-list[count.index][0]

Inappropriate value for attribute "user": string required.


Error: Incorrect attribute value type

  on main.tf line 27, in resource "aws_iam_user_policy_attachment" "test-attach":
  27:   user = local.association-list[count.index][0]

Inappropriate value for attribute "user": string required.


Error: Invalid index

  on main.tf line 28, in resource "aws_iam_user_policy_attachment" "test-attach":
  28:   policy_arn = "arn:aws-us-gov:iam::aws:policy/${local.association-list[count.index][1]}"
    |----------------
    | count.index is 0
    | local.association-list is tuple with 2 elements

The given key does not identify an element in this collection value.


Error: Invalid template interpolation value

  on main.tf line 28, in resource "aws_iam_user_policy_attachment" "test-attach":
  28:   policy_arn = "arn:aws-us-gov:iam::aws:policy/${local.association-list[count.index][1]}"
    |----------------
    | count.index is 1
    | local.association-list is tuple with 2 elements

Cannot include the given value in a string template: string required.
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?

小智 12

如果您需要“for_each”的地图,“merge”会很方便。

variable "iam-user-policy-map" {
  default = {
    "user 1" = ["policy1", "policy2"],
    "user 2" = ["policy1"]
  }
}

locals {
  association-map = merge([
    for user, policies in var.iam-user-policy-map : {
      for policy in policies :
        "${user}-${policy}" => {
          "user"   = user
          "policy" = policy
        }
    }
  ]...)
}

output "association-map" {
  value = local.association-map
}
Run Code Online (Sandbox Code Playgroud)

输出:

association-map = {
  "user 1-policy1" = {
    "policy" = "policy1"
    "user" = "user 1"
  }
  "user 1-policy2" = {
    "policy" = "policy2"
    "user" = "user 1"
  }
  "user 2-policy1" = {
    "policy" = "policy1"
    "user" = "user 2"
  }
}
Run Code Online (Sandbox Code Playgroud)

for_each 用法示例:

resource "null_resource" "echo" {
  for_each = local.association-map
  provisioner "local-exec" {
    command = "echo 'policy - ${each.value.policy}, user - ${each.value.user}'"
  }
}
Run Code Online (Sandbox Code Playgroud)

https://github.com/hashicorp/terraform/issues/22263#issuecomment-969549347


Mar*_*ins 8

for您的本地值中的表达式将association-list生成一个字符串列表列表,但是您对其的引用将其视为字符串列表列表。

为了得到你想要的展平表示,你可以使用flatten功能,而是因为它本来一切团成一个单一的平面列表我建议你做最里面的值的对象,而不是。(这还将使对它的引用更清晰。)

locals {
  association-list = flatten([
    for user in keys(var.iam-user-policy-map) : [
      for policy in var.iam-user-policy-map[user] : {
        user   = user
        policy = policy
      }
    ]
  ])
}
Run Code Online (Sandbox Code Playgroud)

该表达式的结果将具有以下形状:

[
  { user = "user1", policy = "policy1" },
  { user = "user1", policy = "policy2" },
  { user = "user2", policy = "policy2" },
]
Run Code Online (Sandbox Code Playgroud)

您对它的引用可以采用以下格式:

user = local.association-list[count.index].user
Run Code Online (Sandbox Code Playgroud)
policy_arn = "arn:aws-us-gov:iam::aws:policy/${local.association-list[count.index].policy}"
Run Code Online (Sandbox Code Playgroud)

  • 这里还有另一个问题,即数字引用的元素会受到列表中项目更改的影响。如果您有多个策略附件并且更改了其中之一,terraform 将显示您未更改的其他策略附件的更改,因为它对列表进行了重新排序。在模块中使用 for_each 将导致关键引用元素,例如 module.iam-policy-attachments.aws_iam_role_policy_attachment.role_policy["policy_name"] 而不是 module.iam-policy-attachments.aws_iam_role_policy_attachment.role_policy[1],因此单个策略更改不会影响其他人 (2认同)