上一篇打通了私有网络,随后遇到一个现象:Docker 发布的 Redis 端口,即使没有在 UFW 中放行,也可以访问。
原因在于数据包经过的路径:宿主机服务通常走 INPUT,Docker bridge 的发布端口经 DNAT 后走 FORWARD。只配置 UFW 入站规则,并不足以限制后一类流量。
本篇梳理判断规则所需的原理,下一篇给出实际防护脚本。
本文限定 Linux 上使用 iptables 后端的 Docker bridge 网络:
iptables --version 中出现 nf_tables,可能只是 iptables 使用 nft 兼容层,不等于 Docker 已切换原生 nftables 后端。DOCKER-USER 方案。本场景主要查看两张表:
filter:过滤报文,内置链包括 INPUT、FORWARD、OUTPUT。nat:地址转换,内置链包括 PREROUTING、INPUT、OUTPUT、POSTROUTING。其他常见表:mangle 用于修改报文属性,raw 可用于连接跟踪豁免等处理;本方案不需要修改它们。
常见路径位置:
PREROUTING:入站路由判断之前。INPUT:交给宿主机本地进程。FORWARD:由宿主机转发到其他目标。OUTPUT:宿主机本地产生的报文。POSTROUTING:完成路由判断、离开主机之前。同名自定义链可出现在不同表中。例如 nat/DOCKER 处理端口转换,filter/DOCKER 参与访问放行;查看时要指定表。
规则在链内按顺序检查,匹配后的行为取决于目标动作:
ACCEPT:在当前过滤处理处接受报文;后续其他处理环节仍可能影响它。DROP:丢弃,不返回明确拒绝响应。REJECT:拒绝并返回相应错误。RETURN:退出当前自定义链,回到调用链继续处理。因此,DOCKER-USER 中的 RETURN 只是结束本链检查,之后仍要通过 Docker 的其他规则。
常用命令参数:
bash复制代码
# -S 输出规则语法,便于确认条件和跳转顺序。
sudo iptables -S FORWARD
sudo iptables -S DOCKER-USER
# -n 不解析地址,-v 显示计数,--line-numbers 显示规则序号。
sudo iptables -L DOCKER-USER -n -v --line-numbers-A:追加到链尾。-I 链名 1:插入链首。-C:检查相同规则是否存在。-D:删除匹配规则或指定序号的规则。-w:等待 xtables 锁释放,不是等待某条链创建。以下是理解本场景的简化路径,实际还可能涉及其他表、连接跟踪和 Docker 版本差异。
text复制代码
网卡 → PREROUTING → 路由判断 → INPUT → 宿主机进程allow in 规则用于此类本机入站访问。以 40002:80 为例:
text复制代码
网卡 → nat/PREROUTING → nat/DOCKER
→ DNAT:宿主机:40002 改为 容器IP:80
→ 路由判断 → filter/FORWARD → DOCKER-USER
→ Docker 后续转发规则 → 容器FORWARD,不会按宿主机服务的路径进入 INPUT。ufw deny 40002 不能可靠封住发布端口。DOCKER-USER 是 Docker 为用户预留的转发过滤入口,位于其常规容器放行规则之前;它不处理全部宿主机流量。text复制代码
容器 → 网桥 → FORWARD → POSTROUTING/MASQUERADE → 外网
回包 → 连接跟踪还原地址 → FORWARD → 容器MASQUERADE 是一种源地址转换,将出站源地址改为出口地址。ESTABLISHED,RELATED 用于匹配已有连接和相关流量。若将物理网卡入站转发一律丢弃而不保留回包,可能导致容器无法正常访问外部服务。映射 40002:80 后,进入 DOCKER-USER 的报文目标端口已经是 80。此时直接匹配 --dport 40002 通常不会命中。
使用 conntrack 查询该连接原始方向的目标端口:
bash复制代码
# 只查看具有该条件的规则是否存在,不添加规则。
sudo iptables -C DOCKER-USER -i enp1s0 -p tcp \
-m conntrack --ctdir ORIGINAL --ctorigdstport 40002 -j RETURN--ctdir ORIGINAL:匹配连接的原始请求方向。--ctorigdstport 40002:匹配本机连接跟踪记录中的原始目标端口。WireGuard 流量分为两层:
51820/UDP。wg0 进入,源地址例如 10.10.0.3。内层报文按目标继续分流:
INPUT,由本机入站规则控制。FORWARD,需要 IP 转发和转发规则。因此,开放 UDP 51820 并不等于开放隧道内全部服务;而某个 Docker 端口无需 UFW 入站放行就能访问,也不能证明其他宿主机服务具有相同行为。
bash复制代码
# 发布地址和端口映射。
docker ps --format 'table {{.Names}}\t{{.Ports}}'
# 发布端口的 DNAT 规则。
sudo iptables -t nat -S DOCKER
# 转发链入口、自定义规则和命中计数。
sudo iptables -S FORWARD
sudo iptables -L DOCKER-USER -n -v --line-numbers
# 转发开关与 UFW 当前配置。
sysctl net.ipv4.ip_forward
sudo ufw status verboseDOCKER-USER 添加本场景所需限制。"iptables": false;这会破坏 Docker 自动维护的 NAT 和过滤机制。127.0.0.1;需要访问的端口,再结合绑定地址、防火墙和认证配置。127.0.0.1 属于当前网络命名空间,容器里的回环地址指向容器自己;不能简单归因于某条“禁止容器访问宿主机回环”的规则。::: 发布的 IPv6 入口。理解这些路径后,防护分工就明确了:宿主机服务检查 UFW 入站规则,Docker 发布端口检查转发规则,公网入口再结合云安全组或家庭路由器控制。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。