共计 5080 个字符,预计需要花费 13 分钟才能阅读完成。

之前写的ip白名单用的本地nginx内存空间,更改不方便,今日尝试用lua-resty-redis模块把IP黑白名单写到redis内,这样就可以通过操作redis来实现IP的增删改查。之后也可以让开发在项目管理端写个IP名单管理页,这样也省了运维去直接操作redis
此处演示下redis IP黑名单操作,为了存储IP,此处在redis中使用集合数据类型来存储
Redis集合
redis的Set是String类型的无序集合(zset则是有序的),集合成员是唯一,所以Set类的元素不会重复。而且redis中的Set是通过哈希表实现的,对于增删查的复杂度是O(1)。
增
# 127.0.0.1:6379> SADD key member [member ...]
127.0.0.1:6379> SADD block-ip-list 192.168.44.1
(integer) 1
127.0.0.1:6379> SADD block-ip-list 192.168.44.2 192.168.44.3
(integer) 1
删
# 127.0.0.1:6379> SREM key member [member ...]
127.0.0.1:6379> SREM block-ip-list 192.168.44.3
(integer) 1
查
# 127.0.0.1:6379> SISMEMBER key member
127.0.0.1:6379> SISMEMBER block-ip-list 192.168.44.3
(integer) 0
127.0.0.1:6379> SISMEMBER block-ip-list 192.168.44.1
(integer) 1
# 127.0.0.1:6379> SMEMBERS key
127.0.0.1:6379> SMEMBERS block-ip-list
1) "192.168.44.1"
2) "192.168.44.2"
lua-resty-redis调用redis集合存储IP名单
使用sismember方法
[root@nginx-cluster lua]# cat ip_acl_redis.lua
local redis = require "resty.redis"
local red = redis:new()
red:set_timeout(1000,1000,1000) -- 1 sec
local ok,err = red:connect("127.0.0.1",6379)
if not ok then
ngx.say("failed to connect: ",err)
return
end
ngx.log(ngx.INFO, " ok: ", ok, " type(ok): ", type(ok)," err: ", err)
--- 获取代理头部中透传的真实客户端地址
local headers=ngx.req.get_headers()
local ip = headers["X-REAL-IP"] or headers["X_FORWARDED_FOR"] or ngx.var.remote_addr
--- 判断ip是否set中的元素,若存在则返回为1,若不存在则返回0
local res, err = red:sismember('block-ip-list', ip)
if 1 == res then
ngx.log(ngx.INFO, "client ip in block-ip-list: ", ip)
ngx.exit(ngx.HTTP_FORBIDDEN)
else
ngx.log(ngx.INFO, "client ip not in block-ip-list: ", ip)
end
location块内容
location /sayHello {
access_by_lua_file lua/ip_acl_redis.lua;
content_by_lua_block {
ngx.say("Allow Operating")
ngx.exit(ngx.OK)
}
}
模拟测试
正常访问
[root@nginx-cluster conf.d]# curl 127.0.0.1:8086/sayHello
Allow Operating
# 查看日志
2021/09/08 12:07:55 [info] 3401#0: *1 [lua] ip_acl_redis.lua:9: ok: 1 type(ok): number err: nil, client: 127.0.0.1, server: , request: "GET /sayHello HTTP/1.1", host: "127.0.0.1:8086"
2021/09/08 12:07:55 [info] 3401#0: *1 [lua] ip_acl_redis.lua:21: client ip not in block-ip-list: 127.0.0.1, client: 127.0.0.1, server: , request: "GET /sayHello HTTP/1.1", host: "127.0.0.1:8086"
2021/09/08 12:07:55 [info] 3401#0: *1 client 127.0.0.1 closed keepalive connection
在redis中将ip加入block-ip-list集合中
[root@nginx-cluster conf.d]# redis-cli
127.0.0.1:6379> SADD block-ip-list 127.0.0.1
(integer) 1
127.0.0.1:6379> SMEMBERS block-ip-list
1) "127.0.0.1"
2) "192.168.44.1"
3) "192.168.44.2"
此时测试就会收到403
[root@nginx-cluster conf.d]# curl 127.0.0.1:8086/sayHello
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>openresty/1.17.8.2</center>
</body>
</html>
# 对应日志
2021/09/08 12:13:20 [info] 3402#0: *3 [lua] ip_acl_redis.lua:9: ok: 1 type(ok): number err: nil, client: 127.0.0.1, server: , request: "GET /sayHello HTTP/1.1", host: "127.0.0.1:8086"
2021/09/08 12:13:20 [info] 3402#0: *3 [lua] ip_acl_redis.lua:18: client ip in block-ip-list: 127.0.0.1, client: 127.0.0.1, server: , request: "GET /sayHello HTTP/1.1", host: "127.0.0.1:8086"
2021/09/08 12:13:20 [info] 3402#0: *3 client 127.0.0.1 closed keepalive connection
提取为模块
ip_acl module
[root@nginx-cluster lua]# cat comm/ip_acl.lua
local _M = {}
function _M.is_member(client, ip_set, client_ip)
local res, err = client:sismember(ip_set, client_ip)
if 1 == res then
return true
else
return false
end
end
function _M.redis_client(host,port,pass)
local redis = require "resty.redis"
local client = redis:new()
client:set_timeout(1000,1000,1000) -- 1 sec
local ok,err = client:connect(host,port)
if not ok then
ngx.say("failed to connect: ",err)
return
end
ngx.log(ngx.INFO, " ok: ", ok, " type(ok): ", type(ok)," err: ", err)
return client
end
return _M
lua脚本文件
[root@nginx-cluster lua]# cat ip_acl_redis2.lua
local param = require("comm.ip_acl")
local client = param.redis_client("127.0.0.1", 6379, "")
--- 设置redis名单 keyname
local keyname
local keyname = nil == keyname and ngx.var.host..":"..ngx.var.server_port..":"..ngx.var.uri or keyname
local ip_set = "ip-set:"..keyname
ngx.log(ngx.INFO, "ip_set: ", ip_set)
--- 获取代理头部中透传的真实客户端地址
local headers=ngx.req.get_headers()
local client_ip = headers["X-REAL-IP"] or headers["X_FORWARDED_FOR"] or ngx.var.remote_addr
--- 判断ip是否set中的元素,若为真则返回为1
if param.is_member(client,ip_set,client_ip) then
ngx.log(ngx.INFO, "client ip : "..client_ip.." is in set: "..ip_set)
ngx.exit(ngx.HTTP_FORBIDDEN)
return
end
此时对应的日志
2021/09/08 15:13:20 [info] 15408#0: *5 [lua] ip_acl.lua:21: redis_client(): ok: 1 type(ok): number err: nil, client: 127.0.0.1, server: , request: "GET /sayHi HTTP/1.1", host: "127.0.0.1:8085"
2021/09/08 15:13:20 [info] 15408#0: *5 [lua] ip_acl_redis2.lua:20: ip_set: ip-set:127.0.0.1:8085:/sayHi, client: 127.0.0.1, server: , request: "GET /sayHi HTTP/1.1", host: "127.0.0.1:8085"
2021/09/08 15:13:20 [info] 15408#0: *5 [lua] ip_acl_redis2.lua:28: client ip : 127.0.0.1 is in set: ip-set:127.0.0.1:8085:/sayHi, client: 127.0.0.1, server: , request: "GET /sayHi HTTP/1.1", host: "127.0.0.1:8085"
2022/12/28 20:12:00 [info] 15408#0: *5 client 127.0.0.1 closed keepalive connection
2021/09/08 15:13:25 [info] 15408#0: *7 [lua] ip_acl.lua:21: redis_client(): ok: 1 type(ok): number err: nil, client: 192.168.44.145, server: , request: "GET /sayHi HTTP/1.1", host: "192.168.44.145:8085"
2021/09/08 15:13:25 [info] 15408#0: *7 [lua] ip_acl_redis2.lua:20: ip_set: ip-set:192.168.44.145:8085:/sayHi, client: 192.168.44.145, server: , request: "GET /sayHi HTTP/1.1", host: "192.168.44.145:8085"
2021/09/08 15:13:25 [info] 15408#0: *7 client 192.168.44.145 closed keepalive connection
正文完
隐私政策
留言板
金色传说
kubernetes
terraform
云生原
helm
代码编程
Java
Python
Shell
DevOps
Ansible
Gitlab
Jenkins
运维
老司机
Linux 杂锦
Nginx
数据库
elasticsearch
监控
上帝视角
DJI FPV
DJI mini 3 pro
关于本站