Skip to content

Commit

Permalink
limitCountRedis: add option to disable x-envoy-ratelimited (#835)
Browse files Browse the repository at this point in the history
* feat: use enable_limit_quota_headers as ratelimited option

* feat: add disable_x_envoy_ratelimited_header option

* feat: update doc

* feat: lint-markdown
yizhibian authored Jan 16, 2025
1 parent 085cce2 commit b99be34
Showing 7 changed files with 66 additions and 41 deletions.
4 changes: 4 additions & 0 deletions plugins/plugins/limitcountredis/config_test.go
Original file line number Diff line number Diff line change
@@ -66,6 +66,10 @@ func TestConfig(t *testing.T) {
name: "pass",
input: `{"address":"127.0.0.1:6479", "rules":[{"count":1,"timeWindow":"1s"}], "prefix":"test"}`,
},
{
name: "disable x-envoy-ratelimited header",
input: `{"address":"127.0.0.1:6479", "rules":[{"count":1,"timeWindow":"1s"}], "prefix":"test", "disable_x_envoy_ratelimited_header": true}`,
},
}

for _, tt := range tests {
5 changes: 3 additions & 2 deletions plugins/plugins/limitcountredis/filter.go
Original file line number Diff line number Diff line change
@@ -161,8 +161,9 @@ func (f *filter) DecodeHeaders(headers api.RequestHeaderMap, endStream bool) api
remain := ress[2*i].(int64)
if remain < 0 {
hdr := http.Header{}
// TODO: add option to disable x-envoy-ratelimited
hdr.Set("x-envoy-ratelimited", "true")
if !config.DisableXEnvoyRatelimitedHeader {
hdr.Set("x-envoy-ratelimited", "true")
}
status := 429
if config.RateLimitedStatus >= 400 { // follow the behavior of Envoy
status = int(config.RateLimitedStatus)
34 changes: 18 additions & 16 deletions site/content/en/docs/reference/plugins/limit_count_redis.md
Original file line number Diff line number Diff line change
@@ -16,22 +16,24 @@ The `limitCountRedis` plugin implements a global fixed window rate-limiting by s

## Configuration

| Name | Type | Required | Validation | Description |
|-------------------------|-------------------------------------|----------|----------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| address | string | False | | Redis address. Only one of `address` and `cluster` can be configured. |
| cluster | Cluster | False | | Redis cluster configuration. Only one of `address` and `cluster` can be configured. |
| prefix | string | True | min_len: 1, max_len: 128 | The prefix will be used as the prefix of Redis key. This field is introduced so that the recreation of the route won't reset the counter as the new limiter will use the same key as the previous one. Normally, put a random string in it is enough. To share the limit counters across multiple routes, we can use the same prefix. In this case, ensure the configurations of `limitCountRedis` plugin in these routes are the same. |
| rules | Rule | True | min_items: 1, max_items: 8 | Rules |
| failureModeDeny | boolean | False | | By default, if access to Redis fails, the request is allowed through. When true, it denies the request. |
| enableLimitQuotaHeaders | boolean | False | | Whether to set response headers related to rate-limiting quotas |
| username | string | False | | Username for accessing Redis |
| password | string | False | | Password for accessing Redis |
| tls | boolean | False | | Whether to access Redis over TLS |
| tlsSkipVerify | boolean | False | | Whether to skip verification when accessing Redis over TLS |
| statusOnError | [StatusCode](../type.md#statuscode) | False | | The status code used to deny requests when Redis is inaccessible and `failureModeDeny` is true. Defaults to 500. |
| rateLimitedStatus | [StatusCode](../type.md#statuscode) | False | | The status code for responses denied due to rate-limiting. Defaults to 429. This setting only takes effect when it's 400 or above. |

Each rule's count is independent. Rate-limiting action is triggered once any rule's quota is exhausted. Responses that are denied due to rate-limiting will include the header `x-envoy-ratelimited: true`. If `enableLimitQuotaHeaders` is set to `true` and accessing to redis succeed, all responses will include the following three headers:
| Name | Type | Required | Validation | Description |
|--------------------------------|-------------------------------------|----------|----------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| address | string | False | | Redis address. Only one of `address` and `cluster` can be configured. |
| cluster | Cluster | False | | Redis cluster configuration. Only one of `address` and `cluster` can be configured. |
| prefix | string | True | min_len: 1, max_len: 128 | The prefix will be used as the prefix of Redis key. This field is introduced so that the recreation of the route won't reset the counter as the new limiter will use the same key as the previous one. Normally, put a random string in it is enough. To share the limit counters across multiple routes, we can use the same prefix. In this case, ensure the configurations of `limitCountRedis` plugin in these routes are the same. |
| rules | Rule | True | min_items: 1, max_items: 8 | Rules |
| failureModeDeny | boolean | False | | By default, if access to Redis fails, the request is allowed through. When true, it denies the request. |
| enableLimitQuotaHeaders | boolean | False | | Whether to set response headers related to rate-limiting quotas |
| username | string | False | | Username for accessing Redis |
| password | string | False | | Password for accessing Redis |
| tls | boolean | False | | Whether to access Redis over TLS |
| tlsSkipVerify | boolean | False | | Whether to skip verification when accessing Redis over TLS |
| statusOnError | [StatusCode](../type.md#statuscode) | False | | The status code used to deny requests when Redis is inaccessible and `failureModeDeny` is true. Defaults to 500. |
| rateLimitedStatus | [StatusCode](../type.md#statuscode) | False | | The status code for responses denied due to rate-limiting. Defaults to 429. This setting only takes effect when it's 400 or above. |
| disableXEnvoyRatelimitedHeader | bool | False | | Whether to disable the `x-envoy-ratelimited` response header when rate limiting is triggered |


Each rule's count is independent. Rate-limiting action is triggered once any rule's quota is exhausted. Responses that are denied due to rate-limiting will include the header `x-envoy-ratelimited: true`(which can be disabled by config). If `enableLimitQuotaHeaders` is set to `true` and accessing to redis succeed, all responses will include the following three headers:

* `x-ratelimit-limit`: Represents the applied rate-limiting rule. The format is "the rule with the least remaining quota, (rule quota;w=time window){one or more rules}", e.g., `2, 2;w=60`.
* `x-ratelimit-remaining`: Represents the remaining quota of the rule with the least remaining quota, with a minimum value of `0`.
33 changes: 17 additions & 16 deletions site/content/zh-hans/docs/reference/plugins/limit_count_redis.md
Original file line number Diff line number Diff line change
@@ -16,22 +16,23 @@ title: Limit Count Redis

## 配置

| 名称 | 类型 | 必选 | 校验规则 | 说明 |
|-------------------------|-------------------------------------|------|----------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| address | string || | Redis 地址。`address``cluster` 只能配置一个。 |
| cluster | Cluster || | Redis cluster 配置。`address``cluster` 只能配置一个。 |
| prefix | string || min_len: 1, max_len: 128 | 该字段将用作 Redis key 的前缀。引入这个字段是为了在重新创建路由时不会重置计数器,因为新的限制统计将使用与前一个相同的 key。通常,用一个随机字符串作为它的值就够了。要在多条路由中共享计数器,我们可以使用相同的前缀。在这种情况下,请确保这些路由的 `limitCountRedis` 插件配置相同。 |
| rules | Rule || min_items: 1, max_items: 8 | 规则 |
| failureModeDeny | bool || | 默认情况下,如果访问 Redis 失败,会放行请求。该值为 true 时,会拒绝请求。 |
| enableLimitQuotaHeaders | bool || | 是否设置限流额度相关的响应头 |
| username | string || | 用于访问 Redis 的用户名 |
| password | string || | 用于访问 Redis 的密码 |
| tls | bool || | 是否通过 TLS 访问 Redis |
| tlsSkipVerify | bool || | 通过 TLS 访问 Redis 时是否跳过验证 |
| statusOnError | [StatusCode](../type.md#statuscode) || | 当无法访问 Redis 且 `failureModeDeny` 为 true 时,拒绝请求使用的状态码。默认为 500. |
| rateLimitedStatus | [StatusCode](../type.md#statuscode) || | 因限流产生的拒绝响应的状态码。默认为 429. 该配置仅在不小于 400 时生效。 |

每个规则的统计是独立的。当任一规则的额度用完后,就会触发限流操作。因限流产生的拒绝的响应中会包含 header `x-envoy-ratelimited: true`。如果配置了 `enableLimitQuotaHeaders``true` 且访问 Redis 成功,所有响应中都会包括下面三个头:
| 名称 | 类型 | 必选 | 校验规则 | 说明 |
|--------------------------------|-------------------------------------|-----|----------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------|
| address | string || | Redis 地址。`address``cluster` 只能配置一个。 |
| cluster | Cluster || | Redis cluster 配置。`address``cluster` 只能配置一个。 |
| prefix | string || min_len: 1, max_len: 128 | 该字段将用作 Redis key 的前缀。引入这个字段是为了在重新创建路由时不会重置计数器,因为新的限制统计将使用与前一个相同的 key。通常,用一个随机字符串作为它的值就够了。要在多条路由中共享计数器,我们可以使用相同的前缀。在这种情况下,请确保这些路由的 `limitCountRedis` 插件配置相同。 |
| rules | Rule || min_items: 1, max_items: 8 | 规则 |
| failureModeDeny | bool || | 默认情况下,如果访问 Redis 失败,会放行请求。该值为 true 时,会拒绝请求。 |
| enableLimitQuotaHeaders | bool || | 是否设置限流额度相关的响应头 |
| username | string || | 用于访问 Redis 的用户名 |
| password | string || | 用于访问 Redis 的密码 |
| tls | bool || | 是否通过 TLS 访问 Redis |
| tlsSkipVerify | bool || | 通过 TLS 访问 Redis 时是否跳过验证 |
| statusOnError | [StatusCode](../type.md#statuscode) || | 当无法访问 Redis 且 `failureModeDeny` 为 true 时,拒绝请求使用的状态码。默认为 500. |
| rateLimitedStatus | [StatusCode](../type.md#statuscode) || | 因限流产生的拒绝响应的状态码。默认为 429. 该配置仅在不小于 400 时生效。 |
| disableXEnvoyRatelimitedHeader | bool || | 触发限流时是否关闭`x-envoy-ratelimited`的响应头 |

每个规则的统计是独立的。当任一规则的额度用完后,就会触发限流操作。因限流产生的拒绝的响应中会包含 header `x-envoy-ratelimited: true`(可配置关闭)。如果配置了 `enableLimitQuotaHeaders``true` 且访问 Redis 成功,所有响应中都会包括下面三个头:

* `x-ratelimit-limit`:表示当前应用的限流规则。格式为“当前剩余额度最少的规则,(规则额度;w=时间窗口){1 个或多个规则}”,例如 `2, 2;w=60`
* `x-ratelimit-remaining`:表示当前剩余额度最少的规则的剩余额度,最小值为 `0`
27 changes: 20 additions & 7 deletions types/plugins/limitcountredis/config.pb.go
2 changes: 2 additions & 0 deletions types/plugins/limitcountredis/config.pb.validate.go
2 changes: 2 additions & 0 deletions types/plugins/limitcountredis/config.proto
Original file line number Diff line number Diff line change
@@ -58,4 +58,6 @@ message Config {

// There is no special reason to limit the length <=128, just to avoid too long string
string prefix = 12 [(validate.rules).string = {min_len: 1, max_len: 128}];

bool disable_x_envoy_ratelimited_header = 13;
}

0 comments on commit b99be34

Please sign in to comment.