envoyproxy / envoyproxy/gateway

Rate limit: Distinct default with per-client overrides

Open
#9,737 4 comments 0 reactions 0 assignees View on GitHub
area/api
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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.