为什么 ufw 挡不住容器端口
用 Docker 发布端口时,容器运行时会自己往 nat 表写转发规则:外部流量在进入主机后被直接改写到容器地址,随后走转发链交给容器,根本不经过 ufw 管理的入站规则链。结果就是很典型的现场:ufw status 显示只放行了少数端口,实际却能从公网连上容器里的服务。判断这类问题不能只看防火墙状态,要看转发链。
基本信息
| 加固项 | 容器发布端口的真实暴露面 |
|---|---|
| 适用平台 | Linux(Docker 与 ufw 并存的环境) |
| 风险等级 | 高 |
| 关键链 | nat 表的转发规则与 DOCKER-USER 链 |
| 基线 | 容器端口不默认对全网开放 |
典型使用场景
- 暴露面核查:确认容器端口是否绕过了主机防火墙
- 事故复盘:安全组与 ufw 都只放行了管理端口,服务却仍可从公网访问
- 上线前检查:新容器发布端口前先确定访问范围
- 多环境一致性:开发机随意发布端口,生产环境需要统一收口方式
- 合规整改:容器平台同样需要能说明每个对外端口的来源限制
验证是否被绕过
验证是否被绕过
sudo iptables -t nat -L DOCKER -n --line-numbers | head # 看容器端口转发规则
sudo iptables -L DOCKER-USER -n --line-numbers # 看自定义收口规则
ss -tulnp | grep docker # 本机监听情况
sudo iptables -L FORWARD -n | head -20 # 转发链是实际通道在转发链上做白名单
在转发链上做白名单
# 只允许内网网段访问容器的 8080,其余来源丢弃
sudo iptables -I DOCKER-USER -p tcp --dport 8080 ! -s 10.0.0.0/8 -j DROP
sudo iptables -I DOCKER-USER -j RETURN # 其余流量交回默认流程
sudo iptables -L DOCKER-USER -n --line-numbers # 复核规则顺序三种收口方式
| 方式 | 做法 | 适用与代价 |
|---|---|---|
| 绑定回环地址 | 发布端口时绑定 127.0.0.1,由本机反向代理对外 | 最彻底,服务不出本机;需要反向代理配置配合 |
| 转发链白名单 | 在转发链上按来源与端口放行 | 适合必须直接暴露的场景;规则随容器变化需维护 |
| 统一入口收敛 | 所有对外服务经反向代理或负载均衡发布 | 架构上最清晰,改造成本相对高 |
容器运行时重启会重建相关链,自定义规则虽可保留,但仍要在重启后复验一次;另外只信防火墙状态输出会误判,暴露面必须以另一台机器实际连接测试为准,配置只能用来解释原因。
发布端口时显式绑定内网或回环地址是成本最低的预防手段:一旦绑定在回环上,即使防火墙策略后续被改错,服务也不会直接暴露。排查既有环境时,先列出全部已发布端口及其绑定地址,再决定逐个收口还是一并调整。
排查与整改顺序
先确认现状:列出容器列表、已发布端口与绑定地址,再看转发链与自定义链的规则。第二步是选择收口方式,能绑回环就绑回环,必须对外则在转发链做来源白名单。第三步是验证:从外部主机实测端口连通性,并确认重启容器运行时后规则仍然生效。三步的输出一起留档,作为暴露面整改的证据。