Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

azurerm_web_application_firewall_policy: support rate_limit_* and request_body_* properties #23239

Merged
merged 1 commit into from
Sep 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -168,13 +168,30 @@ func resourceWebApplicationFirewallPolicy() *pluginsdk.Resource {
Required: true,
ValidateFunc: validation.StringInSlice([]string{
string(webapplicationfirewallpolicies.WebApplicationFirewallRuleTypeMatchRule),
string(webapplicationfirewallpolicies.WebApplicationFirewallRuleTypeRateLimitRule),
string(webapplicationfirewallpolicies.WebApplicationFirewallRuleTypeInvalid),
}, false),
},
"name": {
Type: pluginsdk.TypeString,
Optional: true,
},
"rate_limit_duration": {
Type: pluginsdk.TypeString,
Optional: true,
ValidateFunc: validation.StringInSlice(webapplicationfirewallpolicies.PossibleValuesForApplicationGatewayFirewallRateLimitDuration(), false),
},
"rate_limit_threshold": {
Type: pluginsdk.TypeInt,
Optional: true,
ValidateFunc: validation.IntAtLeast(1),
},
"group_rate_limit_by": {
// group variables combination not supported yet, use a single variable name
Type: pluginsdk.TypeString,
Optional: true,
ValidateFunc: validation.StringInSlice(webapplicationfirewallpolicies.PossibleValuesForApplicationGatewayFirewallUserSessionVariable(), false),
},
},
},
},
Expand Down Expand Up @@ -349,6 +366,7 @@ func resourceWebApplicationFirewallPolicy() *pluginsdk.Resource {
Optional: true,
Default: true,
},

"mode": {
Type: pluginsdk.TypeString,
Optional: true,
Expand All @@ -358,23 +376,34 @@ func resourceWebApplicationFirewallPolicy() *pluginsdk.Resource {
}, false),
Default: string(webapplicationfirewallpolicies.WebApplicationFirewallModePrevention),
},

"request_body_check": {
Type: pluginsdk.TypeBool,
Optional: true,
Default: true,
},

"file_upload_limit_in_mb": {
Type: pluginsdk.TypeInt,
Optional: true,
ValidateFunc: validation.IntBetween(1, 4000),
Default: 100,
},

"max_request_body_size_in_kb": {
Type: pluginsdk.TypeInt,
Optional: true,
ValidateFunc: validation.IntBetween(8, 2000),
Default: 128,
},

"request_body_inspect_limit_in_kb": {
Type: pluginsdk.TypeInt,
Optional: true,
Default: 128,
stephybun marked this conversation as resolved.
Show resolved Hide resolved
ValidateFunc: validation.IntAtLeast(0),
},

"log_scrubbing": {
Type: pluginsdk.TypeList,
MaxItems: 1,
Expand Down Expand Up @@ -618,6 +647,27 @@ func expandWebApplicationFirewallPolicyWebApplicationFirewallCustomRule(input []
RuleType: webapplicationfirewallpolicies.WebApplicationFirewallRuleType(ruleType),
}

if rateLimitDuration, ok := v["rate_limit_duration"]; ok && rateLimitDuration.(string) != "" {
result.RateLimitDuration = pointer.To(webapplicationfirewallpolicies.ApplicationGatewayFirewallRateLimitDuration(rateLimitDuration.(string)))
}

if rateLimitThreshHold, ok := v["rate_limit_threshold"]; ok && rateLimitThreshHold.(int) > 0 {
result.RateLimitThreshold = pointer.To(int64(rateLimitThreshHold.(int)))
}

if groupBy, ok := v["group_rate_limit_by"]; ok && groupBy.(string) != "" {
groups := []webapplicationfirewallpolicies.GroupByUserSession{
{
GroupByVariables: []webapplicationfirewallpolicies.GroupByVariable{
{
VariableName: webapplicationfirewallpolicies.ApplicationGatewayFirewallUserSessionVariable(groupBy.(string)),
},
},
},
}
result.GroupByUserSession = &groups
}

results = append(results, result)
}
return &results
Expand All @@ -639,13 +689,15 @@ func expandWebApplicationFirewallPolicyPolicySettings(input []interface{}) *weba
fileUploadLimitInMb := v["file_upload_limit_in_mb"].(int)

result := webapplicationfirewallpolicies.PolicySettings{
State: pointer.To(enabled),
Mode: pointer.To(webapplicationfirewallpolicies.WebApplicationFirewallMode(mode)),
RequestBodyCheck: pointer.To(requestBodyCheck),
MaxRequestBodySizeInKb: pointer.To(int64(maxRequestBodySizeInKb)),
FileUploadLimitInMb: pointer.To(int64(fileUploadLimitInMb)),
LogScrubbing: expandWebApplicationFirewallPolicyLogScrubbing(v["log_scrubbing"].([]interface{})),
State: pointer.To(enabled),
Mode: pointer.To(webapplicationfirewallpolicies.WebApplicationFirewallMode(mode)),
RequestBodyCheck: pointer.To(requestBodyCheck),
MaxRequestBodySizeInKb: pointer.To(int64(maxRequestBodySizeInKb)),
FileUploadLimitInMb: pointer.To(int64(fileUploadLimitInMb)),
LogScrubbing: expandWebApplicationFirewallPolicyLogScrubbing(v["log_scrubbing"].([]interface{})),
RequestBodyInspectLimitInKB: pointer.To(int64(v["request_body_inspect_limit_in_kb"].(int))),
}

return &result
}

Expand Down Expand Up @@ -961,6 +1013,14 @@ func flattenWebApplicationFirewallPolicyWebApplicationFirewallCustomRule(input *
v["match_conditions"] = flattenWebApplicationFirewallPolicyMatchCondition(item.MatchConditions)
v["priority"] = int(item.Priority)
v["rule_type"] = string(item.RuleType)
v["rate_limit_duration"] = pointer.From(item.RateLimitDuration)
v["rate_limit_threshold"] = pointer.From(item.RateLimitThreshold)

if item.GroupByUserSession != nil && len(*item.GroupByUserSession) > 0 {
if groupVariable := (*item.GroupByUserSession)[0].GroupByVariables; len(groupVariable) > 0 {
v["group_rate_limit_by"] = groupVariable[0].VariableName
}
}

results = append(results, v)
}
Expand All @@ -981,6 +1041,7 @@ func flattenWebApplicationFirewallPolicyPolicySettings(input *webapplicationfire
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)
result["request_body_inspect_limit_in_kb"] = pointer.From(input.RequestBodyInspectLimitInKB)

return []interface{}{result}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,35 @@ func TestAccWebApplicationFirewallPolicy_updateOverrideRules(t *testing.T) {
})
}

func TestAccWebApplicationFirewallPolicy_rateLimit(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_web_application_firewall_policy", "test")
r := WebApplicationFirewallResource{}

data.ResourceTest(t, r, []acceptance.TestStep{
{
Config: r.rateLimit(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep(),
{
Config: r.rateLimitUpdate(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep(),
{
Config: r.rateLimit(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep(),
})
}

func TestAccWebApplicationFirewallPolicy_knownCVEs(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_web_application_firewall_policy", "test")
r := WebApplicationFirewallResource{}
Expand Down Expand Up @@ -513,6 +542,174 @@ resource "azurerm_web_application_firewall_policy" "test" {
`, data.RandomInteger, data.Locations.Primary, data.RandomInteger)
}

func (WebApplicationFirewallResource) rateLimit(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

tags = {
env = "test"
}

custom_rules {
name = "Rule1"
priority = 1
rule_type = "RateLimitRule"
rate_limit_duration = "FiveMins"
rate_limit_threshold = 100
group_rate_limit_by = "ClientAddr"

match_conditions {
match_variables {
variable_name = "RemoteAddr"
}

operator = "IPMatch"
negation_condition = false
match_values = ["192.168.1.0/24", "10.0.0.0/24"]
}

action = "Block"
}

managed_rules {
exclusion {
match_variable = "RequestHeaderNames"
selector = "x-shared-secret"
selector_match_operator = "Equals"
}

exclusion {
match_variable = "RequestCookieNames"
selector = "too-much-fun"
selector_match_operator = "EndsWith"
}

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"
}
}
}
}

policy_settings {
enabled = true
mode = "Prevention"
request_body_inspect_limit_in_kb = 1000
}
}
`, data.RandomInteger, data.Locations.Primary, data.RandomInteger)
}

func (WebApplicationFirewallResource) rateLimitUpdate(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

tags = {
env = "test"
}

custom_rules {
name = "Rule1"
priority = 1
rule_type = "RateLimitRule"
rate_limit_duration = "OneMin"
rate_limit_threshold = 123
group_rate_limit_by = "GeoLocation"

match_conditions {
match_variables {
variable_name = "RemoteAddr"
}

operator = "IPMatch"
negation_condition = false
match_values = ["192.168.1.0/24", "10.0.0.0/24"]
}

action = "Block"
}

managed_rules {
exclusion {
match_variable = "RequestHeaderNames"
selector = "x-shared-secret"
selector_match_operator = "Equals"
}

exclusion {
match_variable = "RequestCookieNames"
selector = "too-much-fun"
selector_match_operator = "EndsWith"
}

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"
}
}
}
}

policy_settings {
enabled = true
mode = "Prevention"
request_body_inspect_limit_in_kb = 1234
}
}
`, data.RandomInteger, data.Locations.Primary, data.RandomInteger)
}

func (WebApplicationFirewallResource) updateOverrideRules(data acceptance.TestData) string {
return fmt.Sprintf(`
provider "azurerm" {
Expand Down
10 changes: 9 additions & 1 deletion website/docs/r/web_application_firewall_policy.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -140,12 +140,18 @@ The `custom_rules` block supports the following:

* `priority` - (Required) Describes priority of the rule. Rules with a lower value will be evaluated before rules with a higher value.

* `rule_type` - (Required) Describes the type of rule. Possible values are `MatchRule` and `Invalid`.
* `rule_type` - (Required) Describes the type of rule. Possible values are `MatchRule`, `RateLimitRule` and `Invalid`.

* `match_conditions` - (Required) One or more `match_conditions` blocks as defined below.

* `action` - (Required) Type of action. Possible values are `Allow`, `Block` and `Log`.

* `rate_limit_duration` - (Optional) Specifies the duration at which the rate limit policy will be applied. Should be used with `RateLimitRule` rule type. Possible values are `FiveMins` and `OneMin`.

* `rate_limit_threshold` - (Optional) Specifies the threshold value for the rate limit policy. Must be greater than or equal to 1 if provided.

* `group_rate_limit_by` - (Optional) Specifies what grouping the rate limit will count requests by. Possible values are `GeoLocation`, `ClientAddr` and `None`.

---

The `match_conditions` block supports the following:
Expand Down Expand Up @@ -184,6 +190,8 @@ The `policy_settings` block supports the following:

* `log_scrubbing` - (Optional) One `log_scrubbing` block as defined below.

* `request_body_inspect_limit_in_kb` - (Optional) Specifies the maximum request body inspection limit in KB for the Web Application Firewall. Defaults to `128`.

---

The `managed_rules` block supports the following:
Expand Down
Loading