Terraform部署Azure WAF自定义规则遇ApplicationGatewayFirewallMatchValueNoCollection错误
部署Azure WAF自定义规则时遇到400错误:
Application Gateway Web Application Firewall Policy Name: "waf-policy-prod-uksouth"): unexpected status 400 (400 Bad Request) with error: ApplicationGatewayFirewallMatchValueNoCollection: Custom Rule 'AllowAmexPay' does not have a valid collection match variable 'RequestUri' which support selector in its condition in context 'properties.customRules[2].matchConditions[0].matchVariables[0]'.
with azurerm_web_application_firewall_policy.waf_policy,
on application_gw.tf line 224, in resource "azurerm_web_application_firewall_policy" "waf_policy":
224: resource "azurerm_web_application_firewall_policy" "waf_policy" {
相关配置文件如下:
TFVars文件
custom_rules = [ { name = "RecitePreferences" priority = "70" enabled = true rule_type = "MatchRule" variable_name = "RequestCookies" selector = "Recite.Preferences" operator = "Any" action = "Allow" }, { name = "CookieConsent" priority = "71" enabled = true rule_type = "MatchRule" variable_name = "RequestCookies" selector = "CookieConsent" operator = "Any" action = "Allow" }, { name = "AllowAmexPay" priority = "80" enabled = true rule_type = "MatchRule" variable_name = "RequestUri" selector = "/smart-card/amex-pay" operator = "Contains" action = "Allow" }, { name = "AllowAmexPayComplete" priority = "81" enabled = true rule_type = "MatchRule" variable_name = "RequestUri" selector = "/smart-card/amex-pay-complete" operator = "Contains" action = "Allow" } ]
Variables.tf文件
variable "custom_rules" { type = list(object({ name = string priority = string enabled = bool rule_type = string variable_name = string operator = string selector = string action = string })) }
Application Gateway配置
resource "azurerm_web_application_firewall_policy" "waf_policy" { name = "waf-policy-${var.general_environment}-${var.general_location}" resource_group_name = azurerm_resource_group.prod.name location = azurerm_resource_group.prod.location policy_settings { enabled = true mode = "Detection" request_body_check = false file_upload_limit_in_mb = 100 max_request_body_size_in_kb = 128 } managed_rules { managed_rule_set { type = "OWASP" version = "3.2" dynamic "rule_group_override" { for_each = var.rule_group_override content { rule_group_name = rule_group_override.key dynamic "rule" { for_each = rule_group_override.value content { id = rule.value.id enabled = rule.value.enabled } } } } } dynamic "exclusion" { for_each = var.exclusion content { match_variable = exclusion.value["match_variable"] selector = exclusion.value["selector"] selector_match_operator = exclusion.value["selector_match_operator"] } } managed_rule_set { type = "Microsoft_BotManagerRuleSet" version = "1.0" } } dynamic "custom_rules" { for_each = var.custom_rules content { name = custom_rules.value["name"] enabled = custom_rules.value["enabled"] priority = custom_rules.value["priority"] rule_type = custom_rules.value["rule_type"] action = custom_rules.value["action"] match_conditions { operator = custom_rules.value["operator"] match_variables { variable_name = custom_rules.value["variable_name"] selector = custom_rules.value["selector"] } } } } }
疑问:是否有更优的变量传递方式来解决该部署错误?
错误根源
Azure WAF的RequestUri属于单值匹配变量,这类变量不支持使用selector(selector仅适用于集合类变量,比如RequestCookies、RequestHeaders,用来指定集合中的具体项)。当前配置强制所有规则都传递selector,导致RequestUri规则触发API校验错误。
优化后的变量传递与配置调整
1. 修改Variables.tf:让selector可选,新增match_values字段
调整变量结构,兼容集合类和单值类规则的不同配置需求:
variable "custom_rules" { type = list(object({ name = string priority = string enabled = bool rule_type = string variable_name = string operator = string action = string # selector仅用于集合类变量,设为可选 selector = optional(string) # match_values用于单值变量,设为可选列表 match_values = optional(list(string)) })) }
2. 修改TFVars文件:调整RequestUri规则的配置
把RequestUri规则的selector替换为match_values:
custom_rules = [ { name = "RecitePreferences" priority = "70" enabled = true rule_type = "MatchRule" variable_name = "RequestCookies" selector = "Recite.Preferences" operator = "Any" action = "Allow" }, { name = "CookieConsent" priority = "71" enabled = true rule_type = "MatchRule" variable_name = "RequestCookies" selector = "CookieConsent" operator = "Any" action = "Allow" }, { name = "AllowAmexPay" priority = "80" enabled = true rule_type = "MatchRule" variable_name = "RequestUri" match_values = ["/smart-card/amex-pay"] operator = "Contains" action = "Allow" }, { name = "AllowAmexPayComplete" priority = "81" enabled = true rule_type = "MatchRule" variable_name = "RequestUri" match_values = ["/smart-card/amex-pay-complete"] operator = "Contains" action = "Allow" } ]
3. 修改Application Gateway配置:动态匹配变量类型
在dynamic custom_rules块中,根据变量类型决定是否输出selector或match_values:
resource "azurerm_web_application_firewall_policy" "waf_policy" { # 保留原有基础配置... dynamic "custom_rules" { for_each = var.custom_rules content { name = custom_rules.value["name"] enabled = custom_rules.value["enabled"] priority = custom_rules.value["priority"] rule_type = custom_rules.value["rule_type"] action = custom_rules.value["action"] match_conditions { operator = custom_rules.value["operator"] # 动态生成match_variables dynamic "match_variables" { for_each = [custom_rules.value] content { variable_name = match_variables.value["variable_name"] # 仅当selector存在时输出 if match_variables.value["selector"] != null { selector = match_variables.value["selector"] } } } # 仅当match_values存在时输出 if custom_rules.value["match_values"] != null { match_values = custom_rules.value["match_values"] } } } } }
关键说明
- 集合类变量(如RequestCookies):使用
selector指定要匹配的集合项,配合operator = "Any"或"Equals"等使用。 - 单值类变量(如RequestUri、RequestMethod):使用
match_values指定匹配值,配合operator = "Contains"、"Equals"等使用。 - 调整后的变量结构更灵活,既能兼容原有集合类规则,也能正确配置单值类规则,避免触发Azure WAF的API校验错误。
内容的提问来源于stack exchange,提问作者Matty

