Skip to main content

容器的安全边界

容器与虚拟机有本质区别。容器共享宿主机内核,隔离靠 namespace 和 cgroups 实现。虚拟机有独立内核,隔离靠硬件虚拟化。 这意味着容器逃逸的后果更严重。一个内核漏洞可能让攻击者从容器直接拿到宿主机权限。
容器不是安全沙箱。默认配置下的容器隔离强度远低于虚拟机。多租户环境和运行不可信代码时,必须主动加固。

以非 root 运行

容器里的进程默认以 root 身份运行。容器内 root 在宿主机上同样是高权限用户。这是最常见的风险来源。
更好的做法是在 Dockerfile 里固化。这样任何方式启动都安全。
优先使用官方镜像的 non-root 变体,例如 nginxinc/nginx-unprivileged。它们默认就不用 root 运行。

能力裁剪

Linux 把 root 权限拆成几十个 capability。容器默认持有其中一批,比如修改网络配置的 NET_ADMIN 风险很高。 原则是全部丢弃,再按需加回。
Compose 中的写法:
NET_BIND_SERVICE 允许进程绑定 1024 以下的特权端口。普通 Web 服务通常只需要这一个。

只读根文件系统

攻击者进入容器后的第一件事往往是写入恶意程序。只读根文件系统可以拦住这一步。
应用确实需要写数据的目录,单独挂载 volume。这样攻击面只剩挂载点。
1

确认应用的写入路径

先正常跑容器,用 docker diff 找出它写入了哪些目录。
2

为这些路径准备挂载

数据目录挂 volume,临时目录挂 tmpfs。
3

加上 --read-only 重启验证

应用报错说明还有遗漏的写路径,补齐挂载再试。

镜像安全

镜像是供应链攻击的入口。三条基本规则:
  1. 固定版本,不用 latestlatest 随时可能变,也无法审计。
  2. 用官方镜像或可信来源的镜像。
  3. 上线前扫描漏洞。
trivy image 加进 CI 流水线。发现严重漏洞时让构建失败,漏洞就进不了生产。

守护进程安全

Docker 守护进程以 root 运行。能访问 docker.sock 就等于拿到了宿主机的 root。
不要把 docker.sock 挂载进任何不完全信任的容器。不要在没有 TLS 的情况下开放 Docker 远程 API 的 2375 端口。开放远程 API 必须配置 TLS 双向认证,使用 2376 端口。

敏感信息管理

密码和密钥不要写进 ENV,也不要写进 Dockerfile。它们会留在镜像层里,任何人拿到镜像都能提取。
正确做法是使用 secrets 管理。Docker Swarm 提供 secrets 机制,Kubernetes 有 Secret 资源。单机环境可以把密钥放进权限收紧的文件,再用 bind mount 挂进容器。

安全清单

上线前逐项检查:

延伸阅读