diff --git a/internal/services/network/web_application_firewall_policy_resource.go b/internal/services/network/web_application_firewall_policy_resource.go index 79123a745e95..909675fec08d 100644 --- a/internal/services/network/web_application_firewall_policy_resource.go +++ b/internal/services/network/web_application_firewall_policy_resource.go @@ -438,12 +438,17 @@ func resourceWebApplicationFirewallPolicyCreateUpdate(d *pluginsdk.ResourceData, managedRules := d.Get("managed_rules").([]interface{}) t := d.Get("tags").(map[string]interface{}) + expandedManagedRules, err := expandWebApplicationFirewallPolicyManagedRulesDefinition(managedRules, d) + if err != nil { + return err + } + parameters := network.WebApplicationFirewallPolicy{ Location: utils.String(location), WebApplicationFirewallPolicyPropertiesFormat: &network.WebApplicationFirewallPolicyPropertiesFormat{ CustomRules: expandWebApplicationFirewallPolicyWebApplicationFirewallCustomRule(customRules), PolicySettings: expandWebApplicationFirewallPolicyPolicySettings(policySettings), - ManagedRules: expandWebApplicationFirewallPolicyManagedRulesDefinition(managedRules), + ManagedRules: expandedManagedRules, }, Tags: tags.Expand(t), } @@ -573,19 +578,24 @@ func expandWebApplicationFirewallPolicyPolicySettings(input []interface{}) *netw return &result } -func expandWebApplicationFirewallPolicyManagedRulesDefinition(input []interface{}) *network.ManagedRulesDefinition { +func expandWebApplicationFirewallPolicyManagedRulesDefinition(input []interface{}, d *pluginsdk.ResourceData) (*network.ManagedRulesDefinition, error) { if len(input) == 0 { - return nil + return nil, nil } v := input[0].(map[string]interface{}) exclusions := v["exclusion"].([]interface{}) managedRuleSets := v["managed_rule_set"].([]interface{}) + expandedManagedRuleSets, err := expandWebApplicationFirewallPolicyManagedRuleSet(managedRuleSets, d) + if err != nil { + return nil, err + } + return &network.ManagedRulesDefinition{ Exclusions: expandWebApplicationFirewallPolicyExclusions(exclusions), - ManagedRuleSets: expandWebApplicationFirewallPolicyManagedRuleSet(managedRuleSets), - } + ManagedRuleSets: expandedManagedRuleSets, + }, nil } func expandWebApplicationFirewallPolicyExclusionManagedRules(input []interface{}) *[]network.ExclusionManagedRule { @@ -666,31 +676,37 @@ func expandWebApplicationFirewallPolicyExclusions(input []interface{}) *[]networ return &results } -func expandWebApplicationFirewallPolicyManagedRuleSet(input []interface{}) *[]network.ManagedRuleSet { +func expandWebApplicationFirewallPolicyManagedRuleSet(input []interface{}, d *pluginsdk.ResourceData) (*[]network.ManagedRuleSet, error) { results := make([]network.ManagedRuleSet, 0) - for _, item := range input { - v := item.(map[string]interface{}) + for i, item := range input { + v := item.(map[string]interface{}) ruleSetType := v["type"].(string) ruleSetVersion := v["version"].(string) ruleGroupOverrides := []interface{}{} if value, exists := v["rule_group_override"]; exists { ruleGroupOverrides = value.([]interface{}) } + + expandedRuleGroupOverrides, err := expandWebApplicationFirewallPolicyRuleGroupOverrides(ruleGroupOverrides, d, i) + if err != nil { + return nil, err + } + result := network.ManagedRuleSet{ RuleSetType: utils.String(ruleSetType), RuleSetVersion: utils.String(ruleSetVersion), - RuleGroupOverrides: expandWebApplicationFirewallPolicyRuleGroupOverrides(ruleGroupOverrides), + RuleGroupOverrides: expandedRuleGroupOverrides, } results = append(results, result) } - return &results + return &results, nil } -func expandWebApplicationFirewallPolicyRuleGroupOverrides(input []interface{}) *[]network.ManagedRuleGroupOverride { +func expandWebApplicationFirewallPolicyRuleGroupOverrides(input []interface{}, d *pluginsdk.ResourceData, managedRuleSetIndex int) (*[]network.ManagedRuleGroupOverride, error) { results := make([]network.ManagedRuleGroupOverride, 0) - for _, item := range input { + for i, item := range input { v := item.(map[string]interface{}) ruleGroupName := v["rule_group_name"].(string) @@ -700,19 +716,35 @@ func expandWebApplicationFirewallPolicyRuleGroupOverrides(input []interface{}) * } if !features.FourPointOhBeta() { - if disabledRules := v["disabled_rules"].([]interface{}); len(disabledRules) > 0 { + // `disabled_rules` will be deprecated from 4.0. In 3.x, `rule` and `disabled_rules` point to the same properties of Azure REST API and conflict with each other in the configuration. + // Since both properties will be set in the flatten method, need to use `GetRawConfig` to check which one of these two properties is configured in the configuration file. + managedRuleSetList := d.GetRawConfig().AsValueMap()["managed_rules"].AsValueSlice()[0].AsValueMap()["managed_rule_set"].AsValueSlice() + if managedRuleSetIndex >= len(managedRuleSetList) { + return nil, fmt.Errorf("managed rule set index %d exceeds raw config length %d", managedRuleSetIndex, len(managedRuleSetList)) + } + + ruleGroupOverrideList := managedRuleSetList[managedRuleSetIndex].AsValueMap()["rule_group_override"].AsValueSlice() + if i >= len(ruleGroupOverrideList) { + return nil, fmt.Errorf("rule group override index %d exceeds raw config length %d", i, len(ruleGroupOverrideList)) + } + + if disabledRules := v["disabled_rules"].([]interface{}); !ruleGroupOverrideList[i].AsValueMap()["disabled_rules"].IsNull() { result.Rules = expandWebApplicationFirewallPolicyRules(disabledRules) } - } - if rules := v["rule"].([]interface{}); len(rules) > 0 { - result.Rules = expandWebApplicationFirewallPolicyOverrideRules(rules) + if rules := v["rule"].([]interface{}); !ruleGroupOverrideList[i].AsValueMap()["rule"].IsNull() && len(ruleGroupOverrideList[i].AsValueMap()["rule"].AsValueSlice()) > 0 { + result.Rules = expandWebApplicationFirewallPolicyOverrideRules(rules) + } + } else { + if rules := v["rule"].([]interface{}); len(rules) > 0 { + result.Rules = expandWebApplicationFirewallPolicyOverrideRules(rules) + } } results = append(results, result) } - return &results + return &results, nil } func expandWebApplicationFirewallPolicyRules(input []interface{}) *[]network.ManagedRuleOverride { diff --git a/internal/services/network/web_application_firewall_policy_resource_test.go b/internal/services/network/web_application_firewall_policy_resource_test.go index 91b4138caff0..ec152f7eb28f 100644 --- a/internal/services/network/web_application_firewall_policy_resource_test.go +++ b/internal/services/network/web_application_firewall_policy_resource_test.go @@ -246,6 +246,28 @@ func TestAccWebApplicationFirewallPolicy_excludedRules(t *testing.T) { }) } +func TestAccWebApplicationFirewallPolicy_updateDisabledRules(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_web_application_firewall_policy", "test") + r := WebApplicationFirewallResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.disabledRules(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.updateDisabledRules(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + func (t WebApplicationFirewallResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { id, err := parse.ApplicationGatewayWebApplicationFirewallPolicyID(state.ID) if err != nil { @@ -489,6 +511,12 @@ resource "azurerm_web_application_firewall_policy" "test" { rule_group_override { rule_group_name = "REQUEST-920-PROTOCOL-ENFORCEMENT" + + rule { + id = "920440" + enabled = true + action = "Block" + } } } } @@ -771,3 +799,157 @@ resource "azurerm_web_application_firewall_policy" "test" { } `, data.RandomInteger, data.Locations.Primary, data.RandomInteger) } + +func (WebApplicationFirewallResource) disabledRules(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_web_application_firewall_policy" "test" { + name = "acctestwafpolicy-%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + + policy_settings { + enabled = true + mode = "Prevention" + request_body_check = true + file_upload_limit_in_mb = 100 + max_request_body_size_in_kb = 2000 + } + + managed_rules { + managed_rule_set { + type = "OWASP" + version = "3.2" + + rule_group_override { + rule_group_name = "REQUEST-931-APPLICATION-ATTACK-RFI" + disabled_rules = ["931130"] + } + + rule_group_override { + rule_group_name = "REQUEST-920-PROTOCOL-ENFORCEMENT" + disabled_rules = [ + "920320", # Missing User Agent Header + "920230" # Multiple URL Encoding Detected + ] + } + + rule_group_override { + rule_group_name = "REQUEST-942-APPLICATION-ATTACK-SQLI" + disabled_rules = [ + "942450", + "942430", + "942440", + "942370", + "942340", + "942260", + "942200", + "942330", + "942120", + "942110", + "942150", + "942410", + "942130", + "942100" + ] + } + + rule_group_override { + rule_group_name = "REQUEST-941-APPLICATION-ATTACK-XSS" + disabled_rules = [ + "941340" + ] + } + } + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger) +} + +func (WebApplicationFirewallResource) updateDisabledRules(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_web_application_firewall_policy" "test" { + name = "acctestwafpolicy-%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + + policy_settings { + enabled = true + mode = "Prevention" + request_body_check = true + file_upload_limit_in_mb = 100 + max_request_body_size_in_kb = 2000 + } + + managed_rules { + managed_rule_set { + type = "OWASP" + version = "3.2" + + rule_group_override { + rule_group_name = "REQUEST-931-APPLICATION-ATTACK-RFI" + disabled_rules = ["931130"] + } + + rule_group_override { + rule_group_name = "REQUEST-920-PROTOCOL-ENFORCEMENT" + disabled_rules = [ + "920320", # Missing User Agent Header + "920230" # Multiple URL Encoding Detected + ] + } + + #NEW BLOCK + rule_group_override { + rule_group_name = "REQUEST-932-APPLICATION-ATTACK-RCE" + disabled_rules = ["932100"] + } + + rule_group_override { + rule_group_name = "REQUEST-942-APPLICATION-ATTACK-SQLI" + disabled_rules = [ + "942450", + "942430", + "942440", + "942370", + "942340", + "942260", + "942200", + "942330", + "942120", + "942110", + "942150", + "942410", + "942130", + "942100" + ] + } + + rule_group_override { + rule_group_name = "REQUEST-941-APPLICATION-ATTACK-XSS" + disabled_rules = [ + "941340" + ] + } + } + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger) +}