Skip to content

Commit

Permalink
resource_arm_application_gateway: add advanced waf_configuration with…
Browse files Browse the repository at this point in the history
… disabled_rule_group
  • Loading branch information
bs-matil committed May 7, 2019
1 parent 8a9f79b commit 8e2522b
Show file tree
Hide file tree
Showing 3 changed files with 250 additions and 0 deletions.
98 changes: 98 additions & 0 deletions azurerm/resource_arm_application_gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -919,6 +919,49 @@ func resourceArmApplicationGateway() *schema.Resource {
ValidateFunc: validation.IntBetween(1, 128),
Default: 128,
},
"disabled_rule_group": {
Type: schema.TypeList,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"rule_group_name": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringInSlice([]string{
"crs_20_protocol_violations",
"crs_21_protocol_anomalies",
"crs_23_request_limits",
"crs_30_http_policy",
"crs_35_bad_robots",
"crs_40_generic_attacks",
"crs_41_sql_injection_attacks",
"crs_41_xss_attacks",
"crs_42_tight_security",
"crs_45_trojans",
"REQUEST-911-METHOD-ENFORCEMENT",
"REQUEST-913-SCANNER-DETECTION",
"REQUEST-920-PROTOCOL-ENFORCEMENT",
"REQUEST-921-PROTOCOL-ATTACK",
"REQUEST-930-APPLICATION-ATTACK-LFI",
"REQUEST-931-APPLICATION-ATTACK-RFI",
"REQUEST-932-APPLICATION-ATTACK-RCE",
"REQUEST-933-APPLICATION-ATTACK-PHP",
"REQUEST-941-APPLICATION-ATTACK-XSS",
"REQUEST-942-APPLICATION-ATTACK-SQLI",
"REQUEST-943-APPLICATION-ATTACK-SESSION-FIXATION",
}, true),
},

"rules": {
Type: schema.TypeList,
Optional: true,
Elem: &schema.Schema{
Type: schema.TypeInt,
},
},
},
},
},
},
},
},
Expand Down Expand Up @@ -2612,6 +2655,29 @@ func expandApplicationGatewayWafConfig(d *schema.ResourceData) *network.Applicat
requestBodyCheck := v["request_body_check"].(bool)
maxRequestBodySizeInKb := v["max_request_body_size_kb"].(int)

disabledRuleGroups := make([]network.ApplicationGatewayFirewallDisabledRuleGroup, 0)
for _, disabledRuleGroup := range v["disabled_rule_group"].([]interface{}) {
disabledRuleGroupMap := disabledRuleGroup.(map[string]interface{})

ruleGroupName := disabledRuleGroupMap["rule_group_name"].(string)

rules := make([]int32, 0)
for _, rule := range disabledRuleGroupMap["rules"].([]interface{}) {
rules = append(rules, int32(rule.(int)))
}

if len(rules) == 0 {
rules = nil
}

ruleGroup := network.ApplicationGatewayFirewallDisabledRuleGroup{
RuleGroupName: utils.String(ruleGroupName),
Rules: &rules,
}

disabledRuleGroups = append(disabledRuleGroups, ruleGroup)
}

return &network.ApplicationGatewayWebApplicationFirewallConfiguration{
Enabled: utils.Bool(enabled),
FirewallMode: network.ApplicationGatewayFirewallMode(mode),
Expand All @@ -2620,6 +2686,7 @@ func expandApplicationGatewayWafConfig(d *schema.ResourceData) *network.Applicat
FileUploadLimitInMb: utils.Int32(int32(fileUploadLimitInMb)),
RequestBodyCheck: utils.Bool(requestBodyCheck),
MaxRequestBodySizeInKb: utils.Int32(int32(maxRequestBodySizeInKb)),
DisabledRuleGroups: &disabledRuleGroups,
}
}

Expand All @@ -2645,6 +2712,37 @@ func flattenApplicationGatewayWafConfig(input *network.ApplicationGatewayWebAppl
output["rule_set_version"] = *input.RuleSetVersion
}

ruleGroups := make([]interface{}, 0)
if disabledRuleGroups := input.DisabledRuleGroups; disabledRuleGroups != nil {
for _, ruleGroup := range *disabledRuleGroups {
ruleGroupOutput := map[string]interface{}{}

if ruleGroup.RuleGroupName != nil {
ruleGroupOutput["rule_group_name"] = *ruleGroup.RuleGroupName
}

ruleOutputs := make([]interface{}, 0)
if rules := ruleGroup.Rules; rules != nil {
for _, rule := range *rules {
ruleOutputs = append(ruleOutputs, rule)
}
}
ruleGroupOutput["rules"] = ruleOutputs

ruleGroups = append(ruleGroups, ruleGroupOutput)
}

output["disabled_rule_group"] = ruleGroups
}

if input.RequestBodyCheck != nil {
output["request_body_check"] = *input.RequestBodyCheck
}

if input.MaxRequestBodySizeInKb != nil {
output["max_request_body_size_in_kb"] = *input.MaxRequestBodySizeInKb
}

if input.FileUploadLimitInMb != nil {
output["file_upload_limit_mb"] = int(*input.FileUploadLimitInMb)
}
Expand Down
142 changes: 142 additions & 0 deletions azurerm/resource_arm_application_gateway_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,43 @@ func TestAccAzureRMApplicationGateway_connectionDraining(t *testing.T) {
})
}

func TestAccAzureRMApplicationGateway_webApplicationFirewall_disabledRuleGroups(t *testing.T) {
resourceName := "azurerm_application_gateway.test"
ri := tf.AccRandTimeInt()

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testCheckAzureRMApplicationGatewayDestroy,
Steps: []resource.TestStep{
{
Config: testAccAzureRMApplicationGateway_webApplicationFirewall_disabledRuleGroups(ri, testLocation()),
Check: resource.ComposeTestCheckFunc(
testCheckAzureRMApplicationGatewayExists(resourceName),
resource.TestCheckResourceAttr(resourceName, "sku.0.name", "WAF_Medium"),
resource.TestCheckResourceAttr(resourceName, "sku.0.tier", "WAF"),
resource.TestCheckResourceAttr(resourceName, "sku.0.capacity", "1"),
resource.TestCheckResourceAttr(resourceName, "waf_configuration.0.enabled", "true"),
resource.TestCheckResourceAttr(resourceName, "waf_configuration.0.firewall_mode", "Detection"),
resource.TestCheckResourceAttr(resourceName, "waf_configuration.0.rule_set_type", "OWASP"),
resource.TestCheckResourceAttr(resourceName, "waf_configuration.0.rule_set_version", "3.0"),
resource.TestCheckResourceAttr(resourceName, "waf_configuration.0.request_body_check", "true"),
resource.TestCheckResourceAttr(resourceName, "waf_configuration.0.max_request_body_size_kb", "128"),
resource.TestCheckResourceAttr(resourceName, "waf_configuration.0.file_upload_limit_mb", "100"),
resource.TestCheckResourceAttr(resourceName, "waf_configuration.0.disabled_rule_group.0.rule_group_name", "REQUEST-921-PROTOCOL-ATTACK"),
resource.TestCheckResourceAttr(resourceName, "waf_configuration.0.disabled_rule_group.0.rules.0", "921110"),
resource.TestCheckResourceAttr(resourceName, "waf_configuration.0.disabled_rule_group.0.rules.1", "921151"),
resource.TestCheckResourceAttr(resourceName, "waf_configuration.0.disabled_rule_group.0.rules.2", "921180"),
resource.TestCheckResourceAttr(resourceName, "waf_configuration.0.disabled_rule_group.1.rule_group_name", "REQUEST-930-APPLICATION-ATTACK-LFI"),
resource.TestCheckResourceAttr(resourceName, "waf_configuration.0.disabled_rule_group.1.rules.0", "930120"),
resource.TestCheckResourceAttr(resourceName, "waf_configuration.0.disabled_rule_group.1.rules.1", "930130"),
resource.TestCheckResourceAttr(resourceName, "waf_configuration.0.disabled_rule_group.2.rule_group_name", "REQUEST-942-APPLICATION-ATTACK-SQLI"),
),
},
},
})
}

func testCheckAzureRMApplicationGatewayExists(resourceName string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[resourceName]
Expand Down Expand Up @@ -2074,6 +2111,111 @@ resource "azurerm_application_gateway" "test" {
}
`, template, rInt)
}
func testAccAzureRMApplicationGateway_webApplicationFirewall_disabledRuleGroups(rInt int, location string) string {
template := testAccAzureRMApplicationGateway_template(rInt, location)
return fmt.Sprintf(`
%s
# since these variables are re-used - a locals block makes this more maintainable
locals {
backend_address_pool_name = "${azurerm_virtual_network.test.name}-beap"
frontend_port_name = "${azurerm_virtual_network.test.name}-feport"
frontend_ip_configuration_name = "${azurerm_virtual_network.test.name}-feip"
http_setting_name = "${azurerm_virtual_network.test.name}-be-htst"
listener_name = "${azurerm_virtual_network.test.name}-httplstn"
request_routing_rule_name = "${azurerm_virtual_network.test.name}-rqrt"
}
resource "azurerm_public_ip" "test_standard" {
name = "acctest-pubip-%d-standard"
location = "${azurerm_resource_group.test.location}"
resource_group_name = "${azurerm_resource_group.test.name}"
sku = "Standard"
allocation_method = "Static"
}
resource "azurerm_application_gateway" "test" {
name = "acctestag-%d"
resource_group_name = "${azurerm_resource_group.test.name}"
location = "${azurerm_resource_group.test.location}"
sku {
name = "WAF_v2"
tier = "WAF_v2"
capacity = 1
}
waf_configuration {
enabled = true
firewall_mode = "Detection"
rule_set_type = "OWASP"
rule_set_version = "3.0"
request_body_check = true
max_request_body_size_kb = 128
file_upload_limit_mb = 100
disabled_rule_group {
rule_group_name = "REQUEST-921-PROTOCOL-ATTACK"
rules = [921110, 921151, 921180]
}
disabled_rule_group {
rule_group_name = "REQUEST-930-APPLICATION-ATTACK-LFI"
rules = [930120, 930130]
}
disabled_rule_group {
rule_group_name = "REQUEST-942-APPLICATION-ATTACK-SQLI"
}
}
gateway_ip_configuration {
name = "my-gateway-ip-configuration"
subnet_id = "${azurerm_subnet.test.id}"
}
frontend_port {
name = "${local.frontend_port_name}"
port = 80
}
frontend_ip_configuration {
name = "${local.frontend_ip_configuration_name}"
public_ip_address_id = "${azurerm_public_ip.test_standard.id}"
}
backend_address_pool {
name = "${local.backend_address_pool_name}"
}
backend_http_settings {
name = "${local.http_setting_name}"
cookie_based_affinity = "Disabled"
port = 80
protocol = "Http"
request_timeout = 1
}
http_listener {
name = "${local.listener_name}"
frontend_ip_configuration_name = "${local.frontend_ip_configuration_name}"
frontend_port_name = "${local.frontend_port_name}"
protocol = "Http"
}
request_routing_rule {
name = "${local.request_routing_rule_name}"
rule_type = "Basic"
http_listener_name = "${local.listener_name}"
backend_address_pool_name = "${local.backend_address_pool_name}"
backend_http_settings_name = "${local.http_setting_name}"
}
}
`, template, rInt, rInt)
}

func testAccAzureRMApplicationGateway_template(rInt int, location string) string {
return fmt.Sprintf(`
Expand Down
10 changes: 10 additions & 0 deletions website/docs/r/application_gateway.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,8 @@ A `waf_configuration` block supports the following:

* `rule_set_version` - (Required) The Version of the Rule Set used for this Web Application Firewall.

* `disabled_rule_group` - (Optional) one or many `disabled_rule_group` blocks as defined below.

* `file_upload_limit_mb` - (Optional) The File Upload Limit in MB. Accepted values are in the range `1`MB to `500`MB. Defaults to `100`MB.

* `request_body_check` - (Optional) Is Request Body Inspection enabled? Defaults to `true`.
Expand All @@ -399,6 +401,14 @@ A `waf_configuration` block supports the following:

---

A `disabled_rule_group` block supports the following:

* `rule_group_name` - (Required) The rule group where specific rules should be disabled. Accepted values are: `crs_20_protocol_violations`, `crs_21_protocol_anomalies`, `crs_23_request_limits`, `crs_30_http_policy`, `crs_35_bad_robots`, `crs_40_generic_attacks`, `crs_41_sql_injection_attacks`, `crs_41_xss_attacks`, `crs_42_tight_security`, `crs_45_trojans`, `REQUEST-911-METHOD-ENFORCEMENT`, `REQUEST-913-SCANNER-DETECTION`, `REQUEST-920-PROTOCOL-ENFORCEMENT`, `REQUEST-921-PROTOCOL-ATTACK`, `REQUEST-930-APPLICATION-ATTACK-LFI`, `REQUEST-931-APPLICATION-ATTACK-RFI`, `REQUEST-932-APPLICATION-ATTACK-RCE`, `REQUEST-933-APPLICATION-ATTACK-PHP`, `REQUEST-941-APPLICATION-ATTACK-XSS`, `REQUEST-942-APPLICATION-ATTACK-SQLI`, `REQUEST-943-APPLICATION-ATTACK-SESSION-FIXATION`

* `rules` - (Required) A list of rule numbers which should be disabled in that group. Example: [921110, 921151, 921180] if group is set to `REQUEST-921-PROTOCOL-ATTACK`

---

A `custom_error_configuration` block supports the following:

* `status_code` - (Required) Status code of the application gateway customer error. Possible values are `HttpStatus403` and `HttpStatus502`
Expand Down

0 comments on commit 8e2522b

Please sign in to comment.