Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion apisix/plugins/limit-count/util.lua
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ function _M.redis_cli(conf)
-- so connections with different databases, credentials or TLS settings
-- must not share the default host:port keepalive pool, otherwise a
-- reused connection may be bound to an unexpected database or user, or
-- skip the expected certificate verification
-- skip the expected certificate verification / present the wrong SNI
local scheme = "redis"
if conf.redis_ssl then
scheme = conf.redis_ssl_verify and "rediss-verify" or "rediss"
Expand All @@ -56,11 +56,23 @@ function _M.redis_cli(conf)
-- digest instead of the plaintext credentials in the pool name
pool = pool .. "#" .. crc32((conf.redis_username or "") .. ":" .. conf.redis_password)
end
if conf.redis_ssl and conf.redis_server_name then
pool = pool .. "#" .. conf.redis_server_name
end

local server_name
if conf.redis_ssl then
server_name = conf.redis_server_name or conf.redis_host
if core.utils.parse_ipv4(server_name) or core.utils.parse_ipv6(server_name) then
server_name = nil
end
end

local sock_opts = {
ssl = conf.redis_ssl,
ssl_verify = conf.redis_ssl_verify,
pool = pool,
server_name = server_name,
}

local ok, err = red:connect(conf.redis_host, conf.redis_port or 6379, sock_opts)
Expand Down
3 changes: 3 additions & 0 deletions apisix/utils/redis-schema.lua
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ local policy_to_additional_properties = {
redis_ssl_verify = {
type = "boolean", default = false,
},
redis_server_name = {
type = "string", minLength = 1,
},
redis_keepalive_timeout = {
type = "integer", minimum = 1000, default = 10000
},
Expand Down
14 changes: 13 additions & 1 deletion apisix/utils/redis.lua
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ local function redis_cli(conf)
-- so connections with different databases, credentials or TLS settings
-- must not share the default host:port keepalive pool, otherwise a
-- reused connection may be bound to an unexpected database or user, or
-- skip the expected certificate verification
-- skip the expected certificate verification / present the wrong SNI
local scheme = "redis"
if conf.redis_ssl then
scheme = conf.redis_ssl_verify and "rediss-verify" or "rediss"
Expand All @@ -42,11 +42,23 @@ local function redis_cli(conf)
-- digest instead of the plaintext credentials in the pool name
pool = pool .. "#" .. crc32((conf.redis_username or "") .. ":" .. conf.redis_password)
end
if conf.redis_ssl and conf.redis_server_name then
pool = pool .. "#" .. conf.redis_server_name
end

local server_name
if conf.redis_ssl then
server_name = conf.redis_server_name or conf.redis_host
if core.utils.parse_ipv4(server_name) or core.utils.parse_ipv6(server_name) then
server_name = nil
end
end

local sock_opts = {
ssl = conf.redis_ssl,
ssl_verify = conf.redis_ssl_verify,
pool = pool,
server_name = server_name,
}

local ok, err = red:connect(conf.redis_host, conf.redis_port or 6379, sock_opts)
Expand Down
1 change: 1 addition & 0 deletions docs/en/latest/plugins/ai-cache.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ For the `passthrough` protocol, `ai-proxy` forwards the client's request method,
| redis_timeout | integer | False | 1000 | >= 1 | Redis timeout value in milliseconds. |
| redis_ssl | boolean | False | false | | If true, use SSL to connect to Redis. |
| redis_ssl_verify | boolean | False | false | | If true, verify the Redis server SSL certificate. |
| redis_server_name | string | False | | | TLS SNI when `redis_ssl` is true. Defaults to `redis_host`. When `redis_ssl_verify` is true the certificate must also match this name, so set it when `redis_host` is an alias the certificate does not cover. |
| redis_keepalive_timeout | integer | False | 10000 | >= 1000 | Keepalive timeout, in milliseconds, for the Redis connection pool. |
| redis_keepalive_pool | integer | False | 100 | >= 1 | Maximum number of connections in the Redis keepalive pool. |

Expand Down
1 change: 1 addition & 0 deletions docs/en/latest/plugins/ai-rate-limiting.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ The `ai-rate-limiting` Plugin enforces token-based rate limiting for requests se
| redis_timeout | integer | False | 1000 | [1,...] | The Redis timeout value in milliseconds when `policy` is `redis` or `redis-cluster`. |
| redis_ssl | boolean | False | false | | If true, use SSL to connect to Redis when `policy` is `redis`. |
| redis_ssl_verify | boolean | False | false | | If true, verify the server SSL certificate when `policy` is `redis`. |
| redis_server_name | string | False | | | TLS SNI when `policy` is `redis` and `redis_ssl` is true. Defaults to `redis_host`. When `redis_ssl_verify` is true the certificate must also match this name, so set it when `redis_host` is an alias the certificate does not cover. |
| redis_cluster_nodes | array[string] | False | | | The list of Redis cluster nodes with at least one address. Required when `policy` is `redis-cluster`. |
| redis_cluster_name | string | False | | | The name of the Redis cluster. Required when `policy` is `redis-cluster`. |
| redis_cluster_ssl | boolean | False | false | | If true, use SSL to connect to Redis when `policy` is `redis-cluster`. |
Expand Down
1 change: 1 addition & 0 deletions docs/en/latest/plugins/graphql-limit-count.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ This Plugin shares the same schema as the [limit-count](./limit-count.md) Plugin
| redis_password | string | False | | | Password of the Redis node. Used when `policy` is `redis` or `redis-cluster`. |
| redis_ssl | boolean | False | false | | When true, use SSL to connect to Redis. Used when `policy` is `redis`. |
| redis_ssl_verify | boolean | False | false | | When true, verify the Redis server SSL certificate. Used when `policy` is `redis`. |
| redis_server_name | string | False | | | TLS SNI when `policy` is `redis` and `redis_ssl` is true. Defaults to `redis_host`. When `redis_ssl_verify` is true the certificate must also match this name, so set it when `redis_host` is an alias the certificate does not cover. |
| redis_database | integer | False | 0 | >= 0 | The Redis database number. Used when `policy` is `redis`. |
| redis_timeout | integer | False | 1000 | [1,...] | Redis timeout in milliseconds. Used when `policy` is `redis` or `redis-cluster`. |
| redis_cluster_nodes | array[string] | False | | | List of Redis cluster node addresses. Required when `policy` is `redis-cluster`. |
Expand Down
1 change: 1 addition & 0 deletions docs/en/latest/plugins/limit-conn.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ The `limit-conn` Plugin limits the rate of requests by the number of concurrent
| redis_password | string | False | | | The password of the Redis node when `policy` is `redis` or `redis-cluster`. |
| redis_ssl | boolean | False | false | | If true, use SSL to connect to Redis when `policy` is `redis`. |
| redis_ssl_verify | boolean | False | false | | If true, verify the server SSL certificate when `policy` is `redis`. |
| redis_server_name | string | False | | | TLS SNI when `policy` is `redis` and `redis_ssl` is true. Defaults to `redis_host`. When `redis_ssl_verify` is true the certificate must also match this name, so set it when `redis_host` is an alias the certificate does not cover. |
| redis_database | integer | False | 0 | >= 0 | The database number in Redis when `policy` is `redis`. |
| redis_timeout | integer | False | 1000 | >= 1 | The Redis timeout value in milliseconds when `policy` is `redis` or `redis-cluster`. |
| redis_keepalive_timeout | integer | False | 10000 | >= 1000 | Keepalive timeout in milliseconds for Redis when `policy` is `redis` or `redis-cluster`. |
Expand Down
1 change: 1 addition & 0 deletions docs/en/latest/plugins/limit-count.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ Redis Sentinel, sliding windows, and delayed Redis synchronization are supported
| redis_password | string | False | | | The password of the Redis node when `policy` is `redis`, `redis-cluster`, or `redis-sentinel`. |
| redis_ssl | boolean | False | false | | If true, use SSL to connect to Redis when `policy` is `redis`. |
| redis_ssl_verify | boolean | False | false | | If true, verify the server SSL certificate when `policy` is `redis`. |
| redis_server_name | string | False | | | TLS SNI when `policy` is `redis` and `redis_ssl` is true. Defaults to `redis_host`. When `redis_ssl_verify` is true the certificate must also match this name, so set it when `redis_host` is an alias the certificate does not cover. |
| redis_database | integer | False | 0 | >= 0 | The database number in Redis when `policy` is `redis` or `redis-sentinel`. |
| redis_timeout | integer | False | 1000 | [1,...] | The Redis timeout value in milliseconds when `policy` is `redis` or `redis-cluster`. |
| redis_keepalive_timeout | integer | False | 10000 (`redis` and `redis-cluster`); 60000 (`redis-sentinel`) | >= 1000 (`redis` and `redis-cluster`); >= 1 (`redis-sentinel`) | Keepalive timeout in milliseconds for Redis connections. |
Expand Down
1 change: 1 addition & 0 deletions docs/en/latest/plugins/limit-req.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ The `limit-req` Plugin supports two modes of rate limiting:
| redis_password | string | False | | | The password of the Redis node when `policy` is `redis` or `redis-cluster`. |
| redis_ssl | boolean | False | false | | If true, use SSL to connect to Redis when `policy` is `redis`. |
| redis_ssl_verify | boolean | False | false | | If true, verify the server SSL certificate when `policy` is `redis`. |
| redis_server_name | string | False | | | TLS SNI when `policy` is `redis` and `redis_ssl` is true. Defaults to `redis_host`. When `redis_ssl_verify` is true the certificate must also match this name, so set it when `redis_host` is an alias the certificate does not cover. |
| redis_database | integer | False | 0 | >= 0 | The database number in Redis when `policy` is `redis`. |
| redis_timeout | integer | False | 1000 | [1,...] | The Redis timeout value in milliseconds when `policy` is `redis` or `redis-cluster`. |
| redis_keepalive_timeout | integer | False | 10000 | ≥ 1000 | Keepalive timeout in milliseconds for redis when `policy` is `redis` or `redis-cluster`. |
Expand Down
1 change: 1 addition & 0 deletions docs/zh/latest/plugins/ai-cache.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ import TabItem from '@theme/TabItem';
| redis_timeout | integer | 否 | 1000 | >= 1 | Redis 超时时间,单位为毫秒。 |
| redis_ssl | boolean | 否 | false | | 如果为 true,则使用 SSL 连接 Redis。 |
| redis_ssl_verify | boolean | 否 | false | | 如果为 true,则校验 Redis 服务器的 SSL 证书。 |
| redis_server_name | string | 否 | | | 当 `redis_ssl` 为 true 时使用的 TLS SNI。默认使用 `redis_host`。当 `redis_ssl_verify` 为 true 时,证书还必须与该名称匹配,因此当 `redis_host` 是证书未覆盖的别名时请设置此项。 |
| redis_keepalive_timeout | integer | 否 | 10000 | >= 1000 | Redis 连接池的保活超时时间,单位为毫秒。 |
| redis_keepalive_pool | integer | 否 | 100 | >= 1 | Redis 保活连接池中的最大连接数。 |

Expand Down
1 change: 1 addition & 0 deletions docs/zh/latest/plugins/graphql-limit-count.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ description: graphql-limit-count 插件使用固定窗口算法,基于 GraphQL
| redis_password | string | 否 | | | Redis 节点密码。`policy` 为 `redis` 或 `redis-cluster` 时使用。 |
| redis_ssl | boolean | 否 | false | | 为 true 时使用 SSL 连接 Redis。`policy` 为 `redis` 时使用。 |
| redis_ssl_verify | boolean | 否 | false | | 为 true 时验证 Redis 服务端 SSL 证书。`policy` 为 `redis` 时使用。 |
| redis_server_name | string | 否 | | | 当 `policy` 为 `redis` 且 `redis_ssl` 为 true 时使用的 TLS SNI。默认使用 `redis_host`。当 `redis_ssl_verify` 为 true 时,证书还必须与该名称匹配,因此当 `redis_host` 是证书未覆盖的别名时请设置此项。 |
| redis_database | integer | 否 | 0 | >= 0 | Redis 数据库编号。`policy` 为 `redis` 时使用。 |
| redis_timeout | integer | 否 | 1000 | [1,...] | Redis 超时时间(毫秒)。`policy` 为 `redis` 或 `redis-cluster` 时使用。 |
| redis_cluster_nodes | array[string] | 否 | | | Redis 集群节点地址列表。`policy` 为 `redis-cluster` 时必填。 |
Expand Down
1 change: 1 addition & 0 deletions docs/zh/latest/plugins/limit-conn.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ import TabItem from '@theme/TabItem';
| redis_password | string | 否 | | | 当 `policy` 为 `redis` 或 `redis-cluster` 时,Redis 节点的密码。|
| redis_ssl | boolean | 否 | false | | 如果为 true,则在 `policy` 为 `redis` 时使用 SSL 连接到 Redis。|
| redis_ssl_verify | boolean | 否 | false | | 如果为 true,则在 `policy` 为 `redis` 时验证服务器 SSL 证书。|
| redis_server_name | string | 否 | | | 当 `policy` 为 `redis` 且 `redis_ssl` 为 true 时使用的 TLS SNI。默认使用 `redis_host`。当 `redis_ssl_verify` 为 true 时,证书还必须与该名称匹配,因此当 `redis_host` 是证书未覆盖的别名时请设置此项。|
| redis_database | integer | 否 | 0 | >= 0 | 当 `policy` 为 `redis` 时,Redis 中的数据库编号。|
| redis_timeout | integer | 否 | 1000 | >= 1 | 当 `policy` 为 `redis` 或 `redis-cluster` 时,Redis 超时值(以毫秒为单位)。|
| redis_keepalive_timeout | integer | 否 | 10000 | >= 1000 | 当 `policy` 为 `redis` 或 `redis-cluster` 时,Redis 的空闲连接超时时间(以毫秒为单位)。|
Expand Down
1 change: 1 addition & 0 deletions docs/zh/latest/plugins/limit-count.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ APISIX 3.18.0 及后续版本支持 Redis Sentinel、滑动窗口和 Redis 延
| redis_password | string | 否 | | | 当 `policy` 为 `redis`、`redis-cluster` 或 `redis-sentinel` 时,Redis 节点的密码。 |
| redis_ssl | boolean | 否 | false | | 如果为 true,则在 `policy` 为 `redis` 时使用 SSL 连接 Redis。 |
| redis_ssl_verify | boolean | 否 | false | | 如果为 true,则在 `policy` 为 `redis` 时验证服务器 SSL 证书。 |
| redis_server_name | string | 否 | | | 当 `policy` 为 `redis` 且 `redis_ssl` 为 true 时使用的 TLS SNI。默认使用 `redis_host`。当 `redis_ssl_verify` 为 true 时,证书还必须与该名称匹配,因此当 `redis_host` 是证书未覆盖的别名时请设置此项。 |
| redis_database | integer | 否 | 0 | >= 0 | 当 `policy` 为 `redis` 或 `redis-sentinel` 时,Redis 中的数据库编号。 |
| redis_timeout | integer | 否 | 1000 | [1,...] | 当 `policy` 为 `redis` 或 `redis-cluster` 时,Redis 超时值(以毫秒为单位)。 |
| redis_keepalive_timeout | integer | 否 | `redis` 和 `redis-cluster` 为 10000;`redis-sentinel` 为 60000 | `redis` 和 `redis-cluster` >= 1000;`redis-sentinel` >= 1 | Redis 空闲连接超时时间,单位为毫秒。 |
Expand Down
1 change: 1 addition & 0 deletions docs/zh/latest/plugins/limit-req.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ import TabItem from '@theme/TabItem';
| redis_password | string | 否 | | | 当 `policy` 为 `redis` 或 `redis-cluster` 时,Redis 节点的密码。|
| redis_ssl | boolean | 否 | false | | 如果为 true,则在 `policy` 为 `redis` 时使用 SSL 连接到 Redis。|
| redis_ssl_verify | boolean | 否 | false | | 如果为 true,则在 `policy` 为 `redis` 时验证服务器 SSL 证书。|
| redis_server_name | string | 否 | | | 当 `policy` 为 `redis` 且 `redis_ssl` 为 true 时使用的 TLS SNI。默认使用 `redis_host`。当 `redis_ssl_verify` 为 true 时,证书还必须与该名称匹配,因此当 `redis_host` 是证书未覆盖的别名时请设置此项。|
| redis_database | integer | 否 | 0 | >= 0 | 当 `policy` 为 `redis` 时,Redis 中的数据库编号。|
| redis_timeout | integer | 否 | 1000 | [1,...] | 当 `policy` 为 `redis` 或 `redis-cluster` 时,Redis 超时值(以毫秒为单位)。|
| redis_keepalive_timeout | integer | 否 | 10000 | ≥ 1000 | 当 `policy` 为 `redis` 或 `redis-cluster` 时,与 Redis 的空闲连接超时时间,单位为毫秒。|
Expand Down
41 changes: 41 additions & 0 deletions t/utils/redis-schema.t
Original file line number Diff line number Diff line change
Expand Up @@ -152,3 +152,44 @@ done
--- response_body
3600
60



=== TEST 3: redis_server_name is accepted for redis policy and rejected when empty
--- config
location /t {
content_by_lua_block {
local plugin = require("apisix.plugins.limit-count")

local ok, err = plugin.check_schema({
count = 2,
time_window = 60,
policy = "redis",
redis_host = "127.0.0.1",
redis_ssl = true,
redis_server_name = "redis.example.com",
})
if not ok then
ngx.say(err)
return
end
ngx.say("passed")

ok, err = plugin.check_schema({
count = 2,
time_window = 60,
policy = "redis",
redis_host = "127.0.0.1",
redis_ssl = true,
redis_server_name = "",
})
if ok then
ngx.say("empty redis_server_name should fail")
return
end
ngx.say("rejected")
}
}
--- response_body
passed
rejected
Loading
Loading