From bf2cce9607744722907295eaf974d07e3e3ed2c1 Mon Sep 17 00:00:00 2001 From: Andy Alm Date: Thu, 27 May 2021 17:11:46 -0700 Subject: [PATCH 1/6] Added support for label_match_statement rules as well as assigning labels to rules --- aws/resource_aws_wafv2_rule_group.go | 1 + aws/resource_aws_wafv2_rule_group_test.go | 214 ++++++++++++++++++++ aws/resource_aws_wafv2_web_acl.go | 20 +- aws/resource_aws_wafv2_web_acl_test.go | 235 ++++++++++++++++++++++ aws/wafv2_helper.go | 127 +++++++++++- 5 files changed, 595 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_wafv2_rule_group.go b/aws/resource_aws_wafv2_rule_group.go index 3543e7dbb8c..eaca8102d6e 100644 --- a/aws/resource_aws_wafv2_rule_group.go +++ b/aws/resource_aws_wafv2_rule_group.go @@ -101,6 +101,7 @@ func resourceAwsWafv2RuleGroup() *schema.Resource { Type: schema.TypeInt, Required: true, }, + "rule_label": wafv2RuleLabelsSchema(), "statement": wafv2RootStatementSchema(3), "visibility_config": wafv2VisibilityConfigSchema(), }, diff --git a/aws/resource_aws_wafv2_rule_group_test.go b/aws/resource_aws_wafv2_rule_group_test.go index 39fa6ccee12..3fa17d161b3 100644 --- a/aws/resource_aws_wafv2_rule_group_test.go +++ b/aws/resource_aws_wafv2_rule_group_test.go @@ -745,6 +745,51 @@ func TestAccAwsWafv2RuleGroup_Disappears(t *testing.T) { }) } +func TestAccAwsWafv2RuleGroup_RuleLabels(t *testing.T) { + var v wafv2.RuleGroup + ruleGroupName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_wafv2_rule_group.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSWafv2ScopeRegional(t) }, + ErrorCheck: testAccErrorCheck(t, wafv2.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsWafv2RuleGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAwsWafv2RuleGroupConfig_RuleLabels(ruleGroupName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2RuleGroupExists(resourceName, &v), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "rule.*", map[string]string{ + "rule_label.#": "2", + "rule_label.0.name": "Hashicorp:Test:Label1", + "rule_label.1.name": "Hashicorp:Test:Label2", + }), + ), + }, + { + Config: testAccAwsWafv2RuleGroupConfig_NoRuleLabels(ruleGroupName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2RuleGroupExists(resourceName, &v), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "rule.*", map[string]string{ + "rule_label.#": "0", + }), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateIdFunc: testAccAwsWafv2RuleGroupImportStateIdFunc(resourceName), + }, + }, + }) +} + func TestAccAwsWafv2RuleGroup_GeoMatchStatement(t *testing.T) { var v wafv2.RuleGroup ruleGroupName := acctest.RandomWithPrefix("tf-acc-test") @@ -856,6 +901,55 @@ func TestAccAwsWafv2RuleGroup_GeoMatchStatement_ForwardedIPConfig(t *testing.T) }) } +func TestAccAwsWafv2RuleGroup_LabelMatchStatement(t *testing.T) { + var v wafv2.RuleGroup + ruleGroupName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_wafv2_rule_group.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSWafv2ScopeRegional(t) }, + ErrorCheck: testAccErrorCheck(t, wafv2.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsWafv2RuleGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAwsWafv2RuleGroupConfig_LabelMatchStatement(ruleGroupName, "LABEL", "Hashicorp:Test:Label1"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2RuleGroupExists(resourceName, &v), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "rule.*", map[string]string{ + "statement.#": "1", + "statement.0.label_match_statement.#": "1", + "statement.0.label_match_statement.0.scope": "LABEL", + "statement.0.label_match_statement.0.key": "Hashicorp:Test:Label1", + }), + ), + }, + { + Config: testAccAwsWafv2RuleGroupConfig_LabelMatchStatement(ruleGroupName, "NAMESPACE", "awswaf:managed:aws:bot-control:"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2RuleGroupExists(resourceName, &v), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "rule.*", map[string]string{ + "statement.#": "1", + "statement.0.label_match_statement.#": "1", + "statement.0.label_match_statement.0.scope": "NAMESPACE", + "statement.0.label_match_statement.0.key": "awswaf:managed:aws:bot-control:", + }), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateIdFunc: testAccAwsWafv2RuleGroupImportStateIdFunc(resourceName), + }, + }, + }) +} + func TestAccAwsWafv2RuleGroup_IpSetReferenceStatement(t *testing.T) { var v wafv2.RuleGroup ruleGroupName := acctest.RandomWithPrefix("tf-acc-test") @@ -2736,6 +2830,126 @@ resource "aws_wafv2_rule_group" "test" { `, name) } +func testAccAwsWafv2RuleGroupConfig_LabelMatchStatement(name string, scope string, key string) string { + return fmt.Sprintf(` +resource "aws_wafv2_rule_group" "test" { + capacity = 2 + name = "%[1]s" + scope = "REGIONAL" + + rule { + name = "rule-1" + priority = 1 + + action { + allow {} + } + + statement { + label_match_statement { + scope = "%[2]s" + key = "%[3]s" + } + } + + 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, scope, key) +} + +func testAccAwsWafv2RuleGroupConfig_RuleLabels(name string) string { + return fmt.Sprintf(` +resource "aws_wafv2_rule_group" "test" { + capacity = 2 + name = "%s" + scope = "REGIONAL" + + rule { + name = "rule-1" + priority = 1 + + action { + allow {} + } + + rule_label { + name = "Hashicorp:Test:Label1" + } + + rule_label { + name = "Hashicorp:Test:Label2" + } + + statement { + geo_match_statement { + country_codes = ["US", "NL"] + } + } + + 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 testAccAwsWafv2RuleGroupConfig_NoRuleLabels(name string) string { + return fmt.Sprintf(` +resource "aws_wafv2_rule_group" "test" { + capacity = 2 + name = "%s" + scope = "REGIONAL" + + rule { + name = "rule-1" + priority = 1 + + action { + allow {} + } + + statement { + geo_match_statement { + country_codes = ["US", "NL"] + } + } + + 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 testAccAwsWafv2RuleGroupConfig_LogicalRuleStatement_And(name string) string { return fmt.Sprintf(` resource "aws_wafv2_rule_group" "test" { diff --git a/aws/resource_aws_wafv2_web_acl.go b/aws/resource_aws_wafv2_web_acl.go index ee635a360c9..bac4fd9e18a 100644 --- a/aws/resource_aws_wafv2_web_acl.go +++ b/aws/resource_aws_wafv2_web_acl.go @@ -128,6 +128,7 @@ func resourceAwsWafv2WebACL() *schema.Resource { Type: schema.TypeInt, Required: true, }, + "rule_label": wafv2RuleLabelsSchema(), "statement": wafv2WebACLRootStatementSchema(3), "visibility_config": wafv2VisibilityConfigSchema(), }, @@ -359,6 +360,7 @@ func wafv2WebACLRootStatementSchema(level int) *schema.Schema { "byte_match_statement": wafv2ByteMatchStatementSchema(), "geo_match_statement": wafv2GeoMatchStatementSchema(), "ip_set_reference_statement": wafv2IpSetReferenceStatementSchema(), + "label_match_statement": wafv2LabelMatchStatementSchema(), "managed_rule_group_statement": wafv2ManagedRuleGroupStatementSchema(), "not_statement": wafv2StatementSchema(level), "or_statement": wafv2StatementSchema(level), @@ -448,6 +450,7 @@ func wafv2ScopeDownStatementSchema(level int) *schema.Schema { "and_statement": wafv2StatementSchema(level), "byte_match_statement": wafv2ByteMatchStatementSchema(), "geo_match_statement": wafv2GeoMatchStatementSchema(), + "label_match_statement": wafv2LabelMatchStatementSchema(), "ip_set_reference_statement": wafv2IpSetReferenceStatementSchema(), "not_statement": wafv2StatementSchema(level), "or_statement": wafv2StatementSchema(level), @@ -500,7 +503,7 @@ func expandWafv2WebACLRule(m map[string]interface{}) *wafv2.Rule { return nil } - return &wafv2.Rule{ + rule := &wafv2.Rule{ Name: aws.String(m["name"].(string)), Priority: aws.Int64(int64(m["priority"].(int))), Action: expandWafv2RuleAction(m["action"].([]interface{})), @@ -508,6 +511,12 @@ func expandWafv2WebACLRule(m map[string]interface{}) *wafv2.Rule { Statement: expandWafv2WebACLRootStatement(m["statement"].([]interface{})), VisibilityConfig: expandWafv2VisibilityConfig(m["visibility_config"].([]interface{})), } + + if v, ok := m["rule_label"].(*schema.Set); ok { + rule.RuleLabels = expandWafv2RuleLabels(v.List()) + } + + return rule } func expandWafv2OverrideAction(l []interface{}) *wafv2.OverrideAction { @@ -581,6 +590,10 @@ func expandWafv2WebACLStatement(m map[string]interface{}) *wafv2.Statement { statement.GeoMatchStatement = expandWafv2GeoMatchStatement(v.([]interface{})) } + if v, ok := m["label_match_statement"]; ok { + statement.LabelMatchStatement = expandWafv2LabelMatchStatement(v.([]interface{})) + } + if v, ok := m["managed_rule_group_statement"]; ok { statement.ManagedRuleGroupStatement = expandWafv2ManagedRuleGroupStatement(v.([]interface{})) } @@ -727,6 +740,10 @@ func flattenWafv2WebACLStatement(s *wafv2.Statement) map[string]interface{} { m["geo_match_statement"] = flattenWafv2GeoMatchStatement(s.GeoMatchStatement) } + if s.LabelMatchStatement != nil { + m["label_match_statement"] = flattenWafv2LabelMatchStatement(s.LabelMatchStatement) + } + if s.ManagedRuleGroupStatement != nil { m["managed_rule_group_statement"] = flattenWafv2ManagedRuleGroupStatement(s.ManagedRuleGroupStatement) } @@ -774,6 +791,7 @@ func flattenWafv2WebACLRules(r []*wafv2.Rule) interface{} { m["override_action"] = flattenWafv2OverrideAction(rule.OverrideAction) m["name"] = aws.StringValue(rule.Name) m["priority"] = int(aws.Int64Value(rule.Priority)) + m["rule_label"] = flattenWafv2RuleLabels(rule.RuleLabels) m["statement"] = flattenWafv2WebACLRootStatement(rule.Statement) m["visibility_config"] = flattenWafv2VisibilityConfig(rule.VisibilityConfig) out[i] = m diff --git a/aws/resource_aws_wafv2_web_acl_test.go b/aws/resource_aws_wafv2_web_acl_test.go index 7451f528b19..816040b51ad 100644 --- a/aws/resource_aws_wafv2_web_acl_test.go +++ b/aws/resource_aws_wafv2_web_acl_test.go @@ -850,6 +850,104 @@ func TestAccAwsWafv2WebACL_GeoMatchStatement_ForwardedIPConfig(t *testing.T) { }) } +func TestAccAwsWafv2WebACL_LabelMatchStatement(t *testing.T) { + var v wafv2.WebACL + webACLName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_wafv2_web_acl.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSWafv2ScopeRegional(t) }, + ErrorCheck: testAccErrorCheck(t, wafv2.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsWafv2WebACLDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAwsWafv2WebACLConfig_LabelMatchStatement(webACLName, "LABEL", "Hashicorp:Test:Label1"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2WebACLExists(resourceName, &v), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/webacl/.+$`)), + resource.TestCheckResourceAttr(resourceName, "name", webACLName), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "rule.*", map[string]string{ + "statement.#": "1", + "statement.0.label_match_statement.#": "1", + "statement.0.label_match_statement.0.scope": "LABEL", + "statement.0.label_match_statement.0.key": "Hashicorp:Test:Label1", + }), + ), + }, + { + Config: testAccAwsWafv2WebACLConfig_LabelMatchStatement(webACLName, "NAMESPACE", "awswaf:managed:aws:bot-control:"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2WebACLExists(resourceName, &v), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/webacl/.+$`)), + resource.TestCheckResourceAttr(resourceName, "name", webACLName), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "rule.*", map[string]string{ + "statement.#": "1", + "statement.0.label_match_statement.#": "1", + "statement.0.label_match_statement.0.scope": "NAMESPACE", + "statement.0.label_match_statement.0.key": "awswaf:managed:aws:bot-control:", + }), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateIdFunc: testAccAwsWafv2WebACLImportStateIdFunc(resourceName), + }, + }, + }) +} + +func TestAccAwsWafv2WebACL_RuleLabels(t *testing.T) { + var v wafv2.WebACL + webACLName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_wafv2_web_acl.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSWafv2ScopeRegional(t) }, + ErrorCheck: testAccErrorCheck(t, wafv2.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsWafv2WebACLDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAwsWafv2WebACLConfig_RuleLabels(webACLName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2WebACLExists(resourceName, &v), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/webacl/.+$`)), + resource.TestCheckResourceAttr(resourceName, "name", webACLName), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "rule.*", map[string]string{ + "rule_label.#": "2", + "rule_label.0.name": "Hashicorp:Test:Label1", + "rule_label.1.name": "Hashicorp:Test:Label2", + }), + ), + }, + { + Config: testAccAwsWafv2WebACLConfig_NoRuleLabels(webACLName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2WebACLExists(resourceName, &v), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/webacl/.+$`)), + resource.TestCheckResourceAttr(resourceName, "name", webACLName), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "rule.*", map[string]string{ + "rule_label.#": "0", + }), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateIdFunc: testAccAwsWafv2WebACLImportStateIdFunc(resourceName), + }, + }, + }) +} + func TestAccAwsWafv2WebACL_IPSetReferenceStatement(t *testing.T) { var v wafv2.WebACL webACLName := acctest.RandomWithPrefix("tf-acc-test") @@ -1706,6 +1804,143 @@ resource "aws_wafv2_web_acl" "test" { `, name, countryCodes) } +func testAccAwsWafv2WebACLConfig_LabelMatchStatement(name, labelScope string, labelKey string) string { + return fmt.Sprintf(` +resource "aws_wafv2_web_acl" "test" { + name = "%[1]s" + description = "%[1]s" + scope = "REGIONAL" + + default_action { + allow {} + } + + rule { + name = "rule-1" + priority = 1 + + action { + count {} + } + + statement { + label_match_statement { + scope = "%[2]s" + key = "%[3]s" + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-rule-metric-name" + sampled_requests_enabled = false + } + } + + tags = { + Tag1 = "Value1" + Tag2 = "Value2" + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-metric-name" + sampled_requests_enabled = false + } +} +`, name, labelScope, labelKey) +} + +func testAccAwsWafv2WebACLConfig_RuleLabels(name string) string { + return fmt.Sprintf(` +resource "aws_wafv2_web_acl" "test" { + name = "%[1]s" + description = "%[1]s" + scope = "REGIONAL" + + default_action { + allow {} + } + + rule { + name = "rule-1" + priority = 1 + + action { + block {} + } + + rule_label { + name = "Hashicorp:Test:Label1" + } + + rule_label { + name = "Hashicorp:Test:Label2" + } + + 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 testAccAwsWafv2WebACLConfig_NoRuleLabels(name string) string { + return fmt.Sprintf(` +resource "aws_wafv2_web_acl" "test" { + name = "%[1]s" + description = "%[1]s" + scope = "REGIONAL" + + default_action { + allow {} + } + + rule { + name = "rule-1" + priority = 1 + + action { + block {} + } + + 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 testAccAwsWafv2WebACLConfig_CustomRequestHandling_Count(name, firstHeader string, secondHeader string) string { return fmt.Sprintf(` resource "aws_wafv2_web_acl" "test" { diff --git a/aws/wafv2_helper.go b/aws/wafv2_helper.go index 28107047530..bcedf916428 100644 --- a/aws/wafv2_helper.go +++ b/aws/wafv2_helper.go @@ -33,6 +33,25 @@ func wafv2EmptySchemaDeprecated() *schema.Schema { } } +func wafv2RuleLabelsSchema() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 1024), + validation.StringMatch(regexp.MustCompile(`^[0-9A-Za-z_\-:]+$`), "must contain only alphanumeric, underscore, hyphen, and colon characters"), + ), + }, + }, + }, + } +} + func wafv2RootStatementSchema(level int) *schema.Schema { return &schema.Schema{ Type: schema.TypeList, @@ -44,6 +63,7 @@ func wafv2RootStatementSchema(level int) *schema.Schema { "byte_match_statement": wafv2ByteMatchStatementSchema(), "geo_match_statement": wafv2GeoMatchStatementSchema(), "ip_set_reference_statement": wafv2IpSetReferenceStatementSchema(), + "label_match_statement": wafv2LabelMatchStatementSchema(), "not_statement": wafv2StatementSchema(level - 1), "or_statement": wafv2StatementSchema(level - 1), "regex_pattern_set_reference_statement": wafv2RegexPatternSetReferenceStatementSchema(), @@ -72,6 +92,7 @@ func wafv2StatementSchema(level int) *schema.Schema { "byte_match_statement": wafv2ByteMatchStatementSchema(), "geo_match_statement": wafv2GeoMatchStatementSchema(), "ip_set_reference_statement": wafv2IpSetReferenceStatementSchema(), + "label_match_statement": wafv2LabelMatchStatementSchema(), "not_statement": wafv2StatementSchema(level - 1), "or_statement": wafv2StatementSchema(level - 1), "regex_pattern_set_reference_statement": wafv2RegexPatternSetReferenceStatementSchema(), @@ -100,6 +121,7 @@ func wafv2StatementSchema(level int) *schema.Schema { "byte_match_statement": wafv2ByteMatchStatementSchema(), "geo_match_statement": wafv2GeoMatchStatementSchema(), "ip_set_reference_statement": wafv2IpSetReferenceStatementSchema(), + "label_match_statement": wafv2LabelMatchStatementSchema(), "regex_pattern_set_reference_statement": wafv2RegexPatternSetReferenceStatementSchema(), "size_constraint_statement": wafv2SizeConstraintSchema(), "sqli_match_statement": wafv2SqliMatchStatementSchema(), @@ -205,6 +227,31 @@ func wafv2IpSetReferenceStatementSchema() *schema.Schema { } } +func wafv2LabelMatchStatementSchema() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "key": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 1024), + validation.StringMatch(regexp.MustCompile(`^[0-9A-Za-z_\-:]+$`), "must contain only alphanumeric, underscore, hyphen, and colon characters"), + ), + }, + "scope": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(wafv2.LabelMatchScope_Values(), false), + }, + }, + }, + } +} + func wafv2RegexPatternSetReferenceStatementSchema() *schema.Schema { return &schema.Schema{ Type: schema.TypeList, @@ -550,13 +597,39 @@ func expandWafv2Rule(m map[string]interface{}) *wafv2.Rule { return nil } - return &wafv2.Rule{ + rule := &wafv2.Rule{ Name: aws.String(m["name"].(string)), Priority: aws.Int64(int64(m["priority"].(int))), Action: expandWafv2RuleAction(m["action"].([]interface{})), Statement: expandWafv2RootStatement(m["statement"].([]interface{})), VisibilityConfig: expandWafv2VisibilityConfig(m["visibility_config"].([]interface{})), } + + if v, ok := m["rule_label"].(*schema.Set); ok { + rule.RuleLabels = expandWafv2RuleLabels(v.List()) + } + + return rule +} + +func expandWafv2RuleLabels(l []interface{}) []*wafv2.Label { + if len(l) == 0 || l[0] == nil { + return nil + } + + labels := make([]*wafv2.Label, 0) + + for _, label := range l { + if label == nil { + continue + } + m := label.(map[string]interface{}) + labels = append(labels, &wafv2.Label{ + Name: aws.String(m["name"].(string)), + }) + } + + return labels } func expandWafv2RuleAction(l []interface{}) *wafv2.RuleAction { @@ -771,6 +844,10 @@ func expandWafv2Statement(m map[string]interface{}) *wafv2.Statement { statement.GeoMatchStatement = expandWafv2GeoMatchStatement(v.([]interface{})) } + if v, ok := m["label_match_statement"]; ok { + statement.LabelMatchStatement = expandWafv2LabelMatchStatement(v.([]interface{})) + } + if v, ok := m["not_statement"]; ok { statement.NotStatement = expandWafv2NotStatement(v.([]interface{})) } @@ -979,6 +1056,21 @@ func expandWafv2GeoMatchStatement(l []interface{}) *wafv2.GeoMatchStatement { return statement } +func expandWafv2LabelMatchStatement(l []interface{}) *wafv2.LabelMatchStatement { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + + statement := &wafv2.LabelMatchStatement{ + Key: aws.String(m["key"].(string)), + Scope: aws.String(m["scope"].(string)), + } + + return statement +} + func expandWafv2NotStatement(l []interface{}) *wafv2.NotStatement { if len(l) == 0 || l[0] == nil { return nil @@ -1072,6 +1164,7 @@ func flattenWafv2Rules(r []*wafv2.Rule) interface{} { m["action"] = flattenWafv2RuleAction(rule.Action) m["name"] = aws.StringValue(rule.Name) m["priority"] = int(aws.Int64Value(rule.Priority)) + m["rule_label"] = flattenWafv2RuleLabels(rule.RuleLabels) m["statement"] = flattenWafv2RootStatement(rule.Statement) m["visibility_config"] = flattenWafv2VisibilityConfig(rule.VisibilityConfig) out[i] = m @@ -1189,6 +1282,21 @@ func flattenWafv2CustomHeader(h *wafv2.CustomHTTPHeader) map[string]interface{} return m } +func flattenWafv2RuleLabels(l []*wafv2.Label) []interface{} { + if l == nil || len(l) == 0 { + return nil + } + + out := make([]interface{}, len(l)) + for i, label := range l { + out[i] = map[string]interface{}{ + "name": aws.StringValue(label.Name), + } + } + + return out +} + func flattenWafv2RootStatement(s *wafv2.Statement) interface{} { if s == nil { return []interface{}{} @@ -1229,6 +1337,10 @@ func flattenWafv2Statement(s *wafv2.Statement) map[string]interface{} { m["geo_match_statement"] = flattenWafv2GeoMatchStatement(s.GeoMatchStatement) } + if s.LabelMatchStatement != nil { + m["label_match_statement"] = flattenWafv2LabelMatchStatement(s.LabelMatchStatement) + } + if s.NotStatement != nil { m["not_statement"] = flattenWafv2NotStatement(s.NotStatement) } @@ -1409,6 +1521,19 @@ func flattenWafv2GeoMatchStatement(g *wafv2.GeoMatchStatement) interface{} { return []interface{}{m} } +func flattenWafv2LabelMatchStatement(l *wafv2.LabelMatchStatement) interface{} { + if l == nil { + return []interface{}{} + } + + m := map[string]interface{}{ + "key": aws.StringValue(l.Key), + "scope": aws.StringValue(l.Scope), + } + + return []interface{}{m} +} + func flattenWafv2NotStatement(a *wafv2.NotStatement) interface{} { if a == nil { return []interface{}{} From 903e04b7eff574a4924e83633539057d8fa925e8 Mon Sep 17 00:00:00 2001 From: Andy Alm Date: Fri, 28 May 2021 15:13:35 -0700 Subject: [PATCH 2/6] Added documentation for `rule_label` and `label_match_statement` to the wafv2 rule_group and web_acl resources. --- website/docs/r/wafv2_rule_group.html.markdown | 15 +++++++++++++++ website/docs/r/wafv2_web_acl.html.markdown | 15 +++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/website/docs/r/wafv2_rule_group.html.markdown b/website/docs/r/wafv2_rule_group.html.markdown index a8432218bf1..7a80b3eefdf 100644 --- a/website/docs/r/wafv2_rule_group.html.markdown +++ b/website/docs/r/wafv2_rule_group.html.markdown @@ -300,6 +300,7 @@ Each `rule` supports the following arguments: * `action` - (Required) The action that AWS WAF should take on a web request when it matches the rule's statement. Settings at the `aws_wafv2_web_acl` level can override the rule action setting. See [Action](#action) below for details. * `name` - (Required, Forces new resource) A friendly name of the rule. * `priority` - (Required) If you define more than one Rule in a WebACL, AWS WAF evaluates each request against the `rules` in order based on the value of `priority`. AWS WAF processes rules with lower priority first. +* `rule_label` - (Optional) Labels to apply to web requests that match the rule match statement. See [Rule Label](#rule-label) below for details. * `statement` - (Required) The AWS WAF processing statement for the rule, for example `byte_match_statement` or `geo_match_statement`. See [Statement](#statement) below for details. * `visibility_config` - (Required) Defines and enables Amazon CloudWatch metrics and web request sample collection. See [Visibility Configuration](#visibility-configuration) below for details. @@ -351,6 +352,12 @@ Each block supports the following arguments. Duplicate header names are not allo * `name` - The name of the custom header. For custom request header insertion, when AWS WAF inserts the header into the request, it prefixes this name `x-amzn-waf-`, to avoid confusion with the headers that are already in the request. For example, for the header name `sample`, AWS WAF inserts the header `x-amzn-waf-sample`. * `value` - The value of the custom header. +### Rule Label + +Each block supports the following arguments: + +* `name` - The label string. + ### Statement The processing guidance for a Rule, used by AWS WAF to determine whether a web request matches the rule. See the [documentation](https://docs.aws.amazon.com/waf/latest/developerguide/waf-rule-statements-list.html) for more information. @@ -362,6 +369,7 @@ The `statement` block supports the following arguments: * `and_statement` - (Optional) A logical rule statement used to combine other rule statements with AND logic. See [AND Statement](#and-statement) below for details. * `byte_match_statement` - (Optional) A rule statement that defines a string match search for AWS WAF to apply to web requests. See [Byte Match Statement](#byte-match-statement) below for details. * `geo_match_statement` - (Optional) A rule statement used to identify web requests based on country of origin. See [GEO Match Statement](#geo-match-statement) below for details. +* `label_match_statement` - (Optional) A rule statement that defines a string match search against labels that have been added to the web request by rules that have already run in the web ACL. See [Label Match Statement](#label-match-statement) below for details. * `ip_set_reference_statement` - (Optional) A rule statement used to detect web requests coming from particular IP addresses or address ranges. See [IP Set Reference Statement](#ip-set-reference-statement) below for details. * `not_statement` - (Optional) A logical rule statement used to negate the results of another rule statement. See [NOT Statement](#not-statement) below for details. * `or_statement` - (Optional) A logical rule statement used to combine other rule statements with OR logic. See [OR Statement](#or-statement) below for details. @@ -396,6 +404,13 @@ The `geo_match_statement` block supports the following arguments: * `country_codes` - (Required) An array of two-character country codes, for example, [ "US", "CN" ], from the alpha-2 country ISO codes of the `ISO 3166` international standard. See the [documentation](https://docs.aws.amazon.com/waf/latest/APIReference/API_GeoMatchStatement.html) for valid values. * `forwarded_ip_config` - (Optional) The configuration for inspecting IP addresses in an HTTP header that you specify, instead of using the IP address that's reported by the web request origin. See [Forwarded IP Config](#forwarded-ip-config) below for details. +### Label Match Statement + +The `label_match_statement` block supports the following arguments: + +* `scope` - (Required) Specify whether you want to match using the label name or just the namespace. Valid values are `LABEL` or `NAMESPACE`. +* `key` - (Required) The string to match against. + ### IP Set Reference Statement A rule statement used to detect web requests coming from particular IP addresses or address ranges. To use this, create an `aws_wafv2_ip_set` that specifies the addresses you want to detect, then use the `ARN` of that set in this statement. diff --git a/website/docs/r/wafv2_web_acl.html.markdown b/website/docs/r/wafv2_web_acl.html.markdown index 14640f4fc27..e34a5b5204a 100644 --- a/website/docs/r/wafv2_web_acl.html.markdown +++ b/website/docs/r/wafv2_web_acl.html.markdown @@ -282,6 +282,7 @@ Each `rule` supports the following arguments: * `name` - (Required) A friendly name of the rule. * `override_action` - (Optional) The override action to apply to the rules in a rule group. Used only for rule **statements that reference a rule group**, like `rule_group_reference_statement` and `managed_rule_group_statement`. See [Override Action](#override-action) below for details. * `priority` - (Required) If you define more than one Rule in a WebACL, AWS WAF evaluates each request against the `rules` in order based on the value of `priority`. AWS WAF processes rules with lower priority first. +* `rule_label` - (Optional) Labels to apply to web requests that match the rule match statement. See [Rule Label](#rule-label) below for details. * `statement` - (Required) The AWS WAF processing statement for the rule, for example `byte_match_statement` or `geo_match_statement`. See [Statement](#statement) below for details. * `visibility_config` - (Required) Defines and enables Amazon CloudWatch metrics and web request sample collection. See [Visibility Configuration](#visibility-configuration) below for details. @@ -342,6 +343,12 @@ Each block supports the following arguments. Duplicate header names are not allo * `name` - The name of the custom header. For custom request header insertion, when AWS WAF inserts the header into the request, it prefixes this name `x-amzn-waf-`, to avoid confusion with the headers that are already in the request. For example, for the header name `sample`, AWS WAF inserts the header `x-amzn-waf-sample`. * `value` - The value of the custom header. +### Rule Label + +Each block supports the following arguments: + +* `name` - The label string. + ### Statement The processing guidance for a Rule, used by AWS WAF to determine whether a web request matches the rule. See the [documentation](https://docs.aws.amazon.com/waf/latest/developerguide/waf-rule-statements-list.html) for more information. @@ -354,6 +361,7 @@ The `statement` block supports the following arguments: * `byte_match_statement` - (Optional) A rule statement that defines a string match search for AWS WAF to apply to web requests. See [Byte Match Statement](#byte-match-statement) below for details. * `geo_match_statement` - (Optional) A rule statement used to identify web requests based on country of origin. See [GEO Match Statement](#geo-match-statement) below for details. * `ip_set_reference_statement` - (Optional) A rule statement used to detect web requests coming from particular IP addresses or address ranges. See [IP Set Reference Statement](#ip-set-reference-statement) below for details. +* `label_match_statement` - (Optional) A rule statement that defines a string match search against labels that have been added to the web request by rules that have already run in the web ACL. See [Label Match Statement](#label-match-statement) below for details. * `managed_rule_group_statement` - (Optional) A rule statement used to run the rules that are defined in a managed rule group. This statement can not be nested. See [Managed Rule Group Statement](#managed-rule-group-statement) below for details. * `not_statement` - (Optional) A logical rule statement used to negate the results of another rule statement. See [NOT Statement](#not-statement) below for details. * `or_statement` - (Optional) A logical rule statement used to combine other rule statements with OR logic. See [OR Statement](#or-statement) below for details. @@ -400,6 +408,13 @@ The `ip_set_reference_statement` block supports the following arguments: * `arn` - (Required) The Amazon Resource Name (ARN) of the IP Set that this statement references. * `ip_set_forwarded_ip_config` - (Optional) The configuration for inspecting IP addresses in an HTTP header that you specify, instead of using the IP address that's reported by the web request origin. See [IPSet Forwarded IP Config](#ipset-forwarded-ip-config) below for more details. +### Label Match Statement + +The `label_match_statement` block supports the following arguments: + +* `scope` - (Required) Specify whether you want to match using the label name or just the namespace. Valid values are `LABEL` or `NAMESPACE`. +* `key` - (Required) The string to match against. + ### Managed Rule Group Statement A rule statement used to run the rules that are defined in a managed rule group. From 22724df1f2f6a681c52c56d345c86939e9bdb1b1 Mon Sep 17 00:00:00 2001 From: Andy Alm Date: Fri, 28 May 2021 15:48:52 -0700 Subject: [PATCH 3/6] Added the changelog for the pull request (#19576) --- .changelog/19576.txt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 .changelog/19576.txt diff --git a/.changelog/19576.txt b/.changelog/19576.txt new file mode 100644 index 00000000000..467982cb322 --- /dev/null +++ b/.changelog/19576.txt @@ -0,0 +1,15 @@ +```release-notes:enhancement +resource/aws_wafv2_web_acl: Add `rule_label` to rules. +``` + +```release-notes:enhancement +resource/aws_wafv2_web_acl: Added support for `label_match_statement` to rules. +``` + +```release-notes:enhancement +resource/aws_wafv2_rule_group: Add `rule_label` to rules. +``` + +```release-notes:enhancement +resource/aws_wafv2_rule_group: Added support for `label_match_statement` to rules. +``` \ No newline at end of file From 78bc41d54a78ee87667ff2e0004d975acfcd4d01 Mon Sep 17 00:00:00 2001 From: Andy Alm Date: Fri, 28 May 2021 16:35:57 -0700 Subject: [PATCH 4/6] Fix linting error --- aws/wafv2_helper.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/wafv2_helper.go b/aws/wafv2_helper.go index bcedf916428..245de816a0d 100644 --- a/aws/wafv2_helper.go +++ b/aws/wafv2_helper.go @@ -1283,7 +1283,7 @@ func flattenWafv2CustomHeader(h *wafv2.CustomHTTPHeader) map[string]interface{} } func flattenWafv2RuleLabels(l []*wafv2.Label) []interface{} { - if l == nil || len(l) == 0 { + if len(l) == 0 { return nil } From f474198ba5849662592bd992dd7cac9d4fd6a67f Mon Sep 17 00:00:00 2001 From: Andy Alm Date: Fri, 12 Nov 2021 06:59:05 -0800 Subject: [PATCH 5/6] Fixed linting errors from naming convention changes --- internal/service/wafv2/rule_group_test.go | 18 +++++++++--------- internal/service/wafv2/web_acl_test.go | 18 +++++++++--------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/internal/service/wafv2/rule_group_test.go b/internal/service/wafv2/rule_group_test.go index 1de42c97894..fec7eab3ac6 100644 --- a/internal/service/wafv2/rule_group_test.go +++ b/internal/service/wafv2/rule_group_test.go @@ -684,7 +684,7 @@ func TestAccWAFV2RuleGroup_disappears(t *testing.T) { }) } -func TestAccAwsWafv2RuleGroup_RuleLabels(t *testing.T) { +func TestAccWAFV2RuleGroup_RuleLabels(t *testing.T) { var v wafv2.RuleGroup ruleGroupName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_wafv2_rule_group.test" @@ -696,7 +696,7 @@ func TestAccAwsWafv2RuleGroup_RuleLabels(t *testing.T) { CheckDestroy: testAccCheckRuleGroupDestroy, Steps: []resource.TestStep{ { - Config: testAccAwsWafv2RuleGroupConfig_RuleLabels(ruleGroupName), + Config: testAccRuleGroupConfig_RuleLabels(ruleGroupName), Check: resource.ComposeTestCheckFunc( testAccCheckRuleGroupExists(resourceName, &v), acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), @@ -709,7 +709,7 @@ func TestAccAwsWafv2RuleGroup_RuleLabels(t *testing.T) { ), }, { - Config: testAccAwsWafv2RuleGroupConfig_NoRuleLabels(ruleGroupName), + Config: testAccRuleGroupConfig_NoRuleLabels(ruleGroupName), Check: resource.ComposeTestCheckFunc( testAccCheckRuleGroupExists(resourceName, &v), acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), @@ -840,7 +840,7 @@ func TestAccWAFV2RuleGroup_GeoMatchStatement_forwardedIP(t *testing.T) { }) } -func TestAccAwsWafv2RuleGroup_LabelMatchStatement(t *testing.T) { +func TestAccWAFV2RuleGroup_LabelMatchStatement(t *testing.T) { var v wafv2.RuleGroup ruleGroupName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_wafv2_rule_group.test" @@ -852,7 +852,7 @@ func TestAccAwsWafv2RuleGroup_LabelMatchStatement(t *testing.T) { CheckDestroy: testAccCheckRuleGroupDestroy, Steps: []resource.TestStep{ { - Config: testAccAwsWafv2RuleGroupConfig_LabelMatchStatement(ruleGroupName, "LABEL", "Hashicorp:Test:Label1"), + Config: testAccRuleGroupConfig_LabelMatchStatement(ruleGroupName, "LABEL", "Hashicorp:Test:Label1"), Check: resource.ComposeTestCheckFunc( testAccCheckRuleGroupExists(resourceName, &v), acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), @@ -866,7 +866,7 @@ func TestAccAwsWafv2RuleGroup_LabelMatchStatement(t *testing.T) { ), }, { - Config: testAccAwsWafv2RuleGroupConfig_LabelMatchStatement(ruleGroupName, "NAMESPACE", "awswaf:managed:aws:bot-control:"), + Config: testAccRuleGroupConfig_LabelMatchStatement(ruleGroupName, "NAMESPACE", "awswaf:managed:aws:bot-control:"), Check: resource.ComposeTestCheckFunc( testAccCheckRuleGroupExists(resourceName, &v), acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), @@ -2769,7 +2769,7 @@ resource "aws_wafv2_rule_group" "test" { `, name) } -func testAccAwsWafv2RuleGroupConfig_LabelMatchStatement(name string, scope string, key string) string { +func testAccRuleGroupConfig_LabelMatchStatement(name string, scope string, key string) string { return fmt.Sprintf(` resource "aws_wafv2_rule_group" "test" { capacity = 2 @@ -2802,7 +2802,7 @@ resource "aws_wafv2_rule_group" "test" { `, name, scope, key) } -func testAccAwsWafv2RuleGroupConfig_RuleLabels(name string) string { +func testAccRuleGroupConfig_RuleLabels(name string) string { return fmt.Sprintf(` resource "aws_wafv2_rule_group" "test" { capacity = 2 @@ -2840,7 +2840,7 @@ resource "aws_wafv2_rule_group" "test" { `, name) } -func testAccAwsWafv2RuleGroupConfig_NoRuleLabels(name string) string { +func testAccRuleGroupConfig_NoRuleLabels(name string) string { return fmt.Sprintf(` resource "aws_wafv2_rule_group" "test" { capacity = 2 diff --git a/internal/service/wafv2/web_acl_test.go b/internal/service/wafv2/web_acl_test.go index c0ac33a2e24..37ce7bb857b 100644 --- a/internal/service/wafv2/web_acl_test.go +++ b/internal/service/wafv2/web_acl_test.go @@ -798,7 +798,7 @@ func TestAccWAFV2WebACL_GeoMatch_forwardedIP(t *testing.T) { }) } -func TestAccAwsWafv2WebACL_LabelMatchStatement(t *testing.T) { +func TestAccWAFV2WebACL_LabelMatchStatement(t *testing.T) { var v wafv2.WebACL webACLName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_wafv2_web_acl.test" @@ -810,7 +810,7 @@ func TestAccAwsWafv2WebACL_LabelMatchStatement(t *testing.T) { CheckDestroy: testAccCheckWebACLDestroy, Steps: []resource.TestStep{ { - Config: testAccAwsWafv2WebACLConfig_LabelMatchStatement(webACLName, "LABEL", "Hashicorp:Test:Label1"), + Config: testAccWebACLConfig_LabelMatchStatement(webACLName, "LABEL", "Hashicorp:Test:Label1"), Check: resource.ComposeTestCheckFunc( testAccCheckWebACLExists(resourceName, &v), acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/webacl/.+$`)), @@ -825,7 +825,7 @@ func TestAccAwsWafv2WebACL_LabelMatchStatement(t *testing.T) { ), }, { - Config: testAccAwsWafv2WebACLConfig_LabelMatchStatement(webACLName, "NAMESPACE", "awswaf:managed:aws:bot-control:"), + Config: testAccWebACLConfig_LabelMatchStatement(webACLName, "NAMESPACE", "awswaf:managed:aws:bot-control:"), Check: resource.ComposeTestCheckFunc( testAccCheckWebACLExists(resourceName, &v), acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/webacl/.+$`)), @@ -849,7 +849,7 @@ func TestAccAwsWafv2WebACL_LabelMatchStatement(t *testing.T) { }) } -func TestAccAwsWafv2WebACL_RuleLabels(t *testing.T) { +func TestAccWAFV2WebACL_RuleLabels(t *testing.T) { var v wafv2.WebACL webACLName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_wafv2_web_acl.test" @@ -861,7 +861,7 @@ func TestAccAwsWafv2WebACL_RuleLabels(t *testing.T) { CheckDestroy: testAccCheckWebACLDestroy, Steps: []resource.TestStep{ { - Config: testAccAwsWafv2WebACLConfig_RuleLabels(webACLName), + Config: testAccWebACLConfig_RuleLabels(webACLName), Check: resource.ComposeTestCheckFunc( testAccCheckWebACLExists(resourceName, &v), acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/webacl/.+$`)), @@ -875,7 +875,7 @@ func TestAccAwsWafv2WebACL_RuleLabels(t *testing.T) { ), }, { - Config: testAccAwsWafv2WebACLConfig_NoRuleLabels(webACLName), + Config: testAccWebACLConfig_NoRuleLabels(webACLName), Check: resource.ComposeTestCheckFunc( testAccCheckWebACLExists(resourceName, &v), acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/webacl/.+$`)), @@ -1752,7 +1752,7 @@ resource "aws_wafv2_web_acl" "test" { `, name, countryCodes) } -func testAccAwsWafv2WebACLConfig_LabelMatchStatement(name, labelScope string, labelKey string) string { +func testAccWebACLConfig_LabelMatchStatement(name, labelScope string, labelKey string) string { return fmt.Sprintf(` resource "aws_wafv2_web_acl" "test" { name = "%[1]s" @@ -1792,7 +1792,7 @@ resource "aws_wafv2_web_acl" "test" { `, name, labelScope, labelKey) } -func testAccAwsWafv2WebACLConfig_RuleLabels(name string) string { +func testAccWebACLConfig_RuleLabels(name string) string { return fmt.Sprintf(` resource "aws_wafv2_web_acl" "test" { name = "%[1]s" @@ -1833,7 +1833,7 @@ resource "aws_wafv2_web_acl" "test" { `, name) } -func testAccAwsWafv2WebACLConfig_NoRuleLabels(name string) string { +func testAccWebACLConfig_NoRuleLabels(name string) string { return fmt.Sprintf(` resource "aws_wafv2_web_acl" "test" { name = "%[1]s" From 6940e142ad7aa398ac46a2db5e026528f99cd218 Mon Sep 17 00:00:00 2001 From: Angie Pinilla Date: Mon, 22 Nov 2021 17:19:57 -0500 Subject: [PATCH 6/6] empty set check --- internal/service/wafv2/helper.go | 2 +- internal/service/wafv2/web_acl.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/service/wafv2/helper.go b/internal/service/wafv2/helper.go index ba45a580632..6ec9382754f 100644 --- a/internal/service/wafv2/helper.go +++ b/internal/service/wafv2/helper.go @@ -600,7 +600,7 @@ func expandWafv2Rule(m map[string]interface{}) *wafv2.Rule { VisibilityConfig: expandWafv2VisibilityConfig(m["visibility_config"].([]interface{})), } - if v, ok := m["rule_label"].(*schema.Set); ok { + if v, ok := m["rule_label"].(*schema.Set); ok && v.Len() > 0 { rule.RuleLabels = expandWafv2RuleLabels(v.List()) } diff --git a/internal/service/wafv2/web_acl.go b/internal/service/wafv2/web_acl.go index 26b9bfd6fa4..f199b4e04c1 100644 --- a/internal/service/wafv2/web_acl.go +++ b/internal/service/wafv2/web_acl.go @@ -516,7 +516,7 @@ func expandWafv2WebACLRule(m map[string]interface{}) *wafv2.Rule { VisibilityConfig: expandWafv2VisibilityConfig(m["visibility_config"].([]interface{})), } - if v, ok := m["rule_label"].(*schema.Set); ok { + if v, ok := m["rule_label"].(*schema.Set); ok && v.Len() > 0 { rule.RuleLabels = expandWafv2RuleLabels(v.List()) }