Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: limit-count plugin with redis cluster support tls/ssl #8558

Merged
merged 15 commits into from
Jan 3, 2023
6 changes: 6 additions & 0 deletions apisix/plugins/limit-count/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,12 @@ local policy_to_additional_properties = {
redis_cluster_name = {
type = "string",
},
redis_cluster_ssl = {
type = "boolean", default = false,
},
redis_cluster_ssl_verify = {
type = "boolean", default = false,
},
},
required = {"redis_cluster_nodes", "redis_cluster_name"},
},
Expand Down
4 changes: 4 additions & 0 deletions apisix/plugins/limit-count/limit-count-redis-cluster.lua
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ local function new_redis_cluster(conf)
read_timeout = conf.redis_timeout,
auth = conf.redis_password,
dict_name = "plugin-limit-count-redis-cluster-slot-lock",
connect_opts = {
ssl = conf.redis_cluster_ssl,
ssl_verify = conf.redis_cluster_ssl_verify,
}
}

for i, conf_item in ipairs(conf.redis_cluster_nodes) do
Expand Down
50 changes: 50 additions & 0 deletions ci/pod/docker-compose.plugin.yml
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,56 @@ services:
CONTEXT_MODE: "self-host"
FUNC_CONTEXT: "{\"name\":\"HelloWorld\",\"version\":\"v1.0.0\",\"port\":\"8080\",\"runtime\":\"Knative\"}"

## RedisCluster Enable TLS
redis-node-0:
image: docker.io/bitnami/redis-cluster:7.0
volumes:
- ./t/certs:/certs
environment:
- 'ALLOW_EMPTY_PASSWORD=yes'
- 'REDIS_NODES=redis-node-0 redis-node-1 redis-node-2'
- 'REDIS_TLS_ENABLED=yes'
- 'REDIS_TLS_CERT_FILE=/certs/mtls_server.crt'
- 'REDIS_TLS_KEY_FILE=/certs/mtls_server.key'
- 'REDIS_TLS_CA_FILE=/certs/mtls_ca.crt'
- 'REDIS_TLS_AUTH_CLIENTS=no'
ports:
- '7000:6379'

redis-node-1:
image: docker.io/bitnami/redis-cluster:7.0
volumes:
- ./t/certs:/certs
environment:
- 'ALLOW_EMPTY_PASSWORD=yes'
- 'REDIS_NODES=redis-node-0 redis-node-1 redis-node-2'
- 'REDIS_TLS_ENABLED=yes'
- 'REDIS_TLS_CERT_FILE=/certs/mtls_server.crt'
- 'REDIS_TLS_KEY_FILE=/certs/mtls_server.key'
- 'REDIS_TLS_CA_FILE=/certs/mtls_ca.crt'
- 'REDIS_TLS_AUTH_CLIENTS=no'
ports:
- '7001:6379'

redis-node-2:
image: docker.io/bitnami/redis-cluster:7.0
volumes:
- ./t/certs:/certs
depends_on:
- redis-node-0
- redis-node-1
environment:
- 'ALLOW_EMPTY_PASSWORD=yes'
- 'REDIS_CLUSTER_REPLICAS=0'
- 'REDIS_NODES=redis-node-0 redis-node-1 redis-node-2'
- 'REDIS_CLUSTER_CREATOR=yes'
- 'REDIS_TLS_ENABLED=yes'
- 'REDIS_TLS_CERT_FILE=/certs/mtls_server.crt'
- 'REDIS_TLS_KEY_FILE=/certs/mtls_server.key'
- 'REDIS_TLS_CA_FILE=/certs/mtls_ca.crt'
- 'REDIS_TLS_AUTH_CLIENTS=no'
ports:
- '7002:6379'

networks:
apisix_net:
Expand Down
2 changes: 2 additions & 0 deletions docs/en/latest/plugins/limit-count.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ The `limit-count` Plugin limits the number of requests to your service by a give
| redis_timeout | integer | False | 1000 | [1,...] | Timeout in milliseconds for any command submitted to the Redis server. Used when the `policy` attribute is set to `redis` or `redis-cluster`. |
| redis_cluster_nodes | array | required when `policy` is `redis-cluster` | | | Addresses of Redis cluster nodes. Used when the `policy` attribute is set to `redis-cluster`. |
| redis_cluster_name | string | required when `policy` is `redis-cluster` | | | Name of the Redis cluster service nodes. Used when the `policy` attribute is set to `redis-cluster`. |
| redis_cluster_ssl | boolean | False | false | | If set to `true`, then uses SSL to connect to redis-cluster. Used when the `policy` attribute is set to `redis-cluster`. |
| redis_cluster_ssl_verify | boolean | False | false | | If set to `true`, then verifies the validity of the server SSL certificate. Used when the `policy` attribute is set to `redis-cluster`. |

## Enabling the Plugin

Expand Down
2 changes: 2 additions & 0 deletions docs/zh/latest/plugins/limit-count.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ description: 本文介绍了 Apache APISIX limit-count 插件的相关操作,
| redis_timeout | integer | 否 | 1000 | [1,...] | 当 `policy` 设置为 `redis` 或 `redis-cluster` 时,Redis 服务节点的超时时间(以毫秒为单位)。|
| redis_cluster_nodes | array | 否 | | | 当使用 `redis-cluster` 限速策略时,Redis 集群服务节点的地址列表(至少需要两个地址)。**当 `policy` 属性设置为 `redis-cluster` 时必选。**|
| redis_cluster_name | string | 否 | | | 当使用 `redis-cluster` 限速策略时,Redis 集群服务节点的名称。**当 `policy` 设置为 `redis-cluster` 时必选。**|
| redis_cluster_ssl | boolean | 否 | false | | 当使用 `redis-cluster` 限速策略时, 如果设置为 true,则使用 SSL 连接到 `redis-cluster` |
| redis_cluster_ssl_verify | boolean | 否 | false | | 当使用 `redis-cluster` 限速策略时,如果设置为 true,则验证服务器 SSL 证书的有效性 |

## 启用插件

Expand Down
158 changes: 158 additions & 0 deletions t/plugin/limit-count-redis-cluster.t
Original file line number Diff line number Diff line change
Expand Up @@ -384,3 +384,161 @@ GET /hello
hello world
--- error_log
connection refused



=== TEST 12: set route, use error type for redis_cluster_ssl and redis_cluster_ssl_verify
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"limit-count": {
"count": 2,
"time_window": 60,
"rejected_code": 503,
"key": "remote_addr",
"policy": "redis-cluster",
"redis_timeout": 1001,
"redis_cluster_nodes": [
"127.0.0.1:7000",
"127.0.0.1:7001"
],
"redis_cluster_name": "redis-cluster-1",
"redis_cluster_ssl": "true",
"redis_cluster_ssl_verify": "false"
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)

if code >= 300 then
ngx.status = code
end
ngx.print(body)
}
}
--- error_code: 400
--- response_body
{"error_msg":"failed to check the configuration of plugin limit-count err: else clause did not match"}



=== TEST 13: set route, redis_cluster_ssl_verify is true(will cause ssl handshake err), with enable degradation switch
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"uri": "/hello",
"plugins": {
"limit-count": {
"count": 2,
"time_window": 60,
"rejected_code": 503,
"key": "remote_addr",
"policy": "redis-cluster",
"allow_degradation": true,
"redis_timeout": 1001,
"redis_cluster_nodes": [
"127.0.0.1:7000",
"127.0.0.1:7001"
],
"redis_cluster_name": "redis-cluster-1",
"redis_cluster_ssl": true,
"redis_cluster_ssl_verify": true
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}]]
)

if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed



=== TEST 14: enable degradation switch for TEST 13
--- request
GET /hello
--- response_body
hello world
--- error_log
failed to do ssl handshake



=== TEST 15: set route, with redis_cluster_nodes and redis_cluster_name redis_cluster_ssl and redis_cluster_ssl_verify
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"uri": "/hello",
"plugins": {
"limit-count": {
"count": 2,
"time_window": 60,
"rejected_code": 503,
"key": "remote_addr",
"policy": "redis-cluster",
"redis_timeout": 1001,
"redis_cluster_nodes": [
"127.0.0.1:7000",
"127.0.0.1:7001"
],
"redis_cluster_name": "redis-cluster-1",
"redis_cluster_ssl": true,
"redis_cluster_ssl_verify": false
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}]]
)

if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed



=== TEST 16: up the limit
--- pipelined_requests eval
["GET /hello", "GET /hello", "GET /hello", "GET /hello"]
--- error_code eval
[200, 200, 503, 503]