diff --git a/azurerm/internal/services/frontdoor/resource_arm_front_door_firewall_policy.go b/azurerm/internal/services/frontdoor/resource_arm_front_door_firewall_policy.go index bce0af2546598..0ee9e23845595 100644 --- a/azurerm/internal/services/frontdoor/resource_arm_front_door_firewall_policy.go +++ b/azurerm/internal/services/frontdoor/resource_arm_front_door_firewall_policy.go @@ -248,6 +248,42 @@ func resourceArmFrontDoorFirewallPolicy() *schema.Resource { ValidateFunc: validate.NoEmptyStrings, }, + "exclusion": { + Type: schema.TypeList, + MaxItems: 100, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "match_variable": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + string(frontdoor.QueryStringArgNames), + string(frontdoor.RequestBodyPostArgNames), + string(frontdoor.RequestCookieNames), + string(frontdoor.RequestHeaderNames), + }, false), + }, + "operator": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + string(frontdoor.Contains), + string(frontdoor.EndsWith), + string(frontdoor.Equals), + string(frontdoor.EqualsAny), + string(frontdoor.StartsWith), + }, false), + }, + "selector": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.NoEmptyStrings, + }, + }, + }, + }, + "override": { Type: schema.TypeList, MaxItems: 100, @@ -260,6 +296,42 @@ func resourceArmFrontDoorFirewallPolicy() *schema.Resource { ValidateFunc: validate.NoEmptyStrings, }, + "exclusion": { + Type: schema.TypeList, + MaxItems: 100, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "match_variable": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + string(frontdoor.QueryStringArgNames), + string(frontdoor.RequestBodyPostArgNames), + string(frontdoor.RequestCookieNames), + string(frontdoor.RequestHeaderNames), + }, false), + }, + "operator": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + string(frontdoor.Contains), + string(frontdoor.EndsWith), + string(frontdoor.Equals), + string(frontdoor.EqualsAny), + string(frontdoor.StartsWith), + }, false), + }, + "selector": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.NoEmptyStrings, + }, + }, + }, + }, + "rule": { Type: schema.TypeList, MaxItems: 1000, @@ -278,6 +350,42 @@ func resourceArmFrontDoorFirewallPolicy() *schema.Resource { Default: false, }, + "exclusion": { + Type: schema.TypeList, + MaxItems: 100, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "match_variable": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + string(frontdoor.QueryStringArgNames), + string(frontdoor.RequestBodyPostArgNames), + string(frontdoor.RequestCookieNames), + string(frontdoor.RequestHeaderNames), + }, false), + }, + "operator": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + string(frontdoor.Contains), + string(frontdoor.EndsWith), + string(frontdoor.Equals), + string(frontdoor.EqualsAny), + string(frontdoor.StartsWith), + }, false), + }, + "selector": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.NoEmptyStrings, + }, + }, + }, + }, + "action": { Type: schema.TypeString, Required: true, @@ -344,6 +452,7 @@ func resourceArmFrontDoorFirewallPolicyCreateUpdate(d *schema.ResourceData, meta customBlockResponseBody := d.Get("custom_block_response_body").(string) customRules := d.Get("custom_rule").([]interface{}) managedRules := d.Get("managed_rule").([]interface{}) + t := d.Get("tags").(map[string]interface{}) frontdoorWebApplicationFirewallPolicy := frontdoor.WebApplicationFirewallPolicy{ @@ -577,12 +686,17 @@ func expandArmFrontDoorFirewallManagedRules(input []interface{}) *frontdoor.Mana ruleType := managedRule["type"].(string) version := managedRule["version"].(string) overrides := managedRule["override"].([]interface{}) + exclusions := managedRule["exclusion"].([]interface{}) managedRuleSet := frontdoor.ManagedRuleSet{ RuleSetType: utils.String(ruleType), RuleSetVersion: utils.String(version), } + if exclusions := expandArmFrontDoorFirewallManagedRuleGroupExclusion(exclusions); exclusions != nil { + managedRuleSet.Exclusions = exclusions + } + if ruleGroupOverrides := expandArmFrontDoorFirewallManagedRuleGroupOverride(overrides); ruleGroupOverrides != nil { managedRuleSet.RuleGroupOverrides = ruleGroupOverrides } @@ -595,6 +709,31 @@ func expandArmFrontDoorFirewallManagedRules(input []interface{}) *frontdoor.Mana } } +func expandArmFrontDoorFirewallManagedRuleGroupExclusion(input []interface{}) *[]frontdoor.ManagedRuleExclusion { + if len(input) == 0 { + return nil + } + + managedRuleExclusions := make([]frontdoor.ManagedRuleExclusion, 0) + for _, v := range input { + exclusion := v.(map[string]interface{}) + + matchVariable := exclusion["match_variable"].(string) + operator := exclusion["operator"].(string) + selector := exclusion["selector"].(string) + + managedRuleExclusion := frontdoor.ManagedRuleExclusion{ + MatchVariable: frontdoor.ManagedRuleExclusionMatchVariable(matchVariable), + SelectorMatchOperator: frontdoor.ManagedRuleExclusionSelectorMatchOperator(operator), + Selector: utils.String(selector), + } + + managedRuleExclusions = append(managedRuleExclusions, managedRuleExclusion) + } + + return &managedRuleExclusions +} + func expandArmFrontDoorFirewallManagedRuleGroupOverride(input []interface{}) *[]frontdoor.ManagedRuleGroupOverride { if len(input) == 0 { return nil @@ -606,11 +745,16 @@ func expandArmFrontDoorFirewallManagedRuleGroupOverride(input []interface{}) *[] ruleGroupName := override["rule_group_name"].(string) rules := override["rule"].([]interface{}) + exclusions := override["exclusion"].([]interface{}) managedRuleGroupOverride := frontdoor.ManagedRuleGroupOverride{ RuleGroupName: utils.String(ruleGroupName), } + if exclusions := expandArmFrontDoorFirewallManagedRuleGroupExclusion(exclusions); exclusions != nil { + managedRuleGroupOverride.Exclusions = exclusions + } + if managedRuleOverride := expandArmFrontDoorFirewallRuleOverride(rules); managedRuleOverride != nil { managedRuleGroupOverride.Rules = managedRuleOverride } @@ -636,6 +780,7 @@ func expandArmFrontDoorFirewallRuleOverride(input []interface{}) *[]frontdoor.Ma } ruleId := rule["rule_id"].(string) action := rule["action"].(string) + exclusions := rule["exclusion"].([]interface{}) managedRuleOverride := frontdoor.ManagedRuleOverride{ RuleID: utils.String(ruleId), @@ -643,6 +788,10 @@ func expandArmFrontDoorFirewallRuleOverride(input []interface{}) *[]frontdoor.Ma Action: frontdoor.ActionType(action), } + if exclusions := expandArmFrontDoorFirewallManagedRuleGroupExclusion(exclusions); exclusions != nil { + managedRuleOverride.Exclusions = exclusions + } + managedRuleOverrides = append(managedRuleOverrides, managedRuleOverride) } @@ -731,6 +880,29 @@ func flattenArmFrontDoorFirewallManagedRules(input *frontdoor.ManagedRuleSetList output["override"] = flattenArmFrontDoorFirewallOverrides(v) } + if v := r.Exclusions; v != nil { + output["exclusion"] = flattenArmFrontDoorFirewallExclusions(v) + } + + results = append(results, output) + } + + return results +} + +func flattenArmFrontDoorFirewallExclusions(managedRuleExclusion *[]frontdoor.ManagedRuleExclusion) []interface{} { + if managedRuleExclusion == nil { + return make([]interface{}, 0) + } + + results := make([]interface{}, 0) + for _, o := range *managedRuleExclusion { + output := make(map[string]interface{}) + + output["match_variable"] = o.MatchVariable + output["operator"] = o.SelectorMatchOperator + output["selector"] = o.Selector + results = append(results, output) } @@ -750,6 +922,10 @@ func flattenArmFrontDoorFirewallOverrides(groupOverride *[]frontdoor.ManagedRule output["rule_group_name"] = *v } + if v := o.Exclusions; v != nil { + output["exclusion"] = flattenArmFrontDoorFirewallExclusions(v) + } + if rules := o.Rules; rules != nil { output["rule"] = flattenArmFrontdoorFirewallRules(rules) } @@ -776,6 +952,10 @@ func flattenArmFrontdoorFirewallRules(override *[]frontdoor.ManagedRuleOverride) output["rule_id"] = *v } + if v := o.Exclusions; v != nil { + output["exclusion"] = flattenArmFrontDoorFirewallExclusions(v) + } + results = append(results, output) } diff --git a/azurerm/internal/services/frontdoor/tests/resource_arm_front_door_firewall_policy_test.go b/azurerm/internal/services/frontdoor/tests/resource_arm_front_door_firewall_policy_test.go index 4ab716b994486..90fa27dfc9a7c 100644 --- a/azurerm/internal/services/frontdoor/tests/resource_arm_front_door_firewall_policy_test.go +++ b/azurerm/internal/services/frontdoor/tests/resource_arm_front_door_firewall_policy_test.go @@ -111,7 +111,10 @@ func TestAccAzureRMFrontDoorFirewallPolicy_complete(t *testing.T) { resource.TestCheckResourceAttr(data.ResourceName, "custom_rule.0.name", "Rule1"), resource.TestCheckResourceAttr(data.ResourceName, "custom_rule.1.name", "Rule2"), resource.TestCheckResourceAttr(data.ResourceName, "managed_rule.0.type", "DefaultRuleSet"), - resource.TestCheckResourceAttr(data.ResourceName, "managed_rule.1.type", "BotProtection"), + resource.TestCheckResourceAttr(data.ResourceName, "managed_rule.0.exclusion.0.match_variable", "QueryStringArgNames"), + resource.TestCheckResourceAttr(data.ResourceName, "managed_rule.0.override.1.exclusion.0.selector", "really_not_suspicious"), + resource.TestCheckResourceAttr(data.ResourceName, "managed_rule.0.override.1.rule.0.exclusion.0.selector", "innocent"), + resource.TestCheckResourceAttr(data.ResourceName, "managed_rule.1.type", "Microsoft_BotManagerRuleSet"), ), }, data.ImportStep(), @@ -276,22 +279,49 @@ resource "azurerm_frontdoor_firewall_policy" "test" { managed_rule { type = "DefaultRuleSet" - version = "preview-0.1" + version = "1.0" + + exclusion { + match_variable = "QueryStringArgNames" + operator = "Equals" + selector = "not_suspicious" + } override { rule_group_name = "PHP" rule { - rule_id = "933111" + rule_id = "933100" enabled = false action = "Block" } } - } + override { + rule_group_name = "SQLI" + + exclusion { + match_variable = "QueryStringArgNames" + operator = "Equals" + selector = "really_not_suspicious" + } + + rule { + rule_id = "942200" + action = "Block" + + exclusion { + match_variable = "QueryStringArgNames" + operator = "Equals" + selector = "innocent" + } + } + } + } + managed_rule { - type = "BotProtection" - version = "preview-0.1" + type = "Microsoft_BotManagerRuleSet" + version = "1.0" } } `, data.RandomInteger, data.Locations.Primary, inner) diff --git a/website/docs/r/front_door_firewall_policy.html.markdown b/website/docs/r/front_door_firewall_policy.html.markdown index 9d43f07028e45..ebb5e4525573e 100644 --- a/website/docs/r/front_door_firewall_policy.html.markdown +++ b/website/docs/r/front_door_firewall_policy.html.markdown @@ -44,7 +44,7 @@ resource "azurerm_frontdoor_firewall_policy" "example" { } } - custom_rules { + custom_rule { name = "Rule2" enabled = true priority = 2 @@ -72,22 +72,49 @@ resource "azurerm_frontdoor_firewall_policy" "example" { managed_rule { type = "DefaultRuleSet" - version = "preview-0.1" + version = "1.0" + + exclusion { + match_variable = "QueryStringArgNames" + operator = "Equals" + selector = "not_suspicious" + } override { rule_group_name = "PHP" rule { - rule_id = "933111" + rule_id = "933100" enabled = false action = "Block" } } + + override { + rule_group_name = "SQLI" + + exclusion { + match_variable = "QueryStringArgNames" + operator = "Equals" + selector = "really_not_suspicious" + } + + rule { + rule_id = "942200" + action = "Block" + + exclusion { + match_variable = "QueryStringArgNames" + operator = "Equals" + selector = "innocent" + } + } + } } managed_rule { - type = "BotProtection" - version = "preview-0.1" + type = "Microsoft_BotManagerRuleSet" + version = "1.0" } } ``` @@ -160,6 +187,8 @@ The `managed_rule` block supports the following: * `version` - (Required) The version on the managed rule to use with this resource. +* `exclusion` - (Optional) One or more `exclusion` blocks as defined below. + * `override` - (Optional) One or more `override` blocks as defined below. --- @@ -168,6 +197,8 @@ The `override` block supports the following: * `rule_group_name` - (Required) The managed rule group to override. +* `exclusion` - (Optional) One or more `exclusion` blocks as defined below. + * `rule` - (Optional) One or more `rule` blocks as defined below. If none are specified, all of the rules in the group will be disabled. --- @@ -180,6 +211,18 @@ The `rule` block supports the following: * `enabled` - (Optional) Is the managed rule override enabled or disabled. Defaults to `false` +* `exclusion` - (Optional) One or more `exclusion` blocks as defined below. + +--- + +The `exclusion` block supports the following: + +* `match_variable` - (Required) The variable type to be excluded. Possible values are `QueryStringArgNames`, `RequestBodyPostArgNames`, `RequestCookieNames`, `RequestHeaderNames`. + +* `operator` - (Required) Comparison operator to apply to the selector when specifying which elements in the collection this exclusion applies to. Possible values are: `Equals`, `Contains`, `StartsWith`, `EndsWith`, `EqualsAny`. + +* `selector` - (Required) Selector for the value in the `match_variable` attribute this exclusion applies to. + ## Attributes Reference The following attributes are exported: