【问题标题】:Can you have a variable as a block definition name?您可以将变量作为块定义名称吗?
【发布时间】:2021-07-22 22:19:54
【问题描述】:

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

这里需要一个参数或块定义。要设置参数,请使用等号“=”来引入参数值。

我猜这是因为它看到引号中的变量并期望 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"
            }

【问题讨论】:

    标签: amazon-web-services terraform web-application-firewall


    【解决方案1】:

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

    您的目标似乎是根据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 块所期望的相当,但我们可以使用the splat operator[*] 轻松地将可能为空的值调整为包含零或一个元素的列表。例如,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 看到所有可能的结果都将符合资源类型的声明的架构。

    【讨论】:

    • 非常感谢@MartinAtkins 提供如此详细的回复。这说得通。但是,我尝试过对其进行测试,但它显示了一个错误:“每个”对象只能在“资源”块中使用,并且只有在设置了“for_each”参数时才能使用。我有点困惑,因为我们已经在动态块中设置了 for_each。我们现在仍在使用旧版本的 terraform,12.7,我不确定这是否与它有任何关系。我会继续尝试调试问题。
    • 很抱歉...我在写这篇文章时出错了。我倾向于在一个会话中回答一堆问题,所以有时我大脑中的东西会从一个答案潜入另一个答案。请注意,我已将此处的 each.value 替换为 single_header.valuesingle_query_argument.value,这与动态块的默认迭代器符号(以块类型命名)相匹配。
    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 2021-06-01
      • 1970-01-01
      • 2011-11-30
      • 2017-02-27
      • 1970-01-01
      • 2014-03-20
      • 1970-01-01
      • 1970-01-01
      • 2017-08-28
      相关资源
      最近更新 更多