Skip to content

Commit

Permalink
feat: limit-count plugin with redis cluster support tls/ssl (#8558)
Browse files Browse the repository at this point in the history
Fixes #8413
  • Loading branch information
ronething authored Jan 3, 2023
1 parent 21b50e5 commit c0c906e
Show file tree
Hide file tree
Showing 6 changed files with 222 additions and 0 deletions.
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]

0 comments on commit c0c906e

Please sign in to comment.