容器横向渗透防护安全加固配置:Docker容器横向渗透防护
容器横向渗透是云原生场景下最危险的安全威胁之一。
当攻击者突破一个容器,如果容器间默认全互通、以root权限运行、没有额外安全约束,他就能轻易扫描相邻容器、窃取数据,甚至逃逸到宿主机。
本文从零开始,手把手教你通过Docker原生配置实现容器横向渗透防护,操作过程中每步都有可验证结果。
环境准备:一台装了Docker的Linux主机
- 系统:Ubuntu 20.04+/CentOS 7+ 均可,已安装Docker(版本≥19.03即可,支持用户命名空间等特性)
- 权限:能执行
sudo命令 - 后续所有命令均在终端执行,无需安装额外工具
第一步:打破“容器默认全互通”的信任
Docker默认使用 bridge 网络,所有容器在同一个网段内可以互相访问。
这不是你想要的。
操作1:重启Docker时加参数禁用默认容器间通信
编辑Docker daemon配置文件 /etc/docker/daemon.json,如果文件不存在则新建:
{
"icc": false
}
icc 是 inter-container communication 的缩写,设为 false 后,通过默认bridge网络启动的容器将无法互相ping通。
保存后重启Docker:
sudo systemctl restart docker
验证效果:启动两个简单容器测试:
docker run -d --name test1 alpine sleep 1000
docker run -d --name test2 alpine sleep 1000
docker exec test2 ping test1
预期输出类似 ping: bad address 'test1' 或 ping: connect: Network is unreachable。
操作2:使用用户自定义网络(推荐)
如果业务需要容器间通信(比如同一个应用的不同服务),不要用默认bridge。创建自定义网络并显式指定哪些容器加入:
docker network create myapp-net
docker run -d --name web --network myapp-net nginx:alpine
docker run -d --name api --network myapp-net node:14-alpine
只有加入 myapp-net 的容器才能互相访问。
不同网络间的容器完全隔离。
第二步:限制容器内权限——让攻击者“施展不开”
即使网络隔离了,如果容器内部拥有过多能力(Capabilities),攻击者依然可能逃逸。
操作3:丢弃所有非必需Capability
运行容器时使用 --cap-drop=ALL,再根据需要添加特定能力:
docker run -d --cap-drop=ALL --cap-add=NET_BIND_SERVICE nginx:alpine
这样容器除了绑定端口外,没有任何系统级权限(如加载内核模块、修改系统时间等),横向渗透常用的ARP欺骗、嗅探等操作直接失效。
操作4:设置只读文件系统
攻击者进入容器后无法写入文件(包括下载后门二进制):
docker run -d --read-only --tmpfs /tmp nginx:alpine
--tmpfs /tmp 是为临时文件单独挂载一个可写目录(比如Nginx写PID文件),主体文件系统只读。
第三步:启用用户命名空间——让root从内部“缩水”
默认情况下容器内root映射到宿主机root,风险极大。
开启用户命名空间后,容器内root在宿主机上会映射为一个普通用户(如 uid 165536)。
操作5:配置用户命名空间
编辑 /etc/docker/daemon.json,在之前的内容上追加:
{
"icc": false,
"userns-remap": "default"
}
userns-remap: default 会创建一个名为 dockremap 的用户和组,重启Docker后所有容器都会在新命名空间下运行。
重启Docker并验证:
sudo systemctl restart docker
docker run -d --name test nginx:alpine
ps aux | grep nginx
你会发现容器进程的用户不再是root,而是 165536 开头的ID。
此时攻击者即使拿到容器内root权限,也无法对宿主机做任何敏感操作。
注意:开启用户命名空间后,宿主机与容器之间的文件卷挂载(volume)需要手动调整权限,否则容器可能无法写入挂载目录。
解决办法是在宿主机上把目录所有者改为 dockremap。
第四步:用Seccomp策略限制系统调用
Seccomp可以过滤容器内的系统调用,许多横向渗透攻击(如利用 ptrace 调试进程)都需要特定syscall。
操作6:应用Docker默认的Seccomp策略
Docker自带了一份白名单策略,只需在启动容器时指定:
docker run -d --security-opt seccomp=default.json nginx:alpine
如果你需要更严格的控制,可以参考 Docker官方seccomp profile 自定义。
一般情况下默认策略已足够,它禁用了 mount、unshare、pivot_root 等危险系统调用。
避坑指南:新手最常犯的错误
- 忘记重启Docker:修改
/etc/docker/daemon.json后必须执行sudo systemctl restart docker才会生效。 - 用户命名空间与主机卷的冲突:挂载宿主机目录时,容器内的uid不再是0(root),而是映射后的uid(默认1434)。建议使用
docker run --user 1000:1000显式指定容器内UID与宿主机对齐,或直接修改目录权限。 - 只配了网络隔离没配权限:网络隔离只防容器间通信,如果攻击者通过其他方式(如暴露端口)进入,仍然可能横向移动。必须结合Capability限制和只读文件系统。
- Seccomp影响性能?:在正常业务负载下,默认Seccomp策略对I/O密集应用有微乎其微的影响(<1%),可以忽略。
效果验证:确认加固是否有效
- 网络隔离验证:按第一步的方法,尝试从一个容器 ping 另一个不属于同一自定义网络的容器,应失败。
- Capability验证:在加固后的容器内执行
capsh --print看剩余能力列表,应该只看到NET_BIND_SERVICE等少数。 - 用户映射验证:运行
cat /proc/1/uid_map查看UID映射范围,如果第一行是0 165536 65536说明用户命名空间已开启。 - Seccomp验证:尝试在容器内执行
mount命令,应提示Operation not permitted。
完成以上四步后,你的容器环境已经从默认的“宽松模式”切换到了安全模式。
即使某个容器被攻破,攻击者也无法轻易扫描其他容器或逃逸到宿主机。
建议每次部署新容器时,都对照这份清单检查一遍,养成习惯。
如果你在加固过程中遇到任何报错,请优先检查Docker daemon日志:sudo journalctl -u docker -n 50,大部分配置问题都能在这里找到线索。