ngx_stream_access_module基于 IP 的流式访问控制实践指南
1. 前言
自 Nginx 1.9.2 起,官方在 Stream 子系统(四层 TCP/UDP 代理)中引入了 ngx_stream_access_module,用最简洁的 allow/deny
语义完成对客户端源地址的黑白名单控制。相比 HTTP 阶段常用的 ngx_http_access_module
,它更专注于 L4 连接层,能保护 MySQL、Redis、MQTT、Syslog 等非-HTTP 后端。([nginx.org][1])
2. 典型应用场景
场景 | 目标 | 亮点 |
---|---|---|
数据库内网暴露 | 仅允许运维网段接入 MySQL 3306 | 在 Nginx 上统一做四层防火墙,免后端逐台配置 |
UDP 日志网关 | 仅允许特定 IDC 的收集器访问 | 流量进入业务 VPC 前先做 ACL |
物联网 MQTT Broker | 针对海外节点放行 IPv6 前缀 | 与 HTTP ACL 混用,统一策略中心 |
3. 指令速查
指令 | 语法 | 作用域 | 说明 | ||||
---|---|---|---|---|---|---|---|
allow | `allow <address | CIDR | unix: | all>;` | stream ,server | 放行匹配地址/网段;unix: 代表全部本地 UNIX-Domain Socket | |
deny | `deny <address | CIDR | unix: | all>;` | 同上 | 拒绝匹配地址/网段;亦支持 all 全拒绝 | ([nginx.org][1]) |
匹配顺序:按配置文件从上到下第一次命中即终止判定;未命中走默认策略。
4. 工作原理深入
- 阶段:发生在
preread
阶段(握手之后、业务代理之前),因此可在真正连接后端前就丢弃非法连接。 - 数据结构:解析指令后所有条目以前缀树保存,查找复杂度
O(log N)
。 - IPv6 支持:与 IPv4 同级,允许在同一
server
块混用;支持/0–/128
任意前缀。 - UNIX-Domain Socket:当 Nginx 作为本机进程间代理(
listen unix:/tmp/mysock
)时,可利用unix:
进行专门 ACL。
5. 基础配置与逐条解析
stream {# ① TCP 负载均衡到后端 MySQLupstream mysql_backend {server 10.0.0.10:3306 max_fails=3 fail_timeout=30s;server 10.0.0.11:3306;}server {listen 3306 reuseport;# ② 先阻止内网误写死地址deny 192.168.1.1;# ③ 放行两段内网 & 指定 IPv6allow 192.168.1.0/24;allow 10.1.1.0/16;allow 2001:db8::/32;# ④ 其余全部拒绝deny all;proxy_pass mysql_backend;# ⑤ 观察日志access_log /var/log/nginx/mysql_stream.log;}
}
- 先拒绝再放行? 实际上 顺序优先:如果把
deny all
写在最上面,会导致全部连接被立即拒绝。 - IPv6 注意掩码:
::/0
相当于全部 IPv6,需要配合精细的/32+
前缀分段放行。
6. 与 ngx_http_access_module
的差异
特性 | stream(access) | http(access) |
---|---|---|
工作层次 | L4 (TCP/UDP) | L7 (HTTP) |
可用指令 | allow / deny | allow / deny |
常见变量 | $remote_addr (仅日志) | $remote_addr 、$binary_remote_addr |
强制返回码 | 关闭 TCP 连接 | 返回 403 / 444 |
场景 | DB/MQ/自定义协议 | 网站、API 网关 |
若需要在同一台 Nginx 对 HTTP 和 MySQL 均做 ACL,需分别在
http {}
与stream {}
各写一份规则,互不影响。
7. 动态模块与编译选项
默认编译时自动启用;如需裁剪体积,可 --without-stream_access_module
;若使用 动态模块:
./configure --with-stream --with-stream=dynamic
make && make install
# 配置文件中
load_module modules/ngx_stream_access_module.so;
这样可在运行时按需加载。([nginx.org][2])
8. 调试与排错
- 快速验证:
nginx -t
只检查语法,不做 ACL 测试;可用nc -vz
模拟不同 IP(借助--source
选项)连通性。 - access_log:在
stream
块显式声明日志路径,观察连接被403
(“Forbidden”) 还是被硬断 (client closed connection
)。 - 连接追踪:结合
tcpdump
或ss -tn state TIME-WAIT
确认连接生命周期是否如预期。
9. 性能与最佳实践
- 条目顺序:把最常命中的网段写在最前面,减少匹配次数。
- 不可替代防火墙:
iptables/nftables
在 内核栈 前就丢弃包,仍是第一道防线;Nginx ACL 更灵活,用于细粒度应用层转发。 - 集中管理:可搭配
include /etc/nginx/acl/*.conf;
把公共网段分文件维护,或借助 动态重载 工具(Ansible、SaltStack)。
10. 结语
ngx_stream_access_module
用极低成本在 Nginx 层增加了一道 面向传输层协议的访问控制网关。对于需要同时代理多种协议、并希望统一安全策略的场景,它是既轻量又高效的解决方案。熟练掌握 allow/deny
回溯顺序、CIDR 写法以及日志诊断技巧,就能在生产环境中快速隔离非法流量并保障关键服务安全。