envoyproxy / envoyproxy/gateway
Rate limit: Distinct default with per-client overrides
- Dominant language
- Go
- Stars
- 3k
- Forks
- 864
- Avg merge
- 1d 22h
- Merged PRs (30d)
- 148
Description
*Description*:
I would like to use Envoy Gateway with Global Rate Limiting to enforce rate limiting rules such as:
* The default client is rate limited to 10 req/s
* Client A is rate limited to 15 req/s
* Client B is rate limited to 20 req/s
* Client C is rate limited to 5 req/s
```yaml
rateLimit:
global:
rules:
# Default rule
- clientSelectors:
- headers:
- name: x-user-id
type: Distinct
limit:
requests: 10
unit: Second
# Client A
- clientSelectors:
- headers:
- name: x-user-id
value: client-a
limit:
requests: 15
unit: Second
# Client B
- clientSelectors:
- headers:
- name: x-user-id
value: client-b
limit:
requests: 20
unit: Second
# Client C
- clientSelectors:
- headers:
- name: x-user-id
value: client-c
limit:
requests: 5
unit: Second
```
Based on my understanding and testing, the above config does not work as I hope because the rate limit conditions are evaluated independently on any matching condition. The default rate limit (10 req/s) also applies to Client A, B and C, which ends up prematurely limiting Client A and B to 10 req/s.
We can work around this by negating the default rate for the known clients, but this is hard to maintain over time. However, we face MaxItems limitations on `clientSelectors[].headers`.
```yaml
rateLimit:
global:
rules:
# Default rule
- clientSelectors:
- headers:
- name: x-user-id
type: Distinct
- name: x-user-id
value: client-a
invert: true
- name: x-user-id
value: client-b
invert: true
- name: x-user-id
value: client-c
invert: true
limit:
requests: 10
unit: Second
# Client A
- clientSelectors:
- headers:
- name: x-user-id
value: client-a
limit:
requests: 15
unit: Second
# Client B
- clientSelectors:
- headers:
- name: x-user-id
value: client-b
limit:
requests: 20
unit: Second
# Client C
- clientSelectors:
- headers:
- name: x-user-id
value: client-c
limit:
requests: 5
unit: Second
```
I'm hoping we can support this usage pattern in a more streamlined manner.
Another way to achieve this goal is by setting the rate limits dynamically, something that is now supported: https://gateway.envoyproxy.io/latest/api/extension_types/#ratelimitvaluemetadata. However, that requires setting the metadata through extProc, Lua, WASM, etc, which is a bit of a heavy lift.
*Feature*:
Support a "default" rate limit that only applies if other clientSelectors do not apply.
I'm open to making the PR for this if we agree on high-level implementation details.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start by reviewing the rateLimit.global.rules and clientSelectors behavior described in the issue, then compare it with the RateLimitValueMetadata extension documentation linked there. Done means a default rule applies only when no more-specific client selector matches, while the distinct limits for clients A, B, and C continue to work without manually negating each known client.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- api, backend-api-design
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100