From 01ed5b8fbe975a7a83c377a153d7b8e2a9b7d5b8 Mon Sep 17 00:00:00 2001 From: xuwu1 Date: Fri, 14 Jul 2023 14:23:36 +0800 Subject: [PATCH] wafpolicy supports log scrubbing --- ...eb_application_firewall_policy_resource.go | 122 +++++++++++++++++- ...plication_firewall_policy_resource_test.go | 70 ++++++++++ ..._application_firewall_policy.html.markdown | 22 ++++ 3 files changed, 212 insertions(+), 2 deletions(-) diff --git a/internal/services/network/web_application_firewall_policy_resource.go b/internal/services/network/web_application_firewall_policy_resource.go index 91e81763b1320..3448534b9f2c1 100644 --- a/internal/services/network/web_application_firewall_policy_resource.go +++ b/internal/services/network/web_application_firewall_policy_resource.go @@ -370,6 +370,53 @@ func resourceWebApplicationFirewallPolicy() *pluginsdk.Resource { ValidateFunc: validation.IntBetween(8, 2000), Default: 128, }, + "log_scrubbing": { + Type: pluginsdk.TypeList, + MaxItems: 1, + Optional: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + Default: true, + }, + "rule": { + Type: pluginsdk.TypeList, + Optional: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + Default: true, + }, + "match_variable": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice( + webapplicationfirewallpolicies.PossibleValuesForScrubbingRuleEntryMatchVariable(), + false), + }, + "selector_match_operator": { + Type: pluginsdk.TypeString, + Optional: true, + Default: "Equals", + ValidateFunc: validation.StringInSlice( + webapplicationfirewallpolicies.PossibleValuesForScrubbingRuleEntryMatchOperator(), + false), + }, + "selector": { + Type: pluginsdk.TypeString, + Optional: true, + Description: "When matchVariable is a collection, operator used to specify which elements in the collection this rule applies to.", + }, + }, + }, + }, + }, + }, + }, }, }, }, @@ -582,10 +629,53 @@ func expandWebApplicationFirewallPolicyPolicySettings(input []interface{}) *weba RequestBodyCheck: pointer.To(requestBodyCheck), MaxRequestBodySizeInKb: pointer.To(int64(maxRequestBodySizeInKb)), FileUploadLimitInMb: pointer.To(int64(fileUploadLimitInMb)), + LogScrubbing: expandWebApplicationFirewallPolicyLogScrubbing(v["log_scrubbing"].([]interface{})), } return &result } +func expandWebApplicationFirewallPolicyLogScrubbing(input []interface{}) *webapplicationfirewallpolicies.PolicySettingsLogScrubbing { + if len(input) == 0 { + return nil + } + + var res webapplicationfirewallpolicies.PolicySettingsLogScrubbing + v := input[0].(map[string]interface{}) + state := webapplicationfirewallpolicies.WebApplicationFirewallScrubbingStateDisabled + if value, ok := v["enabled"].(bool); ok && value { + state = webapplicationfirewallpolicies.WebApplicationFirewallScrubbingStateEnabled + } + res.State = &state + + res.ScrubbingRules = expanedWebApplicationPolicyScrubbingRules(v["rule"].([]interface{})) + + return &res +} + +func expanedWebApplicationPolicyScrubbingRules(input []interface{}) *[]webapplicationfirewallpolicies.WebApplicationFirewallScrubbingRules { + if len(input) == 0 { + return nil + } + var res []webapplicationfirewallpolicies.WebApplicationFirewallScrubbingRules + for _, rule := range input { + v := rule.(map[string]interface{}) + var item webapplicationfirewallpolicies.WebApplicationFirewallScrubbingRules + state := webapplicationfirewallpolicies.ScrubbingRuleEntryStateDisabled + if value, ok := v["enabled"].(bool); ok && value { + state = webapplicationfirewallpolicies.ScrubbingRuleEntryStateEnabled + } + item.State = &state + item.MatchVariable = webapplicationfirewallpolicies.ScrubbingRuleEntryMatchVariable(v["match_variable"].(string)) + item.SelectorMatchOperator = webapplicationfirewallpolicies.ScrubbingRuleEntryMatchOperator(v["selector_match_operator"].(string)) + if val, ok := v["selector"]; ok { + item.Selector = pointer.To(val.(string)) + } + + res = append(res, item) + } + return &res +} + func expandWebApplicationFirewallPolicyManagedRulesDefinition(input []interface{}, d *pluginsdk.ResourceData) (*webapplicationfirewallpolicies.ManagedRulesDefinition, error) { if len(input) == 0 { return nil, nil @@ -872,12 +962,40 @@ func flattenWebApplicationFirewallPolicyPolicySettings(input *webapplicationfire result["enabled"] = pointer.From(input.State) == webapplicationfirewallpolicies.WebApplicationFirewallEnabledStateEnabled result["mode"] = string(pointer.From(input.Mode)) result["request_body_check"] = input.RequestBodyCheck - result["max_request_body_size_in_kb"] = int(*input.MaxRequestBodySizeInKb) - result["file_upload_limit_in_mb"] = int(*input.FileUploadLimitInMb) + result["max_request_body_size_in_kb"] = int(pointer.From(input.MaxRequestBodySizeInKb)) + result["file_upload_limit_in_mb"] = int(pointer.From(input.FileUploadLimitInMb)) + result["log_scrubbing"] = flattenWebApplicationFirewallPolicyLogScrubbing(input.LogScrubbing) return []interface{}{result} } +func flattenWebApplicationFirewallPolicyLogScrubbing(input *webapplicationfirewallpolicies.PolicySettingsLogScrubbing) interface{} { + if input == nil { + return make([]interface{}, 0) + } + result := make(map[string]interface{}) + result["enabled"] = pointer.From(input.State) == webapplicationfirewallpolicies.WebApplicationFirewallScrubbingStateEnabled + result["rule"] = flattenWebApplicationFirewallPolicyLogScrubbingRules(input.ScrubbingRules) + return []interface{}{result} +} + +func flattenWebApplicationFirewallPolicyLogScrubbingRules(rules *[]webapplicationfirewallpolicies.WebApplicationFirewallScrubbingRules) interface{} { + result := make([]interface{}, 0) + if rules == nil || len(*rules) == 0 { + return result + } + for _, rule := range *rules { + item := map[string]interface{}{} + item["enabled"] = pointer.From(rule.State) == webapplicationfirewallpolicies.ScrubbingRuleEntryStateEnabled + item["match_variable"] = rule.MatchVariable + item["selector_match_operator"] = rule.SelectorMatchOperator + item["selector"] = pointer.From(rule.Selector) + result = append(result, item) + } + return &result + +} + func flattenWebApplicationFirewallPolicyManagedRulesDefinition(input webapplicationfirewallpolicies.ManagedRulesDefinition) []interface{} { results := make([]interface{}, 0) 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 698eacc432743..8f7e62e31c3bf 100644 --- a/internal/services/network/web_application_firewall_policy_resource_test.go +++ b/internal/services/network/web_application_firewall_policy_resource_test.go @@ -286,6 +286,21 @@ func TestAccWebApplicationFirewallPolicy_updateDisabledRules(t *testing.T) { }) } +func TestAccWebApplicationFirewallPolicy_LogScrubbing(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_web_application_firewall_policy", "test") + r := WebApplicationFirewallResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.withLogScrubbing(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 := webapplicationfirewallpolicies.ParseApplicationGatewayWebApplicationFirewallPolicyID(state.ID) if err != nil { @@ -1030,3 +1045,58 @@ resource "azurerm_web_application_firewall_policy" "test" { } `, data.RandomInteger, data.Locations.Primary, data.RandomInteger) } + +func (WebApplicationFirewallResource) withLogScrubbing(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%[1]d" + location = "%[2]s" +} + +resource "azurerm_web_application_firewall_policy" "test" { + name = "acctestwafpolicy-%[1]d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + + policy_settings { + enabled = true + mode = "Detection" + log_scrubbing { + enabled = true + rule { + enabled = true + match_variable = "RequestHeaderNames" + selector_match_operator = "Equals" + selector = "User-Agent" + } + } + } + + managed_rules { + managed_rule_set { + type = "OWASP" + version = "3.2" + + rule_group_override { + rule_group_name = "REQUEST-920-PROTOCOL-ENFORCEMENT" + rule { + id = "920300" + enabled = true + action = "Log" + } + + rule { + id = "920440" + enabled = true + action = "Block" + } + } + } + } +} +`, data.RandomInteger, data.Locations.Primary) +} diff --git a/website/docs/r/web_application_firewall_policy.html.markdown b/website/docs/r/web_application_firewall_policy.html.markdown index 6d44ed9812ad3..6d42cf3c5d07b 100644 --- a/website/docs/r/web_application_firewall_policy.html.markdown +++ b/website/docs/r/web_application_firewall_policy.html.markdown @@ -180,6 +180,8 @@ The `policy_settings` block supports the following: * `max_request_body_size_in_kb` - (Optional) The Maximum Request Body Size in KB. Accepted values are in the range `8` to `2000`. Defaults to `128`. +* `log_scrubbing` - (Optional) One `log_scrubbing` block as defined below. + --- The `managed_rules` block supports the following: @@ -246,6 +248,26 @@ The `rule` block supports the following: * `action` - (Optional) Describes the override action to be applied when rule matches. Possible values are `Allow`, `AnomalyScoring`, `Block` and `Log`. +--- + +The `log_scrubbing` block supports the following: + +* `enabled` - (Optional) Whether the log scrubbing is enabled or disabled. Defaults to `true`. + +* `rule` - (Optional) One or more `scrubbing_rule` as define below. + +--- + +The `scrubbing_rule` block supports the following: + +* `enabled` - (Optional) Whether this rule is enabled. Defaults to `true`. + +* `match_variable` - (Required) Specifies the variable to be scrubbed from the logs. Possible values are `RequestHeaderNames`, `RequestCookieNames`, `RequestArgNames`, `RequestPostArgNames`, `RequestJSONArgNames` and `RequestIPAddress`. + +* `selector_match_operator` - (Optional) Specifies the operating on the `selector`. Possible values are `Equals` and `EqualsAny`. Defaults to `Equals`. + +* `selector` - (Optional) Specifies which elements in the collection this rule applies to. + ## Attributes Reference In addition to the Arguments listed above - the following Attributes are exported: