Skip to content

Commit 0d91c6c

Browse files
committed
feat: add query parameter match support in ratelimit
Signed-off-by: sachin maurya <[email protected]>
1 parent ee4ae71 commit 0d91c6c

23 files changed

+846
-9
lines changed

api/v1alpha1/ratelimit_types.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,19 @@ type RateLimitSelectCondition struct {
197197
//
198198
// +optional
199199
SourceCIDR *SourceMatch `json:"sourceCIDR,omitempty"`
200+
201+
// Rate limit on query parameters.
202+
// +optional
203+
QueryParameters *QueryParameters `json:"queryParameters,omitempty"`
204+
}
205+
206+
type QueryParameters struct {
207+
// The name of the query parameter to use for rate limiting.
208+
// Value of this query parameter is used to populate the value of the descriptor entry for the descriptor_key.
209+
QueryParameterName string `json:"queryParameterName,omitempty"`
210+
// The key to use when creating the rate limit descriptor entry.
211+
// This descriptor key will be used to identify the rate limit rule in the rate limiting service.
212+
DescriptorKey string `json:"descriptorKey,omitempty"`
200213
}
201214

202215
// +kubebuilder:validation:Enum=Exact;Distinct

api/v1alpha1/zz_generated.deepcopy.go

Lines changed: 20 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -994,6 +994,20 @@ spec:
994994
type: object
995995
maxItems: 16
996996
type: array
997+
queryParameters:
998+
description: Rate limit on query parameters.
999+
properties:
1000+
descriptorKey:
1001+
description: |-
1002+
The key to use when creating the rate limit descriptor entry.
1003+
This descriptor key will be used to identify the rate limit rule in the rate limiting service.
1004+
type: string
1005+
queryParameterName:
1006+
description: |-
1007+
The name of the query parameter to use for rate limiting.
1008+
Value of this query parameter is used to populate the value of the descriptor entry for the descriptor_key.
1009+
type: string
1010+
type: object
9971011
sourceCIDR:
9981012
description: |-
9991013
SourceCIDR is the client IP Address range to match on.
@@ -1245,6 +1259,20 @@ spec:
12451259
type: object
12461260
maxItems: 16
12471261
type: array
1262+
queryParameters:
1263+
description: Rate limit on query parameters.
1264+
properties:
1265+
descriptorKey:
1266+
description: |-
1267+
The key to use when creating the rate limit descriptor entry.
1268+
This descriptor key will be used to identify the rate limit rule in the rate limiting service.
1269+
type: string
1270+
queryParameterName:
1271+
description: |-
1272+
The name of the query parameter to use for rate limiting.
1273+
Value of this query parameter is used to populate the value of the descriptor entry for the descriptor_key.
1274+
type: string
1275+
type: object
12481276
sourceCIDR:
12491277
description: |-
12501278
SourceCIDR is the client IP Address range to match on.

charts/gateway-helm/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -993,6 +993,20 @@ spec:
993993
type: object
994994
maxItems: 16
995995
type: array
996+
queryParameters:
997+
description: Rate limit on query parameters.
998+
properties:
999+
descriptorKey:
1000+
description: |-
1001+
The key to use when creating the rate limit descriptor entry.
1002+
This descriptor key will be used to identify the rate limit rule in the rate limiting service.
1003+
type: string
1004+
queryParameterName:
1005+
description: |-
1006+
The name of the query parameter to use for rate limiting.
1007+
Value of this query parameter is used to populate the value of the descriptor entry for the descriptor_key.
1008+
type: string
1009+
type: object
9961010
sourceCIDR:
9971011
description: |-
9981012
SourceCIDR is the client IP Address range to match on.
@@ -1244,6 +1258,20 @@ spec:
12441258
type: object
12451259
maxItems: 16
12461260
type: array
1261+
queryParameters:
1262+
description: Rate limit on query parameters.
1263+
properties:
1264+
descriptorKey:
1265+
description: |-
1266+
The key to use when creating the rate limit descriptor entry.
1267+
This descriptor key will be used to identify the rate limit rule in the rate limiting service.
1268+
type: string
1269+
queryParameterName:
1270+
description: |-
1271+
The name of the query parameter to use for rate limiting.
1272+
Value of this query parameter is used to populate the value of the descriptor entry for the descriptor_key.
1273+
type: string
1274+
type: object
12471275
sourceCIDR:
12481276
description: |-
12491277
SourceCIDR is the client IP Address range to match on.

internal/gatewayapi/backendtrafficpolicy.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -891,10 +891,10 @@ func buildRateLimitRule(rule egv1a1.RateLimitRule) (*ir.RateLimitRule, error) {
891891
}
892892

893893
for _, match := range rule.ClientSelectors {
894-
if len(match.Headers) == 0 && match.SourceCIDR == nil {
894+
if len(match.Headers) == 0 && match.SourceCIDR == nil && match.QueryParameters == nil {
895895
return nil, fmt.Errorf(
896896
"unable to translate rateLimit. At least one of the" +
897-
" header or sourceCIDR must be specified")
897+
" header, sourceCIDR, or queryParameters must be specified")
898898
}
899899
for _, header := range match.Headers {
900900
switch {
@@ -950,6 +950,17 @@ func buildRateLimitRule(rule egv1a1.RateLimitRule) (*ir.RateLimitRule, error) {
950950
cidrMatch.Distinct = distinct
951951
irRule.CIDRMatch = cidrMatch
952952
}
953+
954+
if match.QueryParameters != nil {
955+
// Validate QueryParameters
956+
if match.QueryParameters.QueryParameterName == "" {
957+
return nil, fmt.Errorf("queryParameterName is required when QueryParameters is specified")
958+
}
959+
if match.QueryParameters.DescriptorKey == "" {
960+
return nil, fmt.Errorf("descriptorKey is required when QueryParameters is specified")
961+
}
962+
irRule.QueryParameters = (*ir.QueryParameters)(match.QueryParameters)
963+
}
953964
}
954965

955966
if cost := rule.Cost; cost != nil {

internal/ir/xds.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2242,6 +2242,8 @@ type RateLimitRule struct {
22422242
HeaderMatches []*StringMatch `json:"headerMatches" yaml:"headerMatches"`
22432243
// CIDRMatch define the match conditions on the source IP's CIDR for this route.
22442244
CIDRMatch *CIDRMatch `json:"cidrMatch,omitempty" yaml:"cidrMatch,omitempty"`
2245+
// Rate limit on query parameters.
2246+
QueryParameters *QueryParameters `json:"queryParameters,omitempty" yaml:"queryParameters,omitempty"`
22452247
// Limit holds the rate limit values.
22462248
Limit RateLimitValue `json:"limit,omitempty" yaml:"limit,omitempty"`
22472249
// RequestCost specifies the cost of the request.
@@ -2259,6 +2261,12 @@ type RateLimitRule struct {
22592261
Name string `json:"name,omitempty" yaml:"name,omitempty"`
22602262
}
22612263

2264+
// +k8s:deepcopy-gen=true
2265+
type QueryParameters struct {
2266+
QueryParameterName string `json:"queryParameterName,omitempty" yaml:"queryParameterName,omitempty"`
2267+
DescriptorKey string `json:"descriptorKey,omitempty" yaml:"descriptorKey,omitempty"`
2268+
}
2269+
22622270
// RateLimitCost specifies the cost of the request or response.
22632271
// +k8s:deepcopy-gen=true
22642272
type RateLimitCost struct {
@@ -2278,7 +2286,7 @@ type CIDRMatch struct {
22782286

22792287
// TODO zhaohuabing: remove this function
22802288
func (r *RateLimitRule) IsMatchSet() bool {
2281-
return len(r.HeaderMatches) != 0 || r.CIDRMatch != nil
2289+
return len(r.HeaderMatches) != 0 || r.CIDRMatch != nil || r.QueryParameters != nil
22822290
}
22832291

22842292
type RateLimitUnit egv1a1.RateLimitUnit

internal/ir/zz_generated.deepcopy.go

Lines changed: 20 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/xds/translator/local_ratelimit.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,22 @@ func buildRouteLocalRateLimits(local *ir.LocalRateLimit) (
304304
rlActions = append(rlActions, action)
305305
}
306306
}
307+
if rule.QueryParameters != nil {
308+
queryParam := &routev3.RateLimit_Action_QueryParameters{}
309+
queryParam.DescriptorKey = rule.QueryParameters.DescriptorKey
310+
queryParam.QueryParameterName = rule.QueryParameters.QueryParameterName
311+
action := &routev3.RateLimit_Action{
312+
ActionSpecifier: &routev3.RateLimit_Action_QueryParameters_{
313+
QueryParameters: queryParam,
314+
},
315+
}
316+
rlActions = append(rlActions, action)
317+
318+
entry := &rlv3.RateLimitDescriptor_Entry{
319+
Key: rule.QueryParameters.DescriptorKey,
320+
}
321+
descriptorEntries = append(descriptorEntries, entry)
322+
}
307323

308324
rateLimit := &routev3.RateLimit{Actions: rlActions}
309325
rateLimits = append(rateLimits, rateLimit)

internal/xds/translator/ratelimit.go

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,18 @@ func buildRouteRateLimits(route *ir.HTTPRoute) (rateLimits []*routev3.RateLimit,
336336
}
337337
}
338338

339+
if rule.QueryParameters != nil {
340+
queryParam := &routev3.RateLimit_Action_QueryParameters{}
341+
queryParam.DescriptorKey = rule.QueryParameters.DescriptorKey
342+
queryParam.QueryParameterName = rule.QueryParameters.QueryParameterName
343+
action := &routev3.RateLimit_Action{
344+
ActionSpecifier: &routev3.RateLimit_Action_QueryParameters_{
345+
QueryParameters: queryParam,
346+
},
347+
}
348+
rlActions = append(rlActions, action)
349+
}
350+
339351
// Case when both header and cidr match are not set and the ratelimit
340352
// will be applied to all traffic.
341353
// 3) No Match (apply to all traffic)
@@ -598,7 +610,8 @@ func buildRateLimitServiceDescriptors(route *ir.HTTPRoute) []*rlsconfv3.RateLimi
598610
// the order in which ratelimit actions are built:
599611
// 1) Header Matches
600612
// 2) CIDR Match
601-
// 3) No Match
613+
// 3) Query Parameters
614+
// 4) No Match
602615

603616
for rIdx, rule := range global.Rules {
604617
rateLimitPolicy := &rlsconfv3.RateLimitPolicy{
@@ -682,9 +695,26 @@ func buildRateLimitServiceDescriptors(route *ir.HTTPRoute) []*rlsconfv3.RateLimi
682695
cur = pbDesc
683696
}
684697
}
685-
// Case when both header and cidr match are not set and the ratelimit
698+
699+
// 3) Query Parameters
700+
if rule.QueryParameters != nil {
701+
pbDesc := new(rlsconfv3.RateLimitDescriptor)
702+
pbDesc.Key = rule.QueryParameters.DescriptorKey
703+
pbDesc.Value = ""
704+
705+
if cur != nil {
706+
// The header or cidr match descriptor chain exists, add current
707+
// descriptor to the chain.
708+
cur.Descriptors = []*rlsconfv3.RateLimitDescriptor{pbDesc}
709+
} else {
710+
head = pbDesc
711+
}
712+
cur = pbDesc
713+
}
714+
715+
// Case when both header, cidr match, and query parameters are not set and the ratelimit
686716
// will be applied to all traffic.
687-
// 3) No Match (apply to all traffic)
717+
// 4) No Match (apply to all traffic)
688718
if !rule.IsMatchSet() {
689719
pbDesc := new(rlsconfv3.RateLimitDescriptor)
690720
pbDesc.Key = getRouteRuleDescriptor(domainRuleIdx, -1)
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
http:
2+
- name: "first-listener"
3+
address: "0.0.0.0"
4+
port: 10080
5+
hostnames:
6+
- "*"
7+
path:
8+
mergeSlashes: true
9+
escapedSlashesAction: UnescapeAndRedirect
10+
routes:
11+
- name: "first-route"
12+
traffic:
13+
rateLimit:
14+
global:
15+
rules:
16+
- name: "test-namespace/test-policy-1/rule/0"
17+
headerMatches:
18+
- name: "x-user-id"
19+
exact: "one"
20+
queryParameters:
21+
queryParameterName: "user"
22+
descriptorKey: "user_param"
23+
limit:
24+
requests: 5
25+
unit: second
26+
shared: false
27+
pathMatch:
28+
exact: "foo/bar"
29+
destination:
30+
name: "first-route-dest"
31+
settings:
32+
- endpoints:
33+
- host: "1.2.3.4"
34+
port: 50000

0 commit comments

Comments
 (0)