非 root 运行是什么
非 root 运行指容器内的应用以普通用户身份启动,实现方式有 Dockerfile 的 USER 指令、运行时的 --user 参数、编排层的 runAsUser。它不能让容器绝对安全,但能把容器内漏洞的利用价值压到最低,是加固里成本最低、收益明确的一项。
基本信息
| 实现手段 | 镜像 USER 指令、docker run --user、编排 runAsUser |
|---|---|
| UID 规划 | 用高位 UID(如 10001)降低与宿主账号撞号的可能 |
| 配套动作 | COPY --chown 改属主,数据与日志目录提前预建并授权 |
| 端口限制 | 1024 以下端口需要特权,非 root 要改用高位端口 |
| 验证方式 | docker exec <容器> id 看实际身份 |
典型使用场景
- 应用只读写自己的数据卷、不碰宿主目录时,加账号切 USER 即可完成改造
- 面向公网或多租户的服务,把提权风险限制在容器内普通用户范围内
- 与只读根文件系统、能力裁剪一起组成加固基线,逐项过安全检查
- 从既有镜像改造:先补账号和 --chown,再切 USER,分步验证启动
- 排查容器写不了文件的问题:核对进程身份与目录属主是否匹配
示例
示例
RUN useradd -r -u 10001 -m appuser
WORKDIR /app
COPY --chown=10001:10001 . .
RUN mkdir -p /app/data /app/logs && chown -R 10001:10001 /app
USER 10001
# 应用监听 8080 等非特权端口
ENTRYPOINT ["/app/server"]常见受阻点与处置
| 受阻点 | 原因 | 处置 |
|---|---|---|
| 启动即退出 | 数据目录属主是 root,进程无法写入 | 预建目录并 chown 给运行用户 |
| 监听失败 | 绑定了 80、443 等特权端口 | 改用高位端口,由反代或映射对外 |
| 读不到配置 | 配置文件 600 且属 root | 调整属主,或用只读挂载提供 |
| 日志丢失 | 向宿主目录写入无权限 | 日志输出到 stdout,由运行时收集 |
验证很直接:进容器执行 id,再用 docker inspect 看 Config.User;两者不一致说明编排参数覆盖了镜像里的设置。
与只读根文件系统搭配时要预留可写路径(应用数据目录、/tmp),否则应用会因无法创建临时文件而启动失败。