5.2. Sniffer nginx kafka驱动支持

  • 了解 openresty
  • 安装 openresty
  • 测试 openresty 是否正常
  • 包含新的 nginx
    • 安装 openresty-kafka 模块
    • 导入 kafka.lua 等依赖
    • 修改 kafka.lua 中的配置
  • 原机有 nginx

    • 安装 lua
    • 重新编译 nginx 的环境依赖
    • 导入 kafka.lua 等依赖
    • 修改 kafka.lua 中的配置
    • 导入 openresty 依赖
    • 安装 lua-resty-kafka 模块
  • nginx 的配置

    • 新的 nginx 配置
    • 原有 nginx 配置
  • 解释如何收集流量以及计算
  • sniffer 相关配置
  • 排查错误

了解 openresty


OpenResty由 Nginx 核心加很多第三方模块组成,默认集成了Lua开发环境,使得Nginx可以作为一个Web Server使用. Nginx有很多的特性和好处,但是在Nginx上开发成了一个难题,Nginx模块需要用C开发,而且必须符合一系列复杂的规则,最重要的用C开发模块必须要熟悉Nginx的源代码,使得开发者对其望而生畏。为了开发人员方便,所以接下来我们要介绍一种整合了Nginx和lua的框架,那就是OpenResty,它帮我们实现了可以用lua的规范开发,实现各种业务,并且帮我们弄清楚各个模块的编译顺序.

安装 openresty


安装依赖 yum install readline-devel pcre-devel openssl-devel gcc

—1. 下载openresty源码: http://openresty.org/cn/download.html $ wget https://openresty.org/download/openresty-1.15.8.1rc1.tar.gz

— 2. 解压tar包 $ tar -zxvf openresty-1.15.8.1rc1.tar.gz

— 3. 配置编译选项,可以根据你的实际情况增加、减少相应的模块 $ ./configure —prefix=/opt/openresty —with-luajit —without-http_redis2_module —with-http_iconv_module

— 4. 编译并安装 $ make $ make install

测试安装是否正常

— 1. 修改配置文件如下: $ cat /opt/openresty/nginx/conf/nginx.conf worker_processes 1; error_log logs/error.log info;

events { worker_connections 1024; }

http { server { listen 8003;

  1. location / {
  2. content_by_lua 'ngx.say("hello world.")';
  3. }
  4. }

}

— 2. 启动nginx $ /opt/openresty/nginx/sbin/nginx

— 3. 检查nginx $ curl http://127.0.0.1:8003/ hello world.

出现 hello world 则是正常的

包含新的 nginx

安装 openresty-kafka 模块

  1. 首先在 github 上下载开源的 lua-resty-kafka wget https://github.com/doujiang24/lua-resty-kafka/archive/v0.06.tar.gz
  2. 然后解压 tar -zxvf v0.06.tar.gz
  3. 到以下目录 复制 cd lua-resty-kafka-0.06/lib/resty cp -rf kafka /opt/openresty/lualib/resty/ 这个目录是openresty的安装目录中的resty 请自行判断, 你安装在哪个位置, resty就对应在哪个位置
  4. 这样就完成了

导入 kafka.lua 等依赖

从nginx得到的流量转化成sniffer适用的格式, 先导入kafka.lua脚本 kafka.lua 的位置在 sniffer 的 lua 目录中 导入的位置是 /opt/openresty/lualib/

修改 kafka.lua 中的配置

在 kafka 脚本中的 kafka 的 IP 以及端口需要更改 vim kafka.lua, 修改以下地址

— 定义kafka broker地址

  1. local broker_list = {
  2. { host = "172.x.x.x", port = 9092 },
  3. }

原机有 nginx

安装 lua

实际上在下载 openresty 安装包的时候,里面其实已经依赖了lua了,只需要安装就好了 到解压 openresty 安装包中

  1. cd bundle/LuaJIT-2.1-20190228

如果版本不一致就是对一下 LuaJIT 的文件夹就好了

  1. make
  2. make install

安装好的环境依赖如下

  1. ==== Installing LuaJIT 2.1.0-beta3 to /usr/local ====
  2. mkdir -p /usr/local/bin /usr/local/lib /usr/local/include/luajit-2.1 /usr/local/share/man/man1 /usr/local/lib/pkgconfig /usr/local/share/luajit-2.1.0-beta3/jit /usr/local/share/lua/5.1 /usr/local/lib/lua/5.1
  3. cd src && install -m 0755 luajit /usr/local/bin/luajit-2.1.0-beta3
  4. cd src && test -f libluajit.a && install -m 0644 libluajit.a /usr/local/lib/libluajit-5.1.a || :
  5. rm -f /usr/local/lib/libluajit-5.1.so.2.1.0 /usr/local/lib/libluajit-5.1.so /usr/local/lib/libluajit-5.1.so.2
  6. cd src && test -f libluajit.so && \
  7. install -m 0755 libluajit.so /usr/local/lib/libluajit-5.1.so.2.1.0 && \
  8. ldconfig -n /usr/local/lib && \
  9. ln -sf libluajit-5.1.so.2.1.0 /usr/local/lib/libluajit-5.1.so && \
  10. ln -sf libluajit-5.1.so.2.1.0 /usr/local/lib/libluajit-5.1.so.2 || :
  11. cd etc && install -m 0644 luajit.1 /usr/local/share/man/man1
  12. cd etc && sed -e "s|^prefix=.*|prefix=/usr/local|" -e "s|^multilib=.*|multilib=lib|" luajit.pc > luajit.pc.tmp && \
  13. install -m 0644 luajit.pc.tmp /usr/local/lib/pkgconfig/luajit.pc && \
  14. rm -f luajit.pc.tmp
  15. cd src && install -m 0644 lua.h lualib.h lauxlib.h luaconf.h lua.hpp luajit.h /usr/local/include/luajit-2.1
  16. cd src/jit && install -m 0644 bc.lua bcsave.lua dump.lua p.lua v.lua zone.lua dis_x86.lua dis_x64.lua dis_arm.lua dis_arm64.lua dis_arm64be.lua dis_ppc.lua dis_mips.lua dis_mipsel.lua dis_mips64.lua dis_mips64el.lua vmdef.lua /usr/local/share/luajit-2.1.0-beta3/jit
  17. ln -sf luajit-2.1.0-beta3 /usr/local/bin/luajit
  18. ==== Successfully installed LuaJIT 2.1.0-beta3 to /usr/local ====

重新编译 nginx 的环境依赖

首先以下的相关依赖都是根据 nginx 默认的安装目录, 依赖去配置的, 如果有不同的地方, 需要自己配置一下.

  1. nginx 默认配置目录
  2. nginx path prefix: "/usr/local/nginx"
  3. nginx binary file: "/usr/local/nginx/sbin/nginx"
  4. nginx modules path: "/usr/local/nginx/modules"
  5. nginx configuration prefix: "/usr/local/nginx/conf"
  6. nginx configuration file: "/usr/local/nginx/conf/nginx.conf"
  7. nginx pid file: "/usr/local/nginx/logs/nginx.pid"
  8. nginx error log file: "/usr/local/nginx/logs/error.log"
  9. nginx http access log file: "/usr/local/nginx/logs/access.log"

下载 nginx 源码编译

  1. wget http://nginx.org/download/nginx-1.16.0.tar.gz
  2. cd nginx-1.16.0
  3. export LUAJIT_LIB=/usr/local/openresty/lualib/ export LUAJIT_INC=/usr/local/openresty/luajit/include/luajit-2.1/
  4. 重新配置依赖 要注意的是 openresty 之前放置的目录位置 /home/root
  5. ./configure --prefix=/usr/local/nginx --with-cc-opt=-O2 --add-module=/home/root/openresty-1.15.8.1rc1/bundle/ngx_devel_kit-0.3.1rc1 --add-module=/home/root/openresty-1.15.8.1rc1/bundle/echo-nginx-module-0.61 --add-module=/home/root/openresty-1.15.8.1rc1/bundle/xss-nginx-module-0.06 --add-module=/home/root/openresty-1.15.8.1rc1/bundle/ngx_coolkit-0.2 --add-module=/home/root/openresty-1.15.8.1rc1/bundle/set-misc-nginx-module-0.32 --add-module=/home/root/openresty-1.15.8.1rc1/bundle/form-input-nginx-module-0.12 --add-module=/home/root/openresty-1.15.8.1rc1/bundle/encrypted-session-nginx-module-0.08 --add-module=/home/root/openresty-1.15.8.1rc1/bundle/srcache-nginx-module-0.31 --add-module=/home/root/openresty-1.15.8.1rc1/bundle/ngx_lua-0.10.14 --add-module=/home/root/openresty-1.15.8.1rc1/bundle/ngx_lua_upstream-0.07 --add-module=/home/root/openresty-1.15.8.1rc1/bundle/headers-more-nginx-module-0.33 --add-module=/home/root/openresty-1.15.8.1rc1/bundle/array-var-nginx-module-0.05 --add-module=/home/root/openresty-1.15.8.1rc1/bundle/memc-nginx-module-0.19 --add-module=/home/root/openresty-1.15.8.1rc1/bundle/redis2-nginx-module-0.15 --add-module=/home/root/openresty-1.15.8.1rc1/bundle/redis-nginx-module-0.3.7 --add-module=/home/root/openresty-1.15.8.1rc1/bundle/rds-json-nginx-module-0.15 --add-module=/home/root/openresty-1.15.8.1rc1/bundle/rds-csv-nginx-module-0.09 --add-module=/home/root/openresty-1.15.8.1rc1/bundle/ngx_stream_lua-0.0.6 --with-ld-opt=-Wl,-rpath,/usr/local/lib/ --with-stream --with-stream_ssl_module --with-http_ssl_module
  6. 参数解释:
  7. prefix=/usr/local/nginxnginx安装目录
  8. add-module=/home/root/openresty-1.15.8.1rc1/bundle/:这个是刚刚下载的openresty安装包
  9. with-ld-opt=-Wl,-rpath,/usr/local/lib/:lua安装的路径,上面lua安装的时候,默认是这个位
  10. 置的
  11. 重新编译
  12. make
  13. 但切记不要 make install, 否则就覆盖了原有的nginx.
  14. 但切记不要 make install, 否则就覆盖了原有的nginx.
  15. 但切记不要 make install, 否则就覆盖了原有的nginx.
  16. 使用 objs/nginx -V 检验依赖是否正确
  17. nginx version: nginx/1.16.0
  18. built by gcc 7.3.0 (Ubuntu 7.3.0-27ubuntu1~18.04)
  19. built with OpenSSL 1.1.0g 2 Nov 2017
  20. TLS SNI support enabled
  21. configure arguments: --prefix=/usr/local/nginx --with-cc-opt=-O2 --add-module=/home/root/openresty-1.15.8.1rc1/bundle/ngx_devel_kit-0.3.1rc1 --add-module=/home/root/openresty-1.15.8.1rc1/bundle/echo-nginx-module-0.61 --add-module=/home/root/openresty-1.15.8.1rc1/bundle/xss-nginx-module-0.06 --add-module=/home/root/openresty-1.15.8.1rc1/bundle/ngx_coolkit-0.2 --add-module=/home/root/openresty-1.15.8.1rc1/bundle/set-misc-nginx-module-0.32 --add-module=/home/root/openresty-1.15.8.1rc1/bundle/form-input-nginx-module-0.12 --add-module=/home/root/openresty-1.15.8.1rc1/bundle/encrypted-session-nginx-module-0.08 --add-module=/home/root/openresty-1.15.8.1rc1/bundle/srcache-nginx-module-0.31 --add-module=/home/root/openresty-1.15.8.1rc1/bundle/ngx_lua-0.10.14 --add-module=/home/root/openresty-1.15.8.1rc1/bundle/ngx_lua_upstream-0.07 --add-module=/home/root/openresty-1.15.8.1rc1/bundle/headers-more-nginx-module-0.33 --add-module=/home/root/openresty-1.15.8.1rc1/bundle/array-var-nginx-module-0.05 --add-module=/home/root/openresty-1.15.8.1rc1/bundle/memc-nginx-module-0.19 --add-module=/home/root/openresty-1.15.8.1rc1/bundle/redis2-nginx-module-0.15 --add-module=/home/root/openresty-1.15.8.1rc1/bundle/redis-nginx-module-0.3.7 --add-module=/home/root/openresty-1.15.8.1rc1/bundle/rds-json-nginx-module-0.15 --add-module=/home/root/openresty-1.15.8.1rc1/bundle/rds-csv-nginx-module-0.09 --add-module=/home/root/openresty-1.15.8.1rc1/bundle/ngx_stream_lua-0.0.6 --with-ld-opt=-Wl,-rpath,/usr/local/lib/ --with-stream --with-stream_ssl_module --with-http_ssl_module
  22. 目前的依赖情况是这样的
  23. 备份之前的 nginx
  24. cd /usr/local/nginx/sbin/
  25. cp ./nginx ./nginx.old
  26. 覆盖 nginx
  27. cd /home/root/nginx-1.16.0/objs
  28. cp ./nginx /usr/local/nginx/sbin/
  29. 覆盖之后测试
  30. cd /usr/local/nginx/sbin
  31. ./nginx -t
  32. 可以得到是否有问题
  33. ./nginx 启动
  34. 测试 lua 模块
  35. cd /usr/local/nginx
  36. mkdir lua
  37. cd lua
  38. vim hello.lua
  39. 写入
  40. ngx.log(ngx.ERR,"hello");
  41. nginx文件中更改
  42. location / {
  43. root /workspace/hexo/public/; index index.html index.htm; access_by_lua_file lua/hello.lua;
  44. }
  45. 重启nginx
  46. 访问nginx监听的端口, 去查看错误日志, 正常的情况下是可以看到以下的结果
  47. 2019/05/09 11:39:26 [error] 14225#0: *1 [lua] hello.lua:1: hello, client: 127.0.0.1, server: localhost, request: "GET / HTTP/1.1", host: "127.0.0.1"

导入 kafka.lua 等依赖

  1. cd /usr/local/nginx/
  2. mkdir lua
  3. 导入路径为 /usr/local/nginx/lua
  4. 总共 1 个文件
  5. sniffer lua 目录中 导入

修改 kafka.lua 中的配置

在 kafka 脚本中的 kafka 的 IP 以及端口需要更改 vim kafka.lua, 修改以下地址

— 定义kafka broker地址 local broker_list = { { host = “172.x.x.x”, port = 9092 }, }

导入 openresty 依赖

首先安装 openresty 的目录是 /opt/openresty 所以以下命令都是按这个命令来了, 如果你是安装在其他地方, 请注意一下

cp -rf /opt/openresty/lualib/resty /usr/local/share/luajit-2.1.0-beta3/

如果不行请确认以下 luajit 的版本, 基本不会有啥问题

安装 lua-resty-kafka 模块

  1. 首先在 github 上下载开源的 lua-resty-kafka wget https://github.com/doujiang24/lua-resty-kafka/archive/v0.06.tar.gz
  2. 然后解压 tar -zxvf v0.06.tar.gz
  3. 到以下目录 复制 cd lua-resty-kafka-0.06/lib/resty cp -rf kafka /usr/local/share/luajit-2.1.0-beta3/resty/

这个目录是 luajit-2.1.0-beta3/resty/ 请自行判断, 你安装在哪个位置, resty就对应在哪个位置

  1. 这样就完成了

nginx 的配置

新的 nginx 配置

  1. 接下来需要修改nginx配置来启用 kafka.lua 脚本
  2. 首先需要开启错误日志 找到#error_log logs/error.log; 将 ‘#’ 删除
  3. 然后需要在server中增加参数
    1. set $httplog_to_kafka 1;
    2. set $lualib_path /opt/openresty/lualib;
  4. 以及将流量转发到 lua 中 if ( $httplog_to_kafka ) {
    1. #content_by_lua 'ngx.print("run kafka.lua.")';
    2. log_by_lua_file $lualib_path/kafka.lua;
    }
  5. 以上是简单版, 纯属解释以下, 上个完整版方便你自己的 nginx 对照 ```

    user nobody;

    worker_processes 1;

error_log logs/error.log;

error_log logs/error.log notice;

error_log logs/error.log info;

pid logs/nginx.pid;

events { worker_connections 1024; }

http { include mime.types; default_type application/octet-stream;

  1. #log_format main '$remote_addr - $remote_user [$time_local] "$request" '
  2. # '$status $body_bytes_sent "$http_referer" '
  3. # '"$http_user_agent" "$http_x_forwarded_for"';
  4. #access_log logs/access.log main;
  5. sendfile on;
  6. #tcp_nopush on;
  7. #keepalive_timeout 0;
  8. keepalive_timeout 65;
  9. #gzip on;
  10. server {
  11. listen 8003;
  12. #charset koi8-r;
  13. #access_log logs/host.access.log main;
  14. set $nginx_metrics_enable 0;
  15. set $httplog_to_kafka 1;
  16. set $lualib_path /opt/openresty/lualib;
  17. location / {
  18. if ( $httplog_to_kafka ) {
  19. log_by_lua_file $lualib_path/kafka.lua;
  20. }
  21. }
  22. #error_page 404 /404.html;
  23. # redirect server error pages to the static page /50x.html
  24. #
  25. error_page 500 502 503 504 /50x.html;
  26. location = /50x.html {
  27. root html;
  28. }
  29. # proxy the PHP scripts to Apache listening on 127.0.0.1:80
  30. #
  31. #location ~ \.php$ {
  32. # proxy_pass http://127.0.0.1;
  33. #}
  34. # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
  35. #
  36. #location ~ \.php$ {
  37. # root html;
  38. # fastcgi_pass 127.0.0.1:9000;
  39. # fastcgi_index index.php;
  40. # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
  41. # include fastcgi_params;
  42. #}
  43. # deny access to .htaccess files, if Apache's document root
  44. # concurs with nginx's one
  45. #
  46. #location ~ /\.ht {
  47. # deny all;
  48. #}
  49. }
  50. # another virtual host using mix of IP-, name-, and port-based configuration
  51. #
  52. #server {
  53. # listen 8000;
  54. # listen somename:8080;
  55. # server_name somename alias another.alias;
  56. # location / {
  57. # root html;
  58. # index index.html index.htm;
  59. # }
  60. #}
  61. # HTTPS server
  62. #
  63. #server {
  64. # listen 443 ssl;
  65. # server_name localhost;
  66. # ssl_certificate cert.pem;
  67. # ssl_certificate_key cert.key;
  68. # ssl_session_cache shared:SSL:1m;
  69. # ssl_session_timeout 5m;
  70. # ssl_ciphers HIGH:!aNULL:!MD5;
  71. # ssl_prefer_server_ciphers on;
  72. # location / {
  73. # root html;
  74. # index index.html index.htm;
  75. # }
  76. #}

}

  1. #### 原有 nginx 配置
  2. 关键的地方是

log_by_lua_file lua/kafka.lua;

  1. 运行的目录是 lua 中的 kafka.lua
  2. 导入的模块位置是 /usr/local/share/luajit-2.1.0-beta3/resty/

user nobody;

worker_processes 1;

error_log logs/error.log;

error_log logs/error.log notice;

error_log logs/error.log info;

pid logs/nginx.pid;

events { worker_connections 1024; }

http { include mime.types; default_type application/octet-stream;

  1. #log_format main '$remote_addr - $remote_user [$time_local] "$request" '
  2. # '$status $body_bytes_sent "$http_referer" '
  3. # '"$http_user_agent" "$http_x_forwarded_for"';
  4. #access_log logs/access.log main;
  5. sendfile on;
  6. #tcp_nopush on;
  7. #keepalive_timeout 0;
  8. keepalive_timeout 65;
  9. #gzip on;
  10. server {
  11. listen 80;
  12. server_name localhost;
  13. #charset koi8-r;
  14. #access_log logs/host.access.log main;
  15. location / {
  16. root html;
  17. index index.html index.htm;
  18. if ( $httplog_to_kafka ) {
  19. log_by_lua_file lua/kafka.lua;
  20. }
  21. }
  22. #error_page 404 /404.html;
  23. # redirect server error pages to the static page /50x.html
  24. #
  25. error_page 500 502 503 504 /50x.html;
  26. location = /50x.html {
  27. root html;
  28. }
  29. # proxy the PHP scripts to Apache listening on 127.0.0.1:80
  30. #
  31. #location ~ \.php$ {
  32. # proxy_pass http://127.0.0.1;
  33. #}
  34. # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
  35. #
  36. #location ~ \.php$ {
  37. # root html;
  38. # fastcgi_pass 127.0.0.1:9000;
  39. # fastcgi_index index.php;
  40. # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
  41. # include fastcgi_params;
  42. #}
  43. # deny access to .htaccess files, if Apache's document root
  44. # concurs with nginx's one
  45. #
  46. #location ~ /\.ht {
  47. # deny all;
  48. #}
  49. }
  50. # another virtual host using mix of IP-, name-, and port-based configuration
  51. #
  52. #server {
  53. # listen 8000;
  54. # listen somename:8080;
  55. # server_name somename alias another.alias;
  56. # location / {
  57. # root html;
  58. # index index.html index.htm;
  59. # }
  60. #}
  61. # HTTPS server
  62. #
  63. #server {
  64. # listen 443 ssl;
  65. # server_name localhost;
  66. # ssl_certificate cert.pem;
  67. # ssl_certificate_key cert.key;
  68. # ssl_session_cache shared:SSL:1m;
  69. # ssl_session_timeout 5m;
  70. # ssl_ciphers HIGH:!aNULL:!MD5;
  71. # ssl_prefer_server_ciphers on;
  72. # location / {
  73. # root html;
  74. # index index.html index.htm;
  75. # }
  76. #}

}

  1. ### 解释如何收集流量以及计算
  2. 这部分相对比较简单了, 就是解释一下流量是如何流入到计算出风险的, 首先流量是先经过 nginx 的, openresty 是一个扩展模块, 支持 lua 脚本, 这时候流量会经过我们设定好的 lua 脚本, lua脚本通过设定的分析, 归类为一个结构体, 当然这个结构体是为了适应 sniffer 所支持的格式. 具体可以看 kafka.lua 这个文件中的代码, 也可以看依赖的其他 lua 文件. kafka.lua 这个文件中, 最终把流量解析成一定的格式发送到了 kafka, 然后 sniffer 通过 docker-compose 配置的 kafka, sniffer 中的 kafka 驱动得到启动, kafka 获得这些流量, 将这些流量处理之后, 发送到了计算模块.
  3. ### sniffer 相关配置

version: “2”

services: nebula_sniffer: image : threathunterx/nebula_sniffer:latest container_name: nebula_sniffer_9003 network_mode: “host” volumes:

  • ./logs:/home/nebula_sniffer/logs environment:
  • DEBUG=True
  • REDIS_HOST=127.0.0.1
  • REDIS_PORT=36379
  • NEBULA_HOST=127.0.0.1
  • NEBULA_PORT=9003
  • SOURCES=kafka

    bro

  • DRIVER_INTERFACE=eth0
  • DRIVER_PORT=80,8080,9003
  • BRO_PORT=47000

    kafka

  • BOOTSTRAP_SERVERS=127.0.0.1:9092
  • TOPICS=nebula_nginx_lua
  • GROUP_ID=nebula ```

其实关键的地方在于

  1. BOOTSTRAP_SERVERS=kafka 的 IP 和端口
  2. SOURCES=kafka 那么 sniffer 是按 kafka 驱动来获得流量的

排查错误

排查错误, 主要的错误在于 nginx 与 openresty lua 的程序上, 所以需要在 nginx 上开启 error 日志记录, 上面的教程中有写, 非常的简单. 如果流量进来, 通过 lua 脚本运行有什么错误, 都会在 error.log 日志中体现, 如果没有错误, 那流量在 nginx 这端基本上没有什么问题.

如果在 snffer 还是没办法获取到流量, 那么还是要通过排查 kafka sniffer 方面的日志来解决.