核心原则是不让容器进程以意外uid创建或修改宿主机文件,须从用户身份、挂载方式和运行边界三方面协同控制:对齐uid/gid、显式指定--user、优先只读挂载、改用命名卷、启用userns-remap并自动化拦截风险。

核心原则是:不让容器进程以意外 UID 创建或修改宿主机文件。这不是“调权限”就能糊弄过去的问题,而是必须从用户身份、挂载方式和运行边界三方面同时控制。
对齐容器与宿主机的 UID/GID
Linux 只认数字 ID,不认用户名。容器里 UID 1001 写的文件,在宿主机上就归属 UID 1001 对应的用户——哪怕你根本不知道那是谁。风险就在这种“静默移交”里。
- 启动时显式指定:用 docker run --user $(id -u):$(id -g) 把当前宿主用户的 UID/GID 传进去,确保它和挂载目录的所有者一致
- 查清目标目录归属:ls -ld /host/path 看清楚 UID/GID,再决定容器该用哪个用户启动
- 避免在 Dockerfile 里写 USER root 或留空 USER 指令,除非你明确需要且已隔离该目录的访问范围
限制挂载行为本身
能不挂载就不挂载;必须挂载时,尽量缩小暴露面。
- 只读挂载优先:-v /host/conf:/app/conf:ro,配置类路径一律加 :ro
- 改用命名卷:docker volume create mydata,让 Docker 自行管理底层归属,不把宿主路径直接暴露给容器
- 禁用 root 映射透传:NFS 共享务必检查 /etc/exports 是否启用了 root_squash,严禁出现 no_root_squash
加固运行时边界
即使 UID 对齐了,也要防止容器借写入能力做越界操作。
- 根文件系统设为只读:--read-only,再单独用 --tmpfs 或 volume 给需要写的路径
- 启用 user namespace remapping:dockerd 配置中开启 userns-remap,让容器内 UID 0 在宿主机映射为普通 UID
- 敏感挂载加 SELinux 标签(仅限支持环境):-v /host/log:/app/log:Z,由系统自动打标签约束访问
自动化拦截源头风险
靠人工检查容易漏,要把防线前移到构建和部署环节。
- CI 流水线里加脚本:grep -r "docker\.sock\|\/var\/run\/docker\.sock" . || echo "✅ 安全"
- Dockerfile 扫描用 hadolint,拒绝含 VOLUME ["/var/run/docker.sock"] 或 RUN mount.*docker\.sock 的构建
- 镜像扫描工具加入 UID 检查规则,对未声明 USER 或 USER root 的镜像自动告警











