您可以将变量作为块定义名称吗?

Can you have a variable as a block definition name?

我正在尝试添加一个 AWS WAF 规则,该规则从变量中获取值并将其作为块定义添加到资源中。我不确定我正在尝试的是否可行,我收到错误消息:

An argument or block definition is required here. To set an argument, use the equals sign "=" to introduce the argument value.

我猜这是因为它看到引号中的变量并期望 ito 有参数。

下面有问题的块是“field_to_match”块。

有什么方法可以做到这一点或有其他选择吗?

resource "aws_wafv2_web_acl" "static_hosting" {
  provider    = aws.acm_us_region

  name        = "${var.cityName}-static-hosting"
  description = "WAF for ${var.cityName}-static-hosting"
  scope       = "CLOUDFRONT"

  default_action {
    block {}
  }

  rule {
    name     = "Check_Domain"
    priority = 1

    action {
      allow {}
    }

    statement {
      byte_match_statement {
        text_transformation {
            priority = 0
            type = "NONE"
        }
        field_to_match {
            var.serviceConfig.static_hosting.conditionalType.type {
                name = var.serviceConfig.static_hosting.conditionalType.name
            }

        }
        positional_constraint = var.serviceConfig.static_hosting.conditionalType.conditional
        search_string = var.serviceConfig.static_hosting.conditionalType.string
      }
    }
}

"conditionalType": {
                "type": "single_header",
                "name": "referrer",
                "conditional": "CONTAINS",
                "string": "domain.com"
            }

资源配置中的参数和块在 Terraform 中不能以这种方式动态,因为它们在验证时静态检查,而不是在 plan/apply 期间动态检查。

您的目标似乎是根据 var.serviceConfig.static_hosting.conditionalType.type 的值动态选择要在 byte_match_statement 中使用的几种不同可能块类型中的哪一种。由于这种资源类型的设计,这不是一件容易写的事情,但是 可以通过使用几种不同的表达式和一些 dynamic blocks 来实现它].

我将从这里开始,首先生成一些更直接符合 dynamic 块预期的值,我们有一个集合来迭代每个块而不是单个名称查找。例如:

locals {
  query_type = var.serviceConfig.static_hosting.conditionalType.type

  all_query_arguments = local.query_type == "all_query_arguments" ? {} : null
  body                = local.query_type == "body" ? {} : null
  method              = local.query_type == "method" ? {} : null
  query_string        = local.query_type == "query_string" ? {} : null
  uri_path            = local.query_type == "uri_path" ? {} : null

  single_header = local.query_type == "single_header" ? {
    name = var.serviceConfig.static_hosting.conditionalType.name
  } : null

  single_query_argument = local.query_type == "single_query_argument" ? {
    name = var.serviceConfig.static_hosting.conditionalType.name
  } : null
}

我们在这里取得的成就是为每种可能的查询类型设置了一个单独的符号,在任何时候都只会设置其中一种,而其他的都是 null。这不是 相当 dynamic 块所期望的,但我们可以使用 [=25 轻松地将可能为 null 的值调整为具有零个或一个元素的列表=]、[*]。例如,local.body[*] 要么是空列表,要么是包含单个元素的列表,具体取决于 local.body 是否为 null.

然后这为我们提供了编写 dynamic 块所需的输入,这些块将产生零种或一种允许的块类型,这意味着实际上只有一个总数,因为我们'上面已经安排了一次只能有一个非null

  field_to_match {
    dynamic "all_query_arguments" {
      for_each = local.all_query_arguments[*]
      content {}
    }
    dynamic "body" {
      for_each = local.body[*]
      content {}
    }
    dynamic "method" {
      for_each = local.method[*]
      content {}
    }
    dynamic "query_string" {
      for_each = local.query_string[*]
      content {}
    }
    dynamic "uri_path" {
      for_each = local.uri_path[*]
      content {}
    }
    dynamic "single_header" {
      for_each = local.uri_single_header[*]
      content {
        name = single_header.value.name
      }
    }
    dynamic "single_query_argument" {
      for_each = local.single_query_argument[*]
      content {
        name = single_query_argument.value.name
      }
    }
  }

这种具有多种不同块类型的设计,您可以从中选择任何一种来设置值,这对于 Terraform 资源类型来说是一种不寻常的设计,因此不幸的是 动态地使用它 与等效的静态配置相比,这样的配置相当复杂,但仍然可以使用这样的策略使其动态化,尽管为了让 Terraform 看到所有可能的结果会相当冗长符合资源类型的声明架构。

如果有人遇到类似问题,请快速更新。 Martins 的回答很好,我只需要调整一件事(在更高版本的 terraform 上可能不是问题)。在动态内容块中,我没有使用 each.value.name,而是使用了动态块名称:single_header.value.namesingle_query_argument.value.name.