博客
防御容器逃逸:多租户托管 Docker 隔离实用指南
了解如何通过具体的步骤和示例,在多租户环境中保护 Docker 容器免受逃逸漏洞和隔离故障的侵害。

摘要
Docker 容器共享主机内核,因此隔离至关重要——尤其是在多租户托管环境中,一次容器逃逸就可能危及所有租户。许多开发者认为容器就像完全隔离的虚拟机,但现实并非如此。本文将解释 Docker 隔离背后的 Linux 内核特性(命名空间、cgroups)以及威胁它们的攻击向量。您将学到加固 Docker 设置的实用步骤:限制权限、使用安全运行时、扫描镜像以及实施网络分段。通过一个真实的多租户 WordPress 托管提供商的示例,您将看到如何应用这些防御措施。我们还将涵盖性能权衡以及 seccomp/AppArmor 的使用等注意事项。目标是为您提供一个强大的隔离策略,以防止容器逃逸并确保租户安全。
引言
如果您运营一个多租户托管平台——无论是共享 WordPress 托管、SaaS 应用程序还是开发环境服务——容器逃逸都是最可怕的场景。内核中的漏洞或配置错误可能导致一个租户突破其容器的限制,访问其他租户的数据或主机本身。Docker 的隔离依赖于 Linux 内核特性,如命名空间和 cgroups,但开箱即用的配置通常不足以提供强大的安全性。本文将引导您了解攻击向量,并提供锁定 Docker 容器的可行步骤,并通过一个真实的多租户 WordPress 示例进行说明。有关生产环境编排的更广泛介绍,请参阅我们关于编排生产就绪的容器化应用程序的指南。
理解 Docker 隔离
Docker 容器使用 Linux 命名空间提供进程级隔离:PID 命名空间隔离进程树,网络命名空间分离网络接口,挂载命名空间隔离文件系统挂载,用户命名空间允许将容器 root 映射到非特权主机用户。控制组(cgroups)限制 CPU、内存和磁盘 I/O 等资源使用。这些特性共同在每个容器周围创建了一个“沙箱”。然而,与运行独立内核的虚拟机不同,容器共享主机内核。这意味着内核中的漏洞(例如 CVE-2022-0492)可能被利用来突破容器的命名空间隔离。此外,诸如在容器内以 root 用户运行容器、授予容器所有能力或不丢弃不必要的 Linux 能力等配置错误会扩大攻击面。
攻击向量
常见的攻击向量包括:
- 内核漏洞利用:利用主机内核中的错误来获得主机访问权限。
- 特权容器:使用
--privileged运行会授予所有能力并绕过大多数隔离。 - 能力滥用:即使没有完全的特权模式,拥有危险能力的容器(如
CAP_SYS_ADMIN或CAP_NET_ADMIN)也可以挂载文件系统或操纵网络设置。 - 不安全的镜像实践:使用带有已知漏洞的基础镜像或包含不必要的工具(如编译器或 shell 解释器)。
- 共享挂载命名空间:将主机目录挂载到容器中,如果不是只读,可能会导致逃逸。
实用安全步骤
1. 以非 root 用户运行容器
默认情况下,Docker 在容器内以 root 用户运行。如果攻击者在容器内获得 root 权限,他们将拥有更多优势。在 Dockerfile 中创建一个用户并使用 USER 指令。另外,如果可能,避免在 Docker Compose 中使用 --user 标志映射到任意主机用户。
2. 丢弃所有能力并仅添加必需的
Linux 能力将超级用户权限分解为更小的单元。在 Docker Compose 中,使用 cap_drop: ALL 然后 cap_add 添加必需的能力(例如 NET_BIND_SERVICE)。避免使用 SYS_ADMIN、NET_ADMIN、SYS_PTRACE 等危险能力。
3. 使用只读根文件系统
在容器定义中设置 read_only: true。这可以防止攻击者写入容器的文件系统。如果您的应用程序需要写入临时文件,请在该位置挂载一个 tmpfs 卷。
4. 启用用户命名空间重映射
用户命名空间重映射将容器的 root 用户映射到一个非特权的主机用户。这增加了一层隔离,因为即使容器 root 用户逃逸,他们也只会拥有重映射用户的权限。在 /etc/docker/daemon.json 中启用它,设置 "userns-remap": "default"。请注意,这可能会使卷权限变得复杂。有关更多详细信息,请参阅掌握 Docker 隔离以实现安全高效的 Web 托管。
5. 应用 Seccomp 和 AppArmor/AppArmor 配置文件
Seccomp 限制容器可以进行的系统调用。Docker 提供了一个默认的 seccomp 配置文件,可以阻止危险的系统调用。您也可以创建自定义配置文件。类似地,AppArmor(或 SELinux)提供强制访问控制。使用 AppArmor 将您的容器限制在允许的最小操作集内。可以通过 Docker Compose 中的 security_opt 设置安全配置文件。
6. 使用最小化的基础镜像并扫描漏洞
选择像 Alpine 或 Distroless 这样攻击面更小的镜像。定期使用 Docker Scout、Trivy 或 Clair 等工具扫描镜像。将扫描集成到您的 CI/CD 管道中,以防止部署易受攻击的镜像。
7. 使用自定义桥接网络进行网络分段
为每个租户或应用程序层创建单独的桥接网络。这可以限制东西向流量。在 Docker Compose 中,定义网络并隔离服务。如果服务不需要出站互联网访问,请使用 internal: true。主机上的防火墙规则可以进一步限制容器间的流量。
8. 使用 Cgroups 限制资源
在 Docker Compose 中使用 deploy.resources.limits 设置 CPU 和内存限制。这可以防止受损的容器发起资源耗尽攻击。此外,设置 kernel_memory 和 memory_reservation 以进行更精细控制。
真实示例:使用 Docker Compose 进行多租户 WordPress 托管
考虑一个场景,您为不同的客户托管多个 WordPress 站点,每个站点都在自己的 Docker 容器中。不安全的设置可能如下所示:
version: '3'
services:
wordpress:
image: wordpress:latest
ports:
- "8080:80"
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: exampleuser
WORDPRESS_DB_PASSWORD: examplepass
WORDPRESS_DB_NAME: exampledb
volumes:
- ./wp-content:/var/www/html/wp-content
db:
image: mysql:5.7
environment:
MYSQL_DATABASE: exampledb
MYSQL_USER: exampleuser
MYSQL_PASSWORD: examplepass
MYSQL_ROOT_PASSWORD: somewordpress
volumes:
- db_data:/var/lib/mysql
volumes:
db_data:
此设置存在漏洞:WordPress 容器在内部以 root 用户运行,拥有所有能力(因为没有丢弃任何能力),挂载了具有写入访问权限的主机目录,并且拥有不受限制的网络访问权限。
现在我们来加固它:
version: '3'
services:
wordpress:
image: wordpress:latest
user: www-data
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE
read_only: true
tmpfs:
- /var/www/html/wp-content/plugins
security_opt:
- seccomp=seccomp-profile.json
- apparmor=wordpress-profile
networks:
- frontend
ports:
- "8080:80"
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: exampleuser
WORDPRESS_DB_PASSWORD: examplepass
WORDPRESS_DB_NAME: exampledb
volumes:
- wp-uploads:/var/www/html/wp-content/uploads
deploy:
resources:
limits:
cpus: '0.5'
memory: 256M
db:
image: mysql:5.7
user: mysql
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE
networks:
- backend
environment:
MYSQL_DATABASE: exampledb
MYSQL_USER: exampleuser
MYSQL_PASSWORD: examplepass
MYSQL_ROOT_PASSWORD: somewordpress
volumes:
- db_data:/var/lib/mysql
deploy:
resources:
limits:
cpus: '0.25'
memory: 128M
networks:
frontend:
driver: bridge
internal: false
backend:
driver: bridge
internal: true
volumes:
wp-uploads:
db_data:
主要改进包括:
- 两个容器都以非 root 用户运行(
www-data和mysql)。 - 丢弃了所有能力,仅添加了
NET_BIND_SERVICE。 - WordPress 文件系统是只读的,除了一个 tmpfs 挂载和一个上传卷。
- 应用了 Seccomp 和 AppArmor 配置文件(您需要提供自定义配置文件)。
- 独立的网络将 Web 与数据库隔离开,数据库网络是内部的。
- 资源限制可防止资源耗尽。
有关 WordPress 特定 Docker 加固的更多信息,请参阅Docker for WordPress:隔离容器为何改变一切。
注意事项
- 用户命名空间重映射:虽然功能强大,但它会破坏卷挂载,因为重映射的主机 UID 与容器 UID 不同。您可能需要预先创建具有正确权限的目录或使用支持重映射的 Docker 卷。
- Seccomp/AppArmor 配置文件:自定义配置文件需要了解应用程序的系统调用和文件访问模式。过于严格的配置文件可能会导致功能中断。请彻底测试。
- 性能:额外的安全层,如 seccomp 和 AppArmor,开销很小,但资源限制和只读文件系统可能会影响写密集型应用程序。
- 编排复杂性:在多租户环境中,管理每个租户的 Docker Compose 文件可能会变得繁琐。可以考虑使用更高级别的编排工具,如 Kubernetes,但这会带来其自身的安全考虑。
结论
容器逃逸是多租户 Docker 托管中的一个真实威胁,但它是可以预防的。通过理解隔离机制并应用纵深防御——丢弃能力、以非 root 用户运行、启用用户命名空间、seccomp、AppArmor、网络分段和定期镜像扫描——您可以大大降低风险。请记住,Docker 的默认设置对于多租户工作负载来说并非生产就绪。立即实施这些步骤,以保护您的租户和您的基础设施。有关 Docker 安全最佳实践的全面概述,请参阅使用 Docker 保护您的 Web 应用程序:隔离和最佳实践实用指南。
Sources (5)
- Docker and Container Isolation - Medium
- What is container isolation? Mechanisms, limitations, and secure runtimes | Blog - Northflank
- Container Isolation Explained for Kubernetes and Beyond - Edera
- Docker Security: 5 Risks and 12 Best Practices for Securing Your Containers - Tigera.io
- 9 Security Best Practices for Docker Containers - Kinsta®

