user namespace 通过 uid/gid 映射实现权限虚拟化,容器内 root 映射为宿主机普通用户(如 uid 100100),需内核 ≥3.8、启用 max_user_namespaces、配合 setgroups 降权、uid_map 映射及 mount/pid/uts/ipc 等命名空间协同隔离。

User Namespace 是容器安全隔离的基石,它让容器内看似 root 的进程,在宿主机上只是普通用户。配置不当,隔离就形同虚设;配对了,逃逸风险大幅降低。
确认并启用内核支持
没这个前提,后面都白搭:
- 运行 uname -r,确保内核版本 ≥ 3.8(生产环境建议 ≥ 5.4)
- 检查 cat /proc/sys/user/max_user_namespaces,输出非零(如 65535)表示已启用;若为 0,需在 /etc/sysctl.conf 中添加 user.max_user_namespaces=65535,再执行 sysctl -p
- 普通用户默认可创建 User Namespace,无需 sudo——这是它区别于其他命名空间的关键优势
配置 UID/GID 映射(核心步骤)
映射决定了“容器里的 root 到底是谁”:
- 宿主机用户必须在 /etc/subuid 和 /etc/subgid 中分配子 ID 范围,例如:alice:100000:65536(表示 alice 用户可使用 UID 100000–165535)
- 手动构建时,先执行 echo "deny" > /proc/self/setgroups(否则写入映射会失败)
- 再写入映射:例如将宿主机 UID 1001 映射为容器内 UID 0,执行 echo "0 1001 1" > /proc/self/uid_map;同理写 gid_map
- Docker 24.0+ 可直接用 --userns-remap=default,自动为每个容器分配独立 UID 范围,无需手写映射
必须搭配 Mount 和 PID 等命名空间
单靠 User Namespace 无法防逃逸:
- 启动命令至少包含 --user --pid --mount --uts --ipc,例如:unshare --user --pid --mount --uts --ipc --fork /bin/bash
- 进入后立即执行 mount --make-rprivate /,关闭挂载传播,防止影响宿主机
- 用 mount --bind 或 chroot 提供干净根目录,避免容器看到宿主机 /etc、/var 等敏感路径
- 验证:在容器内运行 ls /etc/shadow 应提示“Permission denied”,而非读取成功
加固策略不能少
映射只是起点,绕过手段很多:
- 禁用危险系统调用:通过 seccomp 策略屏蔽 setuid、chown、cap_setfcap 等,堵住提权路径
- 限制 capabilities:避免 --privileged,慎用 CAP_SYS_ADMIN;按需添加如 NET_BIND_SERVICE
- 根文件系统设为只读:--read-only,再用 --tmpfs 或 -v 按需开放可写路径
- LXC/LXD 配置中明确写 lxc.idmap = u 0 100000 65536,确保映射区间固定且可审计
不复杂但容易忽略——User Namespace 安全不是开个开关就行,而是映射、挂载、能力、策略四者咬合的结果。











