diff --git a/internal/service/wafv2/flex.go b/internal/service/wafv2/flex.go index c4067292dd8..1ddbf4da499 100644 --- a/internal/service/wafv2/flex.go +++ b/internal/service/wafv2/flex.go @@ -84,6 +84,10 @@ func expandRuleAction(l []interface{}) *wafv2.RuleAction { action.Captcha = expandCaptchaAction(v.([]interface{})) } + if v, ok := m["challenge"]; ok && len(v.([]interface{})) > 0 { + action.Challenge = expandChallengeAction(v.([]interface{})) + } + if v, ok := m["count"]; ok && len(v.([]interface{})) > 0 { action.Count = expandCountAction(v.([]interface{})) } @@ -148,6 +152,25 @@ func expandCaptchaAction(l []interface{}) *wafv2.CaptchaAction { return action } +func expandChallengeAction(l []interface{}) *wafv2.ChallengeAction { + action := &wafv2.ChallengeAction{} + + if len(l) == 0 || l[0] == nil { + return action + } + + m, ok := l[0].(map[string]interface{}) + if !ok { + return action + } + + if v, ok := m["custom_request_handling"].([]interface{}); ok && len(v) > 0 { + action.CustomRequestHandling = expandCustomRequestHandling(v) + } + + return action +} + func expandCountAction(l []interface{}) *wafv2.CountAction { action := &wafv2.CountAction{} @@ -1118,6 +1141,10 @@ func flattenRuleAction(a *wafv2.RuleAction) interface{} { m["captcha"] = flattenCaptcha(a.Captcha) } + if a.Challenge != nil { + m["challenge"] = flattenChallenge(a.Challenge) + } + if a.Count != nil { m["count"] = flattenCount(a.Count) } @@ -1166,6 +1193,20 @@ func flattenCaptcha(a *wafv2.CaptchaAction) []interface{} { return []interface{}{m} } +func flattenChallenge(a *wafv2.ChallengeAction) []interface{} { + if a == nil { + return []interface{}{} + } + + m := map[string]interface{}{} + + if a.CustomRequestHandling != nil { + m["custom_request_handling"] = flattenCustomRequestHandling(a.CustomRequestHandling) + } + + return []interface{}{m} +} + func flattenCount(a *wafv2.CountAction) []interface{} { if a == nil { return []interface{}{} diff --git a/internal/service/wafv2/schemas.go b/internal/service/wafv2/schemas.go index 5e0a6b5705f..830492766b2 100644 --- a/internal/service/wafv2/schemas.go +++ b/internal/service/wafv2/schemas.go @@ -549,6 +549,19 @@ func captchaConfigSchema() *schema.Schema { } } +func challengeConfigSchema() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "custom_request_handling": customRequestHandlingSchema(), + }, + }, + } +} + func countConfigSchema() *schema.Schema { return &schema.Schema{ Type: schema.TypeList, diff --git a/internal/service/wafv2/web_acl.go b/internal/service/wafv2/web_acl.go index ddc1a7dfda5..b1b85a639da 100644 --- a/internal/service/wafv2/web_acl.go +++ b/internal/service/wafv2/web_acl.go @@ -100,10 +100,11 @@ func ResourceWebACL() *schema.Resource { MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "allow": allowConfigSchema(), - "block": blockConfigSchema(), - "captcha": captchaConfigSchema(), - "count": countConfigSchema(), + "allow": allowConfigSchema(), + "block": blockConfigSchema(), + "captcha": captchaConfigSchema(), + "challenge": challengeConfigSchema(), + "count": countConfigSchema(), }, }, }, diff --git a/internal/service/wafv2/web_acl_test.go b/internal/service/wafv2/web_acl_test.go index 0a8f9c4ff7c..7d022f7d8fd 100644 --- a/internal/service/wafv2/web_acl_test.go +++ b/internal/service/wafv2/web_acl_test.go @@ -558,12 +558,14 @@ func TestAccWAFV2WebACL_ManagedRuleGroup_basic(t *testing.T) { "statement.0.managed_rule_group_statement.0.rule_action_override.0.action_to_use.0.allow.#": "0", "statement.0.managed_rule_group_statement.0.rule_action_override.0.action_to_use.0.block.#": "0", "statement.0.managed_rule_group_statement.0.rule_action_override.0.action_to_use.0.captcha.#": "0", + "statement.0.managed_rule_group_statement.0.rule_action_override.0.action_to_use.0.challenge.#": "0", "statement.0.managed_rule_group_statement.0.rule_action_override.0.action_to_use.0.count.#": "1", "statement.0.managed_rule_group_statement.0.rule_action_override.0.name": "SizeRestrictions_QUERYSTRING", "statement.0.managed_rule_group_statement.0.rule_action_override.1.action_to_use.#": "1", "statement.0.managed_rule_group_statement.0.rule_action_override.1.action_to_use.0.allow.#": "0", "statement.0.managed_rule_group_statement.0.rule_action_override.1.action_to_use.0.block.#": "0", "statement.0.managed_rule_group_statement.0.rule_action_override.1.action_to_use.0.captcha.#": "0", + "statement.0.managed_rule_group_statement.0.rule_action_override.1.action_to_use.0.challenge.#": "0", "statement.0.managed_rule_group_statement.0.rule_action_override.1.action_to_use.0.count.#": "1", "statement.0.managed_rule_group_statement.0.rule_action_override.1.name": "NoUserAgent_HEADER", "statement.0.managed_rule_group_statement.0.scope_down_statement.#": "1", @@ -1466,10 +1468,11 @@ func TestAccWAFV2WebACL_Custom_requestHandling(t *testing.T) { "action.0.allow.0.custom_request_handling.0.insert_header.0.value": "test-value-1", "action.0.allow.0.custom_request_handling.0.insert_header.1.name": "x-hdr2", "action.0.allow.0.custom_request_handling.0.insert_header.1.value": "test-value-2", - "action.0.block.#": "0", - "action.0.captcha.#": "0", - "action.0.count.#": "0", - "priority": "1", + "action.0.block.#": "0", + "action.0.captcha.#": "0", + "action.0.challenge.#": "0", + "action.0.count.#": "0", + "priority": "1", }), resource.TestCheckResourceAttr(resourceName, "visibility_config.#", "1"), resource.TestCheckResourceAttr(resourceName, "visibility_config.0.cloudwatch_metrics_enabled", "false"), @@ -1495,12 +1498,13 @@ func TestAccWAFV2WebACL_Custom_requestHandling(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "scope", "REGIONAL"), resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), resource.TestCheckTypeSetElemNestedAttrs(resourceName, "rule.*", map[string]string{ - "name": "rule-1", - "action.#": "1", - "action.0.allow.#": "0", - "action.0.block.#": "0", - "action.0.captcha.#": "0", - "action.0.count.#": "1", + "name": "rule-1", + "action.#": "1", + "action.0.allow.#": "0", + "action.0.block.#": "0", + "action.0.captcha.#": "0", + "action.0.challenge.#": "0", + "action.0.count.#": "1", "action.0.count.0.custom_request_handling.#": "1", "action.0.count.0.custom_request_handling.0.insert_header.#": "2", "action.0.count.0.custom_request_handling.0.insert_header.0.name": "x-hdr1", @@ -1527,11 +1531,12 @@ func TestAccWAFV2WebACL_Custom_requestHandling(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "scope", "REGIONAL"), resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), resource.TestCheckTypeSetElemNestedAttrs(resourceName, "rule.*", map[string]string{ - "name": "rule-1", - "action.#": "1", - "action.0.allow.#": "0", - "action.0.block.#": "0", - "action.0.captcha.#": "1", + "name": "rule-1", + "action.#": "1", + "action.0.allow.#": "0", + "action.0.block.#": "0", + "action.0.captcha.#": "1", + "action.0.challenge.#": "0", "action.0.captcha.0.custom_request_handling.#": "1", "action.0.captcha.0.custom_request_handling.0.insert_header.#": "2", "action.0.captcha.0.custom_request_handling.0.insert_header.0.name": "x-hdr1", @@ -1547,6 +1552,33 @@ func TestAccWAFV2WebACL_Custom_requestHandling(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "visibility_config.0.sampled_requests_enabled", "false"), ), }, + { + Config: testAccWebACLConfig_customRequestHandlingChallenge(webACLName), + Check: resource.ComposeTestCheckFunc( + testAccCheckWebACLExists(resourceName, &v), + acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/webacl/.+$`)), + resource.TestCheckResourceAttr(resourceName, "name", webACLName), + resource.TestCheckResourceAttr(resourceName, "default_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.allow.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.block.#", "0"), + resource.TestCheckResourceAttr(resourceName, "scope", "REGIONAL"), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "rule.*", map[string]string{ + "name": "rule-1", + "action.#": "1", + "action.0.allow.#": "0", + "action.0.block.#": "0", + "action.0.captcha.#": "0", + "action.0.challenge.#": "1", + "action.0.count.#": "0", + "priority": "1", + }), + resource.TestCheckResourceAttr(resourceName, "visibility_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "visibility_config.0.cloudwatch_metrics_enabled", "false"), + resource.TestCheckResourceAttr(resourceName, "visibility_config.0.metric_name", "friendly-metric-name"), + resource.TestCheckResourceAttr(resourceName, "visibility_config.0.sampled_requests_enabled", "false"), + ), + }, }, }) } @@ -2383,6 +2415,48 @@ resource "aws_wafv2_web_acl" "test" { `, name, firstHeader, secondHeader) } +func testAccWebACLConfig_customRequestHandlingChallenge(name string) string { + return fmt.Sprintf(` +resource "aws_wafv2_web_acl" "test" { + name = %[1]q + description = %[1]q + scope = "REGIONAL" + + default_action { + allow {} + } + + rule { + name = "rule-1" + priority = 1 + + action { + challenge {} + } + } + + statement { + geo_match_statement { + country_codes = ["US", "CA"] + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-rule-metric-name" + sampled_requests_enabled = false + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-metric-name" + sampled_requests_enabled = false + } +} +`, name) +} + func testAccWebACLConfig_customRequestHandlingCount(name, firstHeader string, secondHeader string) string { return fmt.Sprintf(` resource "aws_wafv2_web_acl" "test" { diff --git a/website/docs/r/wafv2_web_acl.html.markdown b/website/docs/r/wafv2_web_acl.html.markdown index ab8189743ea..a5aebd4b9a0 100644 --- a/website/docs/r/wafv2_web_acl.html.markdown +++ b/website/docs/r/wafv2_web_acl.html.markdown @@ -3,7 +3,7 @@ subcategory: "WAF" layout: "aws" page_title: "AWS: aws_wafv2_web_acl" description: |- - Creates a WAFv2 Web ACL resource. +Creates a WAFv2 Web ACL resource. --- # Resource: aws_wafv2_web_acl @@ -318,6 +318,7 @@ The `action` block supports the following arguments: * `allow` - (Optional) Instructs AWS WAF to allow the web request. See [Allow](#action) below for details. * `block` - (Optional) Instructs AWS WAF to block the web request. See [Block](#block) below for details. * `captcha` - (Optional) Instructs AWS WAF to run a Captcha check against the web request. See [Captcha](#captcha) below for details. +* `challenge` - (Optional) Instructs AWS WAF to run a check against the request to verify that the request is coming from a legitimate client session. See [Challenge](#challenge) below for details. * `count` - (Optional) Instructs AWS WAF to count the web request and allow it. See [Count](#count) below for details. ### Override Action @@ -347,6 +348,13 @@ The `captcha` block supports the following arguments: * `custom_request_handling` - (Optional) Defines custom handling for the web request. See [Custom Request Handling](#custom-request-handling) below for details. +### Challenge + +The `challenge` block supports the following arguments: + +* `custom_request_handling` - (Optional) Defines custom handling for the web request. See [Custom Request Handling](#custom-request-handling) below for details. + + ### Count The `count` block supports the following arguments: