热爱技术,追求卓越
不断求索,精益求精

在原nginx基础上实现lua+redis拦截ip黑名单,非openresty 方式

背景,原来的nginx在生产环境已经正常运行,需要扩展lua实现ip黑名单拦截,原来nginx版本是1.18.0,打算使用原版本的源码重新编译nginx实现扩展。本次扩展还同时升级了OpenSSL,升级后的nginx信息如下:

nginx version: nginx/1.18.0
built by gcc 11.2.0 (Ubuntu 11.2.0-19ubuntu1) 
built with OpenSSL 3.0.2 15 Mar 2022
TLS SNI support enabled
configure arguments: --with-cc-opt='-Wno-error -Wno-deprecated-declarations' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-compat --with-debug --with-pcre-jit --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_sub_module --add-module=/usr/local/src/nginx-modules/ngx_devel_kit-0.3.1 --add-module=/usr/local/src/nginx-modules/lua-nginx-module-0.10.14

安装luajit-2.0.4

本次选用安装luajit-2.0.4:

wget -c http://luajit.org/download/LuaJIT-2.0.4.tar.gz
tar xzvf LuaJIT-2.0.4.tar.gz
cd LuaJIT-2.0.4
make install PREFIX=/usr/local/luajit

环境变量设置,在/etc/profile文件内增加如下:

export LUAJIT_LIB=/usr/local/luajit/lib
export LUAJIT_INC=/usr/local/luajit/include/luajit-2.0

使配置生效

source /etc/profile

Nginx Module下载

NDK(nginx development kit)模块是一个拓展nginx服务器核心功能的模块,第三方模块开发可以基于它来快速实现。NDK提供函数和宏处理一些基本任务,减轻第三方模块开发的代码量。

$ mkdir -p /usr/local/src/nginx-modules
$ cd /usr/local/src/nginx-modules
$ wget https://github.com/vision5/ngx_devel_kit/archive/v0.3.1.tar.gz

# 上面的地址如果下载不了,可以使用以下加速地址
$ wget https://github.91chifun.workers.dev/https://github.com//vision5/ngx_devel_kit/archive/refs/tags/v0.3.1.tar.gz
$ tar -xvf v0.3.1.tar.gz

lua-nginx-module,将Lua的功能嵌入到Nginx HTTP服务器中。

$ cd /usr/local/src/nginx-modules
$ wget https://github.com/openresty/lua-nginx-module/archive/v0.10.14.tar.gz

# 上面的地址如果下载不了,可以使用以下加速地址
$ wget https://github.91chifun.workers.dev/https://github.com//openresty/lua-nginx-module/archive/refs/tags/v0.10.14.tar.gz
$ tar -xvf v0.10.14.tar.gz

Nginx编译配置和测试

检查当前所用的nginx版本

nginx -v
nginx version: nginx/1.18.0 (Ubuntu)

使用的是1.18.0,所以下载1.18.0

 cd /usr/local/src
 wget https://nginx.org/download/nginx-1.18.0.tar.gz
 tar -xvf nginx-1.18.0.tar.gz && cd nginx-1.18.0

检查原来安装的nginx的config参数:

nginx -V

如下:

nginx version: nginx/1.18.0 (Ubuntu)
built with OpenSSL 3.0.2 15 Mar 2022
TLS SNI support enabled
configure arguments: --with-cc-opt='-g -O2 -ffile-prefix-map=/build/nginx-9P0wNJ/nginx-1.18.0=. -flto=auto -ffat-lto-objects -flto=auto -ffat-lto-objects -fstack-protector-strong -Wformat -Werror=format-security -fPIC -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-Bsymbolic-functions -flto=auto -ffat-lto-objects -flto=auto -Wl,-z,relro -Wl,-z,now -fPIC' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-compat --with-debug --with-pcre-jit --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --add-dynamic-module=/build/nginx-9P0wNJ/nginx-1.18.0/debian/modules/http-geoip2 --with-http_addition_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_sub_module

复制出来,修改后,增加模块

./configure --with-cc-opt='-Wno-error -Wno-deprecated-declarations' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-compat --with-debug --with-pcre-jit --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_sub_module --add-module=/usr/local/src/nginx-modules/ngx_devel_kit-0.3.1 --add-module=/usr/local/src/nginx-modules/lua-nginx-module-0.10.14

make,但不要make install;上面增加“–with-cc-opt=’-Wno-error -Wno-deprecated-declarations’”这个选项是因为openssl版本高,nginx编译报错.

在nginx检测配置的过程中,发现找不到lua的依赖库,直接简单粗暴:

apt-get install lua*

IP拦截

在nginx.conf的http下增”lua_shared_dict ip_blacklist 1m;”,如下:

http {
        #由 Nginx 进程分配一块 1M 大小的共享内存空间,用来缓存 IP 黑名单
        lua_shared_dict ip_blacklist 1m;

由 Nginx 进程分配一块 1M 大小的共享内存空间,用来缓存 IP 黑名单。

在需要拦截的server下增加如下测试:

location /ipblacklist {
        access_by_lua_file /var/www/data/lua/ipblacklist.lua;
        default_type 'text/html';
        content_by_lua 'ngx.say("hello,lua")';
}

访问报错:

2022/10/13 10:40:43 [error] 304670#304670: *403 lua entry thread aborted: runtime error: /var/www/data/lua/ipblacklist.lua:25: module 'resty.redis' not found:
    no field package.preload['resty.redis']
    no file './resty/redis.lua'
    no file '/usr/share/luajit-2.1.0-beta3/resty/redis.lua'
    no file '/usr/local/share/lua/5.1/resty/redis.lua'
    no file '/usr/local/share/lua/5.1/resty/redis/init.lua'
    no file '/usr/share/lua/5.1/resty/redis.lua'
    no file '/usr/share/lua/5.1/resty/redis/init.lua'
    no file './resty/redis.so'
    no file '/usr/local/lib/lua/5.1/resty/redis.so'
    no file '/usr/lib/x86_64-linux-gnu/lua/5.1/resty/redis.so'
    no file '/usr/local/lib/lua/5.1/loadall.so'
    no file './resty.so'
    no file '/usr/local/lib/lua/5.1/resty.so'
    no file '/usr/lib/x86_64-linux-gnu/lua/5.1/resty.so'
    no file '/usr/local/lib/lua/5.1/loadall.so'

到lua的share目录,下载lua-resty-redis

cd /usr/share/lua/5.1
git clone https://github.com/openresty/lua-resty-redis.git

在nginx的nginx.conf的http下增加即可:

http {

        ##
        # Basic Settings
        ##
        #由 Nginx 进程分配一块 1M 大小的共享内存空间,用来缓存 IP 黑名单
        lua_shared_dict ip_blacklist 1m;
        lua_package_path "/usr/share/lua/5.1/lua-resty-redis/lib/?.lua;;";

lua访问redis实现拦截脚本

我们这里的脚本文件放在/var/www/data/lua目录下,配置的时候根据自己的情况进行选择。此处redis中存放的ip信息是通过hkeys获取,考虑到后期可能会增加更多个性化的功能,所以在redis中使用hash存储。

lua脚本如下:

local redis_host = "redis的IP"
local redis_port = 6379

-- connection timeout for redis in ms.don't set this too highl

local redis_connection_timeout = 100

-- check a set with this key for blacklist entries

local redis_key = "TRSTECH_MT_IP_GUILTY"

-- cache lookups for this many seconds

local cache_ttl = 60

-- end configuration

local ip = ngx.var.remote_addr
local ip_blacklist = ngx.shared.ip_blacklist
local last_update_time = ip_blacklist:get("last_update_time");

-- only update ip_blacklist from Redis once every cache_ttl seconds:
if last_update_time ==  nil or last_update_time < ( ngx.now() - cache_ttl ) then

  local redis = require "resty.redis";
  local red = redis:new();

  red:set_timeout(redis_connect_timeout);

  local ok, err = red:connect(redis_host, redis_port);
  ok, err = red:auth("你的密码");
  if not ok then
    ngx.log(ngx.DEBUG, "Redis connection error while retrieving ip_blacklist: " .. err);
  else
    local new_ip_blacklist, err =  red:hkeys(redis_key);
    if err then
    ngx.log(ngx.DEBUG, "Redis read error while retrieving ip_blacklist: " .. err);
    else
      -- Peplace the locally stored ip_blacklist with the updated values:
      ip_blacklist:flush_all();
      for index, banned_ip in ipairs(new_ip_blacklist) do
      ip_blacklist:set(banned_ip, true);
      end
      -- update time
      ip_blacklist:set("last_update_time", ngx.now());
    end
  end
end

if ip_blacklist:get(ip) then
  ngx.log(ngx.DEBUG, "Banned IP detected and refused access: " ..  ip);
  return ngx.exit(ngx.HTTP_FORBIDDEN);
end

赞(2)
未经允许不得转载:LoveCTO » 在原nginx基础上实现lua+redis拦截ip黑名单,非openresty 方式

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

热爱技术 追求卓越 精益求精