必须在Dockerfile中用adduser创建固定UID/GID用户并用USER指令切换,K8s中需同步配置runAsUser、runAsGroup和fsGroup三重锁定,再禁用提权与收缩capabilities,最后通过id、ls和touch/sudo三步实测验证。
直接用 user 指令配合 kubernetes 的 securitycontext,能从镜像层和运行时双维度封堵权限漏洞,尤其对挂载卷(volume)场景下的越权读写、跨容器污染、宿主机文件篡改等风险有强抑制作用。关键不在“用了没”,而在“怎么配才不打架、不留缝”。
USER 必须提前在镜像中创建并固定 UID/GID
不能依赖运行时动态创建,否则 securityContext.runAsUser 会覆盖失败或引发 UID 映射错乱。必须在 Dockerfile 中显式定义且与 K8s 配置对齐:
- 用
adduser -u 1001 -S appuser创建系统用户,指定 UID(推荐 1001–65535),避免使用 0 或 65534 等特殊值 - 用
COPY --chown=1001:1001确保应用文件归属该 UID,防止启动时报“permission denied” - 最后用
USER 1001:1001切换——这里写数字比写用户名更可靠,避免镜像内 /etc/passwd 缺失导致解析失败
SecurityContext 要做三重 UID/GID 锁定
仅设 runAsUser 不够,挂载卷时若组权限不匹配,仍可能因 fsGroup 自动补权而绕过限制:
-
runAsUser: 1001:强制进程以 UID 1001 运行,与镜像中 USER 一致 -
runAsGroup: 1001:避免进程默认使用 root 组(GID 0),防止对 group-writable 目录的误操作 -
fsGroup: 2000:为挂载卷单独指定 GID(如 2000),让 kubelet 自动chgrp -R 2000卷内文件,但不提升主进程权限
这样,即使挂载了 hostPath 或 PersistentVolume,容器内进程也只能以 1001:1001 身份访问,无法修改其他 UID 的文件,也避免因卷内文件属组为 root 导致的写入放行。
禁用提权 + 收缩 capabilities,堵死逃逸后门
USER 和 securityContext 只管“身份”,不管“能力”。攻击者拿到非 root UID 后,仍可能通过 capability 提权或滥用内核接口逃逸:
-
allowPrivilegeEscalation: false:禁止进程调用execve()切换到更高权限 UID(如 setuid 二进制) -
capabilities:下drop: ["ALL"],再按需add: ["NET_BIND_SERVICE"](仅当需监听 80/443) - 避免
privileged: true或挂载/proc/sys、/dev等高危路径
验证是否真生效:三步快速自检
上线前别只信配置,进容器实测:
- 执行
id:输出应为uid=1001(appuser) gid=1001(appuser) groups=1001(appuser) - 执行
ls -l /mounted-volume/:所有文件属组应为2000(fsGroup),且无 world-writable 权限 - 尝试
touch /mounted-volume/test && sudo su:两者都应报错(Permission denied / Operation not permitted)
只要这三项全过,挂载卷就不再成为权限泄漏通道,容器真正做到了“有边界、无特权、难逃逸”。


















