【问题标题】:Concatenate a list and resource output in Terraform v1.0在 Terraform v1.0 中连接列表和资源输出
【发布时间】:2021-10-26 22:36:29
【问题描述】:

我有以下本地列表:

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 块,但我想看看是否可以只使用一个。

【问题讨论】:

    标签: amazon-web-services terraform terraform-provider-aws terraform0.12+


    【解决方案1】:

    如前所述,您不能使用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]
    }
    
    

    【讨论】:

      【解决方案2】:

      你已经达到了 Terraform 的限制:

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

      for_each 中使用的值的限制

      map 的键(或一组字符串情况下的所有值)必须是已知值,否则会收到错误消息 for_each 具有在 apply 之前无法确定的依赖项,并且 -target 可能需要。

      表达式也有同样的限制:

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

      【讨论】:

        【解决方案3】:

        在这种情况下使用for_each 需要区分您在 Terraform 配置中为这些对象提供的标签和远程系统分配给它们的标签/ID,因为远程系统的标识符会随着时间而改变并且通常在应用之后才知道,但 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"]
        • 等等,无论您的自定义策略有什么名称

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-09-22
          • 2020-12-16
          • 2021-09-24
          • 1970-01-01
          • 1970-01-01
          • 2019-02-02
          • 2019-07-23
          • 2022-06-22
          相关资源
          最近更新 更多