Skip to content

Commit

Permalink
Merge pull request #35521 from acwwat/f-aws_wafv2-header_order_support
Browse files Browse the repository at this point in the history
feat: Add header_order field support to aws_wafv2_webacl and rule_group
  • Loading branch information
ewbankkit authored Jan 29, 2024
2 parents 33b88e2 + 92b6f0c commit 60b3b69
Show file tree
Hide file tree
Showing 7 changed files with 270 additions and 2 deletions.
7 changes: 7 additions & 0 deletions .changelog/35521.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
```release-note:enhancement
resource/aws_wafv2_rule_group: Add `header_order` to `field_to_match` configuration blocks
```

```release-note:enhancement
resource/aws_wafv2_web_acl: Add `header_order`to `field_to_match` configuration blocks
```
32 changes: 32 additions & 0 deletions internal/service/wafv2/flex.go
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,10 @@ func expandFieldToMatch(l []interface{}) *wafv2.FieldToMatch {
f.Cookies = expandCookies(m["cookies"].([]interface{}))
}

if v, ok := m["header_order"]; ok && len(v.([]interface{})) > 0 {
f.HeaderOrder = expandHeaderOrder(m["header_order"].([]interface{}))
}

if v, ok := m["headers"]; ok && len(v.([]interface{})) > 0 {
f.Headers = expandHeaders(m["headers"].([]interface{}))
}
Expand Down Expand Up @@ -907,6 +911,18 @@ func expandXSSMatchStatement(l []interface{}) *wafv2.XssMatchStatement {
}
}

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

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

return &wafv2.HeaderOrder{
OversizeHandling: aws.String(m["oversize_handling"].(string)),
}
}

func expandHeaders(l []interface{}) *wafv2.Headers {
if len(l) == 0 || l[0] == nil {
return nil
Expand Down Expand Up @@ -1958,6 +1974,10 @@ func flattenFieldToMatch(f *wafv2.FieldToMatch) interface{} {
m["cookies"] = flattenCookies(f.Cookies)
}

if f.HeaderOrder != nil {
m["header_order"] = flattenHeaderOrder(f.HeaderOrder)
}

if f.Headers != nil {
m["headers"] = flattenHeaders(f.Headers)
}
Expand Down Expand Up @@ -2287,6 +2307,18 @@ func flattenVisibilityConfig(config *wafv2.VisibilityConfig) interface{} {
return []interface{}{m}
}

func flattenHeaderOrder(s *wafv2.HeaderOrder) interface{} {
if s == nil {
return []interface{}{}
}

m := map[string]interface{}{
"oversize_handling": aws.StringValue(s.OversizeHandling),
}

return []interface{}{m}
}

func flattenHeaders(s *wafv2.Headers) interface{} {
if s == nil {
return []interface{}{}
Expand Down
95 changes: 95 additions & 0 deletions internal/service/wafv2/rule_group_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,9 @@ func TestAccWAFV2RuleGroup_ByteMatchStatement_fieldToMatch(t *testing.T) {
"statement.0.byte_match_statement.0.field_to_match.0.all_query_arguments.#": "1",
"statement.0.byte_match_statement.0.field_to_match.0.body.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.cookies.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.header_order.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.headers.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.ja3_fingerprint.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.json_body.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.method.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.query_string.#": "0",
Expand All @@ -484,7 +486,9 @@ func TestAccWAFV2RuleGroup_ByteMatchStatement_fieldToMatch(t *testing.T) {
"statement.0.byte_match_statement.0.field_to_match.0.all_query_arguments.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.body.#": "1",
"statement.0.byte_match_statement.0.field_to_match.0.cookies.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.header_order.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.headers.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.ja3_fingerprint.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.json_body.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.method.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.query_string.#": "0",
Expand Down Expand Up @@ -512,7 +516,9 @@ func TestAccWAFV2RuleGroup_ByteMatchStatement_fieldToMatch(t *testing.T) {
"statement.0.byte_match_statement.0.field_to_match.0.cookies.0.match_pattern.#": "1",
"statement.0.byte_match_statement.0.field_to_match.0.cookies.0.match_pattern.0.included_cookies.0": "test",
"statement.0.byte_match_statement.0.field_to_match.0.cookies.0.match_pattern.0.included_cookies.1": "cookie_test",
"statement.0.byte_match_statement.0.field_to_match.0.header_order.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.headers.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.ja3_fingerprint.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.json_body.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.method.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.query_string.#": "0",
Expand Down Expand Up @@ -543,6 +549,32 @@ func TestAccWAFV2RuleGroup_ByteMatchStatement_fieldToMatch(t *testing.T) {
}),
),
},
{
Config: testAccRuleGroupConfig_byteMatchStatementFieldToMatchHeaderOrder(ruleGroupName),
Check: resource.ComposeTestCheckFunc(
testAccCheckRuleGroupExists(ctx, resourceName, &v),
acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexache.MustCompile(`regional/rulegroup/.+$`)),
resource.TestCheckResourceAttr(resourceName, "rule.#", "1"),
resource.TestCheckTypeSetElemNestedAttrs(resourceName, "rule.*", map[string]string{
"statement.#": "1",
"statement.0.byte_match_statement.#": "1",
"statement.0.byte_match_statement.0.field_to_match.#": "1",
"statement.0.byte_match_statement.0.field_to_match.0.all_query_arguments.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.body.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.cookies.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.header_order.#": "1",
"statement.0.byte_match_statement.0.field_to_match.0.header_order.0.oversize_handling": "MATCH",
"statement.0.byte_match_statement.0.field_to_match.0.headers.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.ja3_fingerprint.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.json_body.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.method.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.query_string.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.single_header.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.single_query_argument.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.uri_path.#": "0",
}),
),
},
{
Config: testAccRuleGroupConfig_byteMatchStatementFieldToMatchHeadersMatchPatternAll(ruleGroupName),
Check: resource.ComposeTestCheckFunc(
Expand All @@ -556,13 +588,15 @@ func TestAccWAFV2RuleGroup_ByteMatchStatement_fieldToMatch(t *testing.T) {
"statement.0.byte_match_statement.0.field_to_match.0.all_query_arguments.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.body.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.cookies.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.header_order.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.headers.#": "1",
"statement.0.byte_match_statement.0.field_to_match.0.headers.0.oversize_handling": "MATCH",
"statement.0.byte_match_statement.0.field_to_match.0.headers.0.match_scope": "ALL",
"statement.0.byte_match_statement.0.field_to_match.0.headers.0.match_pattern.#": "1",
"statement.0.byte_match_statement.0.field_to_match.0.headers.0.match_pattern.0.all.#": "1",
"statement.0.byte_match_statement.0.field_to_match.0.headers.0.match_pattern.0.included_headers.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.headers.0.match_pattern.0.excluded_headers.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.ja3_fingerprint.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.json_body.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.method.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.query_string.#": "0",
Expand All @@ -585,6 +619,7 @@ func TestAccWAFV2RuleGroup_ByteMatchStatement_fieldToMatch(t *testing.T) {
"statement.0.byte_match_statement.0.field_to_match.0.all_query_arguments.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.body.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.cookies.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.header_order.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.headers.#": "1",
"statement.0.byte_match_statement.0.field_to_match.0.headers.0.oversize_handling": "MATCH",
"statement.0.byte_match_statement.0.field_to_match.0.headers.0.match_scope": "ALL",
Expand All @@ -594,6 +629,7 @@ func TestAccWAFV2RuleGroup_ByteMatchStatement_fieldToMatch(t *testing.T) {
"statement.0.byte_match_statement.0.field_to_match.0.headers.0.match_pattern.0.included_headers.0": "session",
"statement.0.byte_match_statement.0.field_to_match.0.headers.0.match_pattern.0.included_headers.1": "session-id",
"statement.0.byte_match_statement.0.field_to_match.0.headers.0.match_pattern.0.excluded_headers.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.ja3_fingerprint.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.json_body.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.method.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.query_string.#": "0",
Expand All @@ -616,6 +652,7 @@ func TestAccWAFV2RuleGroup_ByteMatchStatement_fieldToMatch(t *testing.T) {
"statement.0.byte_match_statement.0.field_to_match.0.all_query_arguments.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.body.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.cookies.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.header_order.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.headers.#": "1",
"statement.0.byte_match_statement.0.field_to_match.0.headers.0.oversize_handling": "MATCH",
"statement.0.byte_match_statement.0.field_to_match.0.headers.0.match_scope": "ALL",
Expand All @@ -625,6 +662,7 @@ func TestAccWAFV2RuleGroup_ByteMatchStatement_fieldToMatch(t *testing.T) {
"statement.0.byte_match_statement.0.field_to_match.0.headers.0.match_pattern.0.excluded_headers.0": "session",
"statement.0.byte_match_statement.0.field_to_match.0.headers.0.match_pattern.0.excluded_headers.1": "session-id",
"statement.0.byte_match_statement.0.field_to_match.0.headers.0.match_pattern.0.included_headers.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.ja3_fingerprint.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.json_body.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.method.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.query_string.#": "0",
Expand All @@ -651,7 +689,9 @@ func TestAccWAFV2RuleGroup_ByteMatchStatement_fieldToMatch(t *testing.T) {
"statement.0.byte_match_statement.0.field_to_match.0.all_query_arguments.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.body.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.cookies.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.header_order.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.headers.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.ja3_fingerprint.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.json_body.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.method.#": "1",
"statement.0.byte_match_statement.0.field_to_match.0.query_string.#": "0",
Expand All @@ -674,7 +714,9 @@ func TestAccWAFV2RuleGroup_ByteMatchStatement_fieldToMatch(t *testing.T) {
"statement.0.byte_match_statement.0.field_to_match.0.all_query_arguments.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.body.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.cookies.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.header_order.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.headers.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.ja3_fingerprint.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.json_body.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.method.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.query_string.#": "1",
Expand All @@ -697,7 +739,9 @@ func TestAccWAFV2RuleGroup_ByteMatchStatement_fieldToMatch(t *testing.T) {
"statement.0.byte_match_statement.0.field_to_match.0.all_query_arguments.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.body.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.cookies.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.header_order.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.headers.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.ja3_fingerprint.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.json_body.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.method.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.query_string.#": "0",
Expand All @@ -721,7 +765,9 @@ func TestAccWAFV2RuleGroup_ByteMatchStatement_fieldToMatch(t *testing.T) {
"statement.0.byte_match_statement.0.field_to_match.0.all_query_arguments.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.body.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.cookies.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.header_order.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.headers.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.ja3_fingerprint.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.json_body.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.method.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.query_string.#": "0",
Expand All @@ -745,7 +791,9 @@ func TestAccWAFV2RuleGroup_ByteMatchStatement_fieldToMatch(t *testing.T) {
"statement.0.byte_match_statement.0.field_to_match.0.all_query_arguments.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.body.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.cookies.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.header_order.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.headers.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.ja3_fingerprint.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.json_body.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.method.#": "0",
"statement.0.byte_match_statement.0.field_to_match.0.query_string.#": "0",
Expand Down Expand Up @@ -3294,6 +3342,53 @@ resource "aws_wafv2_rule_group" "test" {
`, rName)
}

func testAccRuleGroupConfig_byteMatchStatementFieldToMatchHeaderOrder(rName string) string {
return fmt.Sprintf(`
resource "aws_wafv2_rule_group" "test" {
capacity = 50
name = %[1]q
scope = "REGIONAL"
rule {
name = "rule-1"
priority = 1
action {
allow {}
}
statement {
byte_match_statement {
search_string = "host:user-agent:accept:authorization:referer"
field_to_match {
header_order {
oversize_handling = "MATCH"
}
}
text_transformation {
priority = 0
type = "NONE"
}
positional_constraint = "STARTS_WITH"
}
}
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
}
}
`, rName)
}

func testAccRuleGroupConfig_byteMatchStatementFieldToMatchHeadersMatchPatternAll(rName string) string {
return fmt.Sprintf(`
resource "aws_wafv2_rule_group" "test" {
Expand Down
13 changes: 13 additions & 0 deletions internal/service/wafv2/schemas.go
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@ func fieldToMatchBaseSchema() *schema.Resource {
"all_query_arguments": emptySchema(),
"body": bodySchema(),
"cookies": cookiesSchema(),
"header_order": headerOrderSchema(),
"headers": headersSchema(),
"ja3_fingerprint": ja3fingerprintSchema(),
"json_body": jsonBodySchema(),
Expand Down Expand Up @@ -870,6 +871,18 @@ func matchScopeSchema() *schema.Schema {
}
}

func headerOrderSchema() *schema.Schema {
return &schema.Schema{
Type: schema.TypeList,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"oversize_handling": oversizeHandlingRequiredSchema(),
},
},
}
}

func headersSchema() *schema.Schema {
return &schema.Schema{
Type: schema.TypeList,
Expand Down
Loading

0 comments on commit 60b3b69

Please sign in to comment.