LabHub
学习 学习路径 课程

容器安全

打开容器的四扇门

在 LabHub 中继续学习

一句话总结

容器逃逸通常并非源于内核漏洞,而是来自我们亲手开放的配置。了解四种模式,就能在审查中用 30 秒发现问题。

本课用于防御。每一项都会配对讲解“为什么危险” 和“如何阻止”。

概念图: 我们亲手开放的配置 · 防御 · 主机 root · 等同于授予主机 root 权限。

为什么需要它

仅确认容器使用非 root 用户,并不能证明主机边界安全。如果开放 Docker 套接字、主机文件系统、PID 命名空间或过多 capability,容器内的低权限进程也能绕过边界并取得主机权限。因此,除了镜像用户,还必须同时审查运行时连接的资源和内核权限。

门 1 — 挂载 Docker 套接字

volumes:
  - /var/run/docker.sock:/var/run/docker.sock

这行常见于 CI 运行器或监控代理。该套接字是 Docker 守护进程的 API,而守护进程以主机 root 身份运行。只要能访问套接字,就能新建一个挂载整个主机根目录的特权容器。也就是说,这一行实际上等同于授予主机 root 权限。

阻止方法——不要把套接字交给容器。如果需要构建容器,使用不依赖守护进程的构建器(kaniko、buildah);如果只为查询信息,则在前面放置只读代理,以白名单限制允许访问的端点。LabHub 使用 kaniko 构建镜像,原因就在这里。

门 2 — --privileged

--privileged 会授予全部 capability、开放设备访问,并实质上禁用 seccomp/AppArmor。在这种状态下,可以把主机磁盘作为 /dev/sda 打开并挂载。

阻止方法——只逐项授予必需的 capability。例如,如果目的只是绑定低位端口,仅需 NET_BIND_SERVICE。在 Kubernetes 中,则应通过 Pod Security Admission 的 baseline 或更严格级别直接拒绝特权 Pod。

门 3 — 挂载主机路径

volumes:
  - /:/host          # 최악
  - /etc:/etc-host   # 나쁨
  - /var/log:/logs   # 상황에 따라

根目录 / 的危险无需多言;即使只有 /etc,也能接触 shadowsudoers 和 cron 文件。如果可写,就会直接导致主机失陷。

阻止方法——把挂载路径缩小到最小范围,并加上 :ro。用命名卷代替主机路径;在 Kubernetes 中,使用策略引擎完全禁止 hostPath 更为可靠。

门 4 — 共享命名空间

--pid=host 会暴露主机上的所有进程,--net=host 则直接使用主机网络栈。前者通过 /proc/<pid>/root 打开访问其他进程文件系统的路径,后者则可访问只在 localhost 上开放的管理端口。

阻止方法——保持默认隔离。即使监控等场景确有必要,也应限制为只读并只保留最少 capability。

一览

配置 实际含义 替代方案
挂载 docker.sock 主机 root kaniko/buildah、只读代理
--privileged 全部 capability + 设备 仅授予所需 cap、PSA baseline
-v /:/host 主机文件系统 缩小范围 + :ro、命名卷
--pid=host 访问其他进程 保持默认隔离

以及多层防御

即使配置正确,运行时漏洞仍然存在,因此要叠加多层防线。

  1. UID——USER 10001。不以 root 运行,就能封堵大多数路径。
  2. capability——全部 drop,只 add 必需项。
  3. NO_NEW_PRIVS——切断通过 setuid 提升权限的途径。
  4. 只读根目录——--read-only,只在必要位置使用 tmpfs。
  5. seccomp——在内核入口阻止危险系统调用。

LabHub 的实验 Pod 同时采用这五层防护。因此,无论在实验内部以 root 身份做什么,都无法触及主机。

实际现场中的情况

下一项检查要关注什么

接下来的测验将区分 Docker 套接字、主机挂载和 PID 共享分别打开了哪些路径,以及最小 capability、NoNewPrivs、seccomp 各自起什么作用。请以前一实验确认的内核权限值为依据,排除“单一防御措施已经足够”的错误答案。