Skip to content

Commit eb9ee3b

Browse files
authored
Merge pull request #41719 from drewtul/f-add-ja34-rate-limits
[Enhancement] Add support for JA3 and JA4 Fingerprint in WebACL rate limits and JA4 support for matching
2 parents cf90ded + 5801cd2 commit eb9ee3b

File tree

6 files changed

+526
-3
lines changed

6 files changed

+526
-3
lines changed

.changelog/41719.txt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
```release-note:enhancement
2+
resource/aws_wafv2_web_acl: Add `ja3_fingerprint` and `ja4_fingerprint` to `custom_key` configuration blocks
3+
```
4+
5+
```release-note:enhancement
6+
resource/aws_wafv2_rule_group: Add `ja3_fingerprint` and `ja4_fingerprint` to `custom_key` configuration blocks
7+
```
8+
9+
```release-note:enhancement
10+
resource/aws_wafv2_web_acl: Add `ja4_fingerprint` to `field_to_match` configuration blocks
11+
```
12+
13+
```release-note:enhancement
14+
resource/aws_wafv2_rule_group: Add `ja4_fingerprint` to `field_to_match` configuration blocks
15+
```

internal/service/wafv2/flex.go

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,10 @@ func expandFieldToMatch(l []interface{}) *awstypes.FieldToMatch {
586586
f.JA3Fingerprint = expandJA3Fingerprint(v.([]interface{}))
587587
}
588588

589+
if v, ok := m["ja4_fingerprint"]; ok && len(v.([]interface{})) > 0 {
590+
f.JA4Fingerprint = expandJA4Fingerprint(v.([]interface{}))
591+
}
592+
589593
if v, ok := m["single_query_argument"]; ok && len(v.([]interface{})) > 0 {
590594
f.SingleQueryArgument = expandSingleQueryArgument(m["single_query_argument"].([]interface{}))
591595
}
@@ -716,6 +720,20 @@ func expandJA3Fingerprint(l []interface{}) *awstypes.JA3Fingerprint {
716720
return ja3fingerprint
717721
}
718722

723+
func expandJA4Fingerprint(l []interface{}) *awstypes.JA4Fingerprint {
724+
if len(l) == 0 || l[0] == nil {
725+
return nil
726+
}
727+
728+
m := l[0].(map[string]interface{})
729+
730+
ja4fingerprint := &awstypes.JA4Fingerprint{
731+
FallbackBehavior: awstypes.FallbackBehavior(m["fallback_behavior"].(string)),
732+
}
733+
734+
return ja4fingerprint
735+
}
736+
719737
func expandJSONMatchPattern(l []interface{}) *awstypes.JsonMatchPattern {
720738
if len(l) == 0 || l[0] == nil {
721739
return nil
@@ -1561,6 +1579,26 @@ func expandRateLimitHeader(l []interface{}) *awstypes.RateLimitHeader {
15611579
}
15621580
}
15631581

1582+
func expandRateLimitJa3Fingerprint(l []interface{}) *awstypes.RateLimitJA3Fingerprint {
1583+
if len(l) == 0 || l[0] == nil {
1584+
return nil
1585+
}
1586+
m := l[0].(map[string]interface{})
1587+
return &awstypes.RateLimitJA3Fingerprint{
1588+
FallbackBehavior: awstypes.FallbackBehavior(m["fallback_behavior"].(string)),
1589+
}
1590+
}
1591+
1592+
func expandRateLimitJa4Fingerprint(l []interface{}) *awstypes.RateLimitJA4Fingerprint {
1593+
if len(l) == 0 || l[0] == nil {
1594+
return nil
1595+
}
1596+
m := l[0].(map[string]interface{})
1597+
return &awstypes.RateLimitJA4Fingerprint{
1598+
FallbackBehavior: awstypes.FallbackBehavior(m["fallback_behavior"].(string)),
1599+
}
1600+
}
1601+
15641602
func expandRateLimitLabelNamespace(l []interface{}) *awstypes.RateLimitLabelNamespace {
15651603
if len(l) == 0 || l[0] == nil {
15661604
return nil
@@ -1626,6 +1664,12 @@ func expandRateBasedStatementCustomKeys(l []interface{}) []awstypes.RateBasedSta
16261664
if v, ok := m["ip"]; ok && len(v.([]interface{})) > 0 {
16271665
r.IP = &awstypes.RateLimitIP{}
16281666
}
1667+
if v, ok := m["ja3_fingerprint"]; ok && len(v.([]interface{})) > 0 {
1668+
r.JA3Fingerprint = expandRateLimitJa3Fingerprint(v.([]interface{}))
1669+
}
1670+
if v, ok := m["ja4_fingerprint"]; ok && len(v.([]interface{})) > 0 {
1671+
r.JA4Fingerprint = expandRateLimitJa4Fingerprint(v.([]interface{}))
1672+
}
16291673
if v, ok := m["label_namespace"]; ok {
16301674
r.LabelNamespace = expandRateLimitLabelNamespace(v.([]interface{}))
16311675
}
@@ -2124,6 +2168,10 @@ func flattenFieldToMatch(f *awstypes.FieldToMatch) interface{} {
21242168
m["ja3_fingerprint"] = flattenJA3Fingerprint(f.JA3Fingerprint)
21252169
}
21262170

2171+
if f.JA4Fingerprint != nil {
2172+
m["ja4_fingerprint"] = flattenJA4Fingerprint(f.JA4Fingerprint)
2173+
}
2174+
21272175
if f.JsonBody != nil {
21282176
m["json_body"] = flattenJSONBody(f.JsonBody)
21292177
}
@@ -2221,6 +2269,18 @@ func flattenJA3Fingerprint(j *awstypes.JA3Fingerprint) interface{} {
22212269
return []interface{}{m}
22222270
}
22232271

2272+
func flattenJA4Fingerprint(j *awstypes.JA4Fingerprint) interface{} {
2273+
if j == nil {
2274+
return []interface{}{}
2275+
}
2276+
2277+
m := map[string]interface{}{
2278+
"fallback_behavior": j.FallbackBehavior,
2279+
}
2280+
2281+
return []interface{}{m}
2282+
}
2283+
22242284
func flattenJSONBody(b *awstypes.JsonBody) interface{} {
22252285
if b == nil {
22262286
return []interface{}{}
@@ -2949,6 +3009,28 @@ func flattenRateLimitHeader(apiObject *awstypes.RateLimitHeader) []interface{} {
29493009
}
29503010
}
29513011

3012+
func flattenRateLimitJa3Fingerprint(apiObject *awstypes.RateLimitJA3Fingerprint) []interface{} {
3013+
if apiObject == nil {
3014+
return nil
3015+
}
3016+
return []interface{}{
3017+
map[string]interface{}{
3018+
"fallback_behavior": apiObject.FallbackBehavior,
3019+
},
3020+
}
3021+
}
3022+
3023+
func flattenRateLimitJa4Fingerprint(apiObject *awstypes.RateLimitJA4Fingerprint) []interface{} {
3024+
if apiObject == nil {
3025+
return nil
3026+
}
3027+
return []interface{}{
3028+
map[string]interface{}{
3029+
"fallback_behavior": apiObject.FallbackBehavior,
3030+
},
3031+
}
3032+
}
3033+
29523034
func flattenRateLimitLabelNamespace(apiObject *awstypes.RateLimitLabelNamespace) []interface{} {
29533035
if apiObject == nil {
29543036
return nil
@@ -3024,6 +3106,12 @@ func flattenRateBasedStatementCustomKeys(apiObject []awstypes.RateBasedStatement
30243106
map[string]interface{}{},
30253107
}
30263108
}
3109+
if o.JA3Fingerprint != nil {
3110+
tfMap["ja3_fingerprint"] = flattenRateLimitJa3Fingerprint(o.JA3Fingerprint)
3111+
}
3112+
if o.JA4Fingerprint != nil {
3113+
tfMap["ja4_fingerprint"] = flattenRateLimitJa4Fingerprint(o.JA4Fingerprint)
3114+
}
30273115
if o.LabelNamespace != nil {
30283116
tfMap["label_namespace"] = flattenRateLimitLabelNamespace(o.LabelNamespace)
30293117
}

internal/service/wafv2/schemas.go

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,8 @@ var fieldToMatchBaseSchema = sync.OnceValue(func() *schema.Resource {
379379
"cookies": cookiesSchema(),
380380
"header_order": headerOrderSchema(),
381381
"headers": headersSchema(),
382-
"ja3_fingerprint": ja3fingerprintSchema(),
382+
"ja3_fingerprint": jaFingerprintSchema(),
383+
"ja4_fingerprint": jaFingerprintSchema(),
383384
"json_body": jsonBodySchema(),
384385
"method": emptySchema(),
385386
"query_string": emptySchema(),
@@ -504,6 +505,23 @@ var forwardedIPConfigSchema = sync.OnceValue(func() *schema.Schema {
504505
}
505506
})
506507

508+
var rateLimitJAFingerprintConfigSchema = sync.OnceValue(func() *schema.Schema {
509+
return &schema.Schema{
510+
Type: schema.TypeList,
511+
Optional: true,
512+
MaxItems: 1,
513+
Elem: &schema.Resource{
514+
Schema: map[string]*schema.Schema{
515+
"fallback_behavior": {
516+
Type: schema.TypeString,
517+
Required: true,
518+
ValidateDiagFunc: enum.Validate[awstypes.FallbackBehavior](),
519+
},
520+
},
521+
},
522+
}
523+
})
524+
507525
var textTransformationSchema = sync.OnceValue(func() *schema.Schema {
508526
return &schema.Schema{
509527
Type: schema.TypeSet,
@@ -860,7 +878,7 @@ func cookiesMatchPatternSchema() *schema.Schema {
860878
}
861879
}
862880

863-
func ja3fingerprintSchema() *schema.Schema {
881+
func jaFingerprintSchema() *schema.Schema {
864882
return &schema.Schema{
865883
Type: schema.TypeList,
866884
Optional: true,
@@ -1078,7 +1096,9 @@ func rateBasedStatementSchema(level int) *schema.Schema {
10781096
},
10791097
},
10801098
},
1081-
"ip": emptySchema(),
1099+
"ip": emptySchema(),
1100+
"ja3_fingerprint": rateLimitJAFingerprintConfigSchema(),
1101+
"ja4_fingerprint": rateLimitJAFingerprintConfigSchema(),
10821102
"label_namespace": {
10831103
Type: schema.TypeList,
10841104
Optional: true,

0 commit comments

Comments
 (0)