Skip to content

Commit

Permalink
Merge pull request #22452 from wilkmaia/main
Browse files Browse the repository at this point in the history
Add support for `regex_match_statement` to AWS WAF v2 ACL rules
  • Loading branch information
gdavison authored Oct 4, 2022
2 parents 3c92710 + 53aebe7 commit 4fe109e
Show file tree
Hide file tree
Showing 8 changed files with 281 additions and 21 deletions.
7 changes: 7 additions & 0 deletions .changelog/22452.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
```release-note:enhancement
resource/aws_wafv2_web_acl: Add support for `regex_match_statement`
```

```release-note:enhancement
resource/aws_wafv2_rule_group: Add support for `regex_match_statement`
```
44 changes: 44 additions & 0 deletions internal/service/wafv2/flex.go
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,10 @@ func expandStatement(m map[string]interface{}) *wafv2.Statement {
statement.OrStatement = expandOrStatement(v.([]interface{}))
}

if v, ok := m["regex_match_statement"]; ok {
statement.RegexMatchStatement = expandRegexMatchStatement(v.([]interface{}))
}

if v, ok := m["regex_pattern_set_reference_statement"]; ok {
statement.RegexPatternSetReferenceStatement = expandRegexPatternSetReferenceStatement(v.([]interface{}))
}
Expand Down Expand Up @@ -672,6 +676,20 @@ func expandOrStatement(l []interface{}) *wafv2.OrStatement {
}
}

func expandRegexMatchStatement(l []interface{}) *wafv2.RegexMatchStatement {
if len(l) == 0 || l[0] == nil {
return nil
}

m := l[0].(map[string]interface{})

return &wafv2.RegexMatchStatement{
RegexString: aws.String(m["regex_string"].(string)),
FieldToMatch: expandFieldToMatch(m["field_to_match"].([]interface{})),
TextTransformations: expandTextTransformations(m["text_transformation"].(*schema.Set).List()),
}
}

func expandRegexPatternSetReferenceStatement(l []interface{}) *wafv2.RegexPatternSetReferenceStatement {
if len(l) == 0 || l[0] == nil {
return nil
Expand Down Expand Up @@ -893,6 +911,10 @@ func expandWebACLStatement(m map[string]interface{}) *wafv2.Statement {
statement.RateBasedStatement = expandRateBasedStatement(v.([]interface{}))
}

if v, ok := m["regex_match_statement"]; ok {
statement.RegexMatchStatement = expandRegexMatchStatement(v.([]interface{}))
}

if v, ok := m["regex_pattern_set_reference_statement"]; ok {
statement.RegexPatternSetReferenceStatement = expandRegexPatternSetReferenceStatement(v.([]interface{}))
}
Expand Down Expand Up @@ -1261,6 +1283,10 @@ func flattenStatement(s *wafv2.Statement) map[string]interface{} {
m["or_statement"] = flattenOrStatement(s.OrStatement)
}

if s.RegexMatchStatement != nil {
m["regex_match_statement"] = flattenRegexMatchStatement(s.RegexMatchStatement)
}

if s.RegexPatternSetReferenceStatement != nil {
m["regex_pattern_set_reference_statement"] = flattenRegexPatternSetReferenceStatement(s.RegexPatternSetReferenceStatement)
}
Expand Down Expand Up @@ -1544,6 +1570,20 @@ func flattenOrStatement(a *wafv2.OrStatement) interface{} {
return []interface{}{m}
}

func flattenRegexMatchStatement(r *wafv2.RegexMatchStatement) interface{} {
if r == nil {
return []interface{}{}
}

m := map[string]interface{}{
"regex_string": aws.StringValue(r.RegexString),
"field_to_match": flattenFieldToMatch(r.FieldToMatch),
"text_transformation": flattenTextTransformations(r.TextTransformations),
}

return []interface{}{m}
}

func flattenRegexPatternSetReferenceStatement(r *wafv2.RegexPatternSetReferenceStatement) interface{} {
if r == nil {
return []interface{}{}
Expand Down Expand Up @@ -1700,6 +1740,10 @@ func flattenWebACLStatement(s *wafv2.Statement) map[string]interface{} {
m["rate_based_statement"] = flattenRateBasedStatement(s.RateBasedStatement)
}

if s.RegexMatchStatement != nil {
m["regex_match_statement"] = flattenRegexMatchStatement(s.RegexMatchStatement)
}

if s.RegexPatternSetReferenceStatement != nil {
m["regex_pattern_set_reference_statement"] = flattenRegexPatternSetReferenceStatement(s.RegexPatternSetReferenceStatement)
}
Expand Down
9 changes: 6 additions & 3 deletions internal/service/wafv2/regex_pattern_set.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,12 @@ func ResourceRegexPatternSet() *schema.Resource {
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"regex_string": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringLenBetween(1, 200),
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.All(
validation.StringLenBetween(1, 200),
validation.StringIsValidRegExp,
),
},
},
},
Expand Down
84 changes: 83 additions & 1 deletion internal/service/wafv2/rule_group_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1296,6 +1296,42 @@ func TestAccWAFV2RuleGroup_minimal(t *testing.T) {
})
}

func TestAccWAFV2RuleGroup_regexMatchStatement(t *testing.T) {
var v wafv2.RuleGroup
ruleGroupName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
resourceName := "aws_wafv2_rule_group.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(t); testAccPreCheckScopeRegional(t) },
ErrorCheck: acctest.ErrorCheck(t, wafv2.EndpointsID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckRuleGroupDestroy,
Steps: []resource.TestStep{
{
Config: testAccRuleGroupConfig_regexMatchStatement(ruleGroupName),
Check: resource.ComposeTestCheckFunc(
testAccCheckRuleGroupExists(resourceName, &v),
acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)),
resource.TestCheckResourceAttr(resourceName, "rule.#", "1"),
resource.TestCheckTypeSetElemNestedAttrs(resourceName, "rule.*", map[string]string{
"statement.#": "1",
"statement.0.regex_match_statement.#": "1",
"statement.0.regex_match_statement.0.regex_string": "[a-z]([a-z0-9_-]*[a-z0-9])?",
"statement.0.regex_match_statement.0.field_to_match.#": "1",
"statement.0.regex_match_statement.0.text_transformation.#": "1",
}),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateIdFunc: testAccRuleGroupImportStateIdFunc(resourceName),
},
},
})
}

func TestAccWAFV2RuleGroup_regexPatternSetReferenceStatement(t *testing.T) {
var v wafv2.RuleGroup
ruleGroupName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
Expand Down Expand Up @@ -3604,14 +3640,60 @@ resource "aws_wafv2_rule_group" "test" {
`, name)
}

func testAccRuleGroupConfig_regexMatchStatement(name string) string {
return fmt.Sprintf(`
resource "aws_wafv2_rule_group" "test" {
capacity = 50
name = "%s"
scope = "REGIONAL"
rule {
name = "rule-1"
priority = 1
action {
allow {}
}
statement {
regex_match_statement {
regex_string = "[a-z]([a-z0-9_-]*[a-z0-9])?"
field_to_match {
body {}
}
text_transformation {
priority = 2
type = "NONE"
}
}
}
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 testAccRuleGroupConfig_regexPatternSetReferenceStatement(name string) string {
return fmt.Sprintf(`
resource "aws_wafv2_regex_pattern_set" "test" {
name = "regex-pattern-set-%s"
scope = "REGIONAL"
regular_expression {
regex_string = "one"
regex_string = "[a-z]([a-z0-9_-]*[a-z0-9])?"
}
}
Expand Down
28 changes: 28 additions & 0 deletions internal/service/wafv2/schemas.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ func rootStatementSchema(level int) *schema.Schema {
"label_match_statement": labelMatchStatementSchema(),
"not_statement": statementSchema(level - 1),
"or_statement": statementSchema(level - 1),
"regex_match_statement": regexMatchStatementSchema(),
"regex_pattern_set_reference_statement": regexPatternSetReferenceStatementSchema(),
"size_constraint_statement": sizeConstraintSchema(),
"sqli_match_statement": sqliMatchStatementSchema(),
Expand Down Expand Up @@ -95,6 +96,7 @@ func statementSchema(level int) *schema.Schema {
"label_match_statement": labelMatchStatementSchema(),
"not_statement": statementSchema(level - 1),
"or_statement": statementSchema(level - 1),
"regex_match_statement": regexMatchStatementSchema(),
"regex_pattern_set_reference_statement": regexPatternSetReferenceStatementSchema(),
"size_constraint_statement": sizeConstraintSchema(),
"sqli_match_statement": sqliMatchStatementSchema(),
Expand Down Expand Up @@ -122,6 +124,7 @@ func statementSchema(level int) *schema.Schema {
"geo_match_statement": geoMatchStatementSchema(),
"ip_set_reference_statement": ipSetReferenceStatementSchema(),
"label_match_statement": labelMatchStatementSchema(),
"regex_match_statement": regexMatchStatementSchema(),
"regex_pattern_set_reference_statement": regexPatternSetReferenceStatementSchema(),
"size_constraint_statement": sizeConstraintSchema(),
"sqli_match_statement": sqliMatchStatementSchema(),
Expand Down Expand Up @@ -246,6 +249,28 @@ func labelMatchStatementSchema() *schema.Schema {
}
}

func regexMatchStatementSchema() *schema.Schema {
return &schema.Schema{
Type: schema.TypeList,
Optional: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"regex_string": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.All(
validation.StringLenBetween(1, 512),
validation.StringIsValidRegExp,
),
},
"field_to_match": fieldToMatchSchema(),
"text_transformation": textTransformationSchema(),
},
},
}
}

func regexPatternSetReferenceStatementSchema() *schema.Schema {
return &schema.Schema{
Type: schema.TypeList,
Expand Down Expand Up @@ -452,6 +477,7 @@ func textTransformationSchema() *schema.Schema {
return &schema.Schema{
Type: schema.TypeSet,
Required: true,
MinItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"priority": {
Expand Down Expand Up @@ -777,6 +803,7 @@ func webACLRootStatementSchema(level int) *schema.Schema {
"not_statement": statementSchema(level),
"or_statement": statementSchema(level),
"rate_based_statement": rateBasedStatementSchema(level),
"regex_match_statement": regexMatchStatementSchema(),
"regex_pattern_set_reference_statement": regexPatternSetReferenceStatementSchema(),
"rule_group_reference_statement": ruleGroupReferenceStatementSchema(),
"size_constraint_statement": sizeConstraintSchema(),
Expand Down Expand Up @@ -871,6 +898,7 @@ func scopeDownStatementSchema(level int) *schema.Schema {
"ip_set_reference_statement": ipSetReferenceStatementSchema(),
"not_statement": statementSchema(level),
"or_statement": statementSchema(level),
"regex_match_statement": regexMatchStatementSchema(),
"regex_pattern_set_reference_statement": regexPatternSetReferenceStatementSchema(),
"size_constraint_statement": sizeConstraintSchema(),
"sqli_match_statement": sqliMatchStatementSchema(),
Expand Down
44 changes: 38 additions & 6 deletions internal/service/wafv2/web_acl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1709,9 +1709,10 @@ func TestAccWAFV2WebACL_RateBased_maxNested(t *testing.T) {
"statement.0.rate_based_statement.0.scope_down_statement.0.not_statement.#": "1",
"statement.0.rate_based_statement.0.scope_down_statement.0.not_statement.0.statement.#": "1",
"statement.0.rate_based_statement.0.scope_down_statement.0.not_statement.0.statement.0.or_statement.#": "1",
"statement.0.rate_based_statement.0.scope_down_statement.0.not_statement.0.statement.0.or_statement.0.statement.#": "2",
"statement.0.rate_based_statement.0.scope_down_statement.0.not_statement.0.statement.0.or_statement.0.statement.#": "3",
"statement.0.rate_based_statement.0.scope_down_statement.0.not_statement.0.statement.0.or_statement.0.statement.0.regex_pattern_set_reference_statement.#": "1",
"statement.0.rate_based_statement.0.scope_down_statement.0.not_statement.0.statement.0.or_statement.0.statement.1.ip_set_reference_statement.#": "1",
"statement.0.rate_based_statement.0.scope_down_statement.0.not_statement.0.statement.0.or_statement.0.statement.1.regex_match_statement.#": "1",
"statement.0.rate_based_statement.0.scope_down_statement.0.not_statement.0.statement.0.or_statement.0.statement.2.ip_set_reference_statement.#": "1",
}),
),
},
Expand Down Expand Up @@ -1750,9 +1751,10 @@ func TestAccWAFV2WebACL_Operators_maxNested(t *testing.T) {
"statement.0.and_statement.0.statement.0.not_statement.#": "1",
"statement.0.and_statement.0.statement.0.not_statement.0.statement.#": "1",
"statement.0.and_statement.0.statement.0.not_statement.0.statement.0.or_statement.#": "1",
"statement.0.and_statement.0.statement.0.not_statement.0.statement.0.or_statement.0.statement.#": "2",
"statement.0.and_statement.0.statement.0.not_statement.0.statement.0.or_statement.0.statement.#": "3",
"statement.0.and_statement.0.statement.0.not_statement.0.statement.0.or_statement.0.statement.0.regex_pattern_set_reference_statement.#": "1",
"statement.0.and_statement.0.statement.0.not_statement.0.statement.0.or_statement.0.statement.1.ip_set_reference_statement.#": "1",
"statement.0.and_statement.0.statement.0.not_statement.0.statement.0.or_statement.0.statement.1.regex_match_statement.#": "1",
"statement.0.and_statement.0.statement.0.not_statement.0.statement.0.or_statement.0.statement.2.ip_set_reference_statement.#": "1",
"statement.0.and_statement.0.statement.1.geo_match_statement.#": "1",
"statement.0.and_statement.0.statement.1.geo_match_statement.0.country_codes.0": "NL",
}),
Expand Down Expand Up @@ -3221,7 +3223,7 @@ resource "aws_wafv2_regex_pattern_set" "test" {
scope = "REGIONAL"
regular_expression {
regex_string = "one"
regex_string = "[a-z]([a-z0-9_-]*[a-z0-9])?"
}
}
Expand Down Expand Up @@ -3273,6 +3275,21 @@ resource "aws_wafv2_web_acl" "test" {
}
}
statement {
regex_match_statement {
regex_string = "[a-z]([a-z0-9_-]*[a-z0-9])?"
field_to_match {
uri_path {}
}
text_transformation {
type = "LOWERCASE"
priority = 1
}
}
}
statement {
ip_set_reference_statement {
arn = aws_wafv2_ip_set.test.arn
Expand Down Expand Up @@ -3308,7 +3325,7 @@ resource "aws_wafv2_regex_pattern_set" "test" {
scope = "REGIONAL"
regular_expression {
regex_string = "one"
regex_string = "[a-z]([a-z0-9_-]*[a-z0-9])?"
}
}
Expand Down Expand Up @@ -3357,6 +3374,21 @@ resource "aws_wafv2_web_acl" "test" {
}
}
statement {
regex_match_statement {
regex_string = "[a-z]([a-z0-9_-]*[a-z0-9])?"
field_to_match {
uri_path {}
}
text_transformation {
type = "LOWERCASE"
priority = 1
}
}
}
statement {
ip_set_reference_statement {
arn = aws_wafv2_ip_set.test.arn
Expand Down
Loading

0 comments on commit 4fe109e

Please sign in to comment.