容器并不等于安全边界。Docker 依靠 Linux 命名空间、控制组和内核安全机制实现隔离,但容器仍与宿主机共享内核。一旦配置了 --privileged、挂载 Docker Socket,或授予不必要的 Linux Capabilities,攻击者就可能扩大影响范围。因此,容器安全的核心不是“加更多工具”,而是贯彻最小权限原则 🔐。
一、先理解 Linux Capabilities
传统 Linux 权限模型中,root 用户拥有几乎全部特权。Capabilities 将这些特权拆分成多个独立能力,例如修改网络配置的 CAP_NET_ADMIN、绕过文件权限检查的 CAP_DAC_OVERRIDE、改变进程身份的 CAP_SETUID,以及加载内核模块的 CAP_SYS_MODULE。
Docker 默认会保留一组常用能力,同时移除部分高风险能力。这比直接赋予完整 root 权限更安全,但“默认集合”并不代表每个应用都需要。官方安全说明也强调,应结合命名空间、Capabilities 和内核加固机制共同审视运行时风险,详见 Docker Engine 安全文档 citeturn1search1。
实践原则:先删除全部 Capabilities,再根据应用的真实行为逐项添加,而不是保留默认权限后凭经验删减。
二、优先使用非 root 用户运行
镜像内的应用不应默认以 root 身份启动。可以在 Dockerfile 中创建专用用户,并通过 USER 指令切换身份。即使攻击者利用应用漏洞获得容器内 Shell,非 root 身份也能减少其修改系统文件、操作其他进程和滥用特权接口的机会。
运行时还可以通过 --user 10001:10001 指定固定 UID 和 GID。选择非系统保留范围内的数值,并确保挂载目录具有匹配权限。需要注意,容器内非 root 只是防线之一,不能替代 Capabilities、seccomp 和只读文件系统。
三、执行 Capabilities 白名单策略
对于普通 Web 服务,可先采用如下运行参数:
docker run --cap-drop=ALL --security-opt=no-new-privileges:true --read-only --tmpfs /tmp:rw,noexec,nosuid,size=64m my-web-app
--cap-drop=ALL 会移除全部能力。如果程序启动失败,应先查看日志和系统调用,再判断是否确实需要添加能力。例如,需要绑定低位端口的旧应用可能使用 --cap-add=NET_BIND_SERVICE。更推荐让应用监听 8080 等非特权端口,再由反向代理或端口映射对外提供 80、443 端口,从而避免增加能力。
不要为了快速解决权限报错而添加 CAP_SYS_ADMIN。该能力覆盖挂载、命名空间及多类系统管理操作,权限范围非常广。若应用声称必须使用它,应优先核查架构设计、文件权限和设备访问方式。
常见能力的审查建议
- NET_ADMIN:仅适用于确实需要调整路由、防火墙或网络接口的组件,普通业务服务通常不需要。
- SYS_PTRACE:调试或诊断工具可能使用,生产业务容器不应长期保留。
- SYS_TIME:允许修改系统时间,应用一般只需读取时间。
- CHOWN:如果镜像构建阶段已完成目录归属设置,运行阶段通常可以移除。
- SETUID、SETGID:仅在进程确实需要切换身份时保留,固定用户运行的服务应尝试删除。
四、叠加运行时防护措施
Capabilities 最小化并不是孤立配置。建议同时启用 no-new-privileges,阻止进程通过 setuid、setgid 文件等方式获得新的权限。对于不需要修改镜像文件的服务,使用 --read-only 将根文件系统设为只读,再通过 tmpfs 或受控数据卷提供必要的写入目录 📦。
不要将 /var/run/docker.sock 挂载到普通业务容器。Docker Socket 可以控制镜像、容器、挂载和宿主机资源,获得其访问权通常意味着能够进一步控制 Docker 主机。OWASP 的 Docker 安全清单同样建议限制 Capabilities、阻止权限提升、使用只读文件系统,并避免暴露 Docker Socket,参见 Docker Security Cheat Sheet citeturn1search4。
此外,应保留 Docker 默认 seccomp 配置,除非经过安全评估,不要直接使用 seccomp=unconfined。宿主机支持时,可结合 AppArmor 或 SELinux 限制文件、进程及设备访问。CPU、内存、进程数和文件描述符也应设置上限,降低失控进程造成拒绝服务的风险。
五、建立可验证的上线流程
- 在测试环境使用 --cap-drop=ALL 启动容器,记录真实报错。
- 根据系统调用、应用文档和业务功能判断缺失权限,不凭猜测添加能力。
- 每次只增加一个 Capability,并执行接口、文件、网络和重启测试。
- 检查容器是否以非 root 用户运行,是否存在特权模式、宿主机敏感目录或 Docker Socket 挂载。
- 将安全参数写入 Compose、部署模板或策略系统,避免依赖人工命令。
- 镜像升级后重新验证权限清单,删除不再使用的能力,并通过 CI/CD 阻止高风险配置进入生产环境。
排查当前容器配置时,可以使用 docker inspect 查看 CapAdd、CapDrop、Privileged、ReadonlyRootfs 和 SecurityOpt 等字段。进入容器后还可检查进程状态中的能力位,确认实际生效结果与部署声明一致。审计的重点不是“参数是否写了”,而是运行时是否真正受到限制 ✅。
总结
Docker 安全加固应从减少权限开始:使用非 root 用户,默认删除全部 Linux Capabilities,仅按业务需要逐项添加;同时启用 no-new-privileges、只读根文件系统、seccomp、资源限制和受控挂载。最小化配置可能需要更多测试,但它能显著缩小漏洞利用后的权限范围。把权限清单纳入版本管理和持续审计,才能让容器安全从一次性配置变成可维护的工程实践。