Linux CRI-O 的 pinns 与用户 namespace 隔离增强

1次阅读

pinns 是 cri-o 默认的轻量级容器用户命名空间初始化工具,专为解决 unshare 在嵌套 user Namespace、uid/gid 映射传递及与 runc 协作时序上的缺陷而设计。

Linux CRI-O 的 pinns 与用户 namespace 隔离增强

pinns 是什么,为什么 CRI-O 会用它而不是直接调用 unshare

pinns 是 CRI-O 默认使用的轻量级容器命名空间初始化工具,专为用户命名空间(userns)隔离设计。它不替代 unshare,而是补足其在多层级 user namespace 场景下的缺陷:比如嵌套 user namespace 创建、uid/gid 映射传递、以及与 runc 的协作时机控制。

常见错误现象是手动替换 pinnsunshare --user --map-root-user 后,容器启动失败并报 operation not permitted —— 这是因为 unshare 没有处理 CRI-O 要求的「先建 user ns、再进新 ns、最后 exec runc」这一精确时序。

  • pinns 会在 fork 出子进程后立刻 drop capabilities,再进入新 user namespace,避免 capability 污染
  • 它读取 CRI-O 传入的 --uid-map--gid-map 参数,生成符合内核要求的映射格式,unshare 不支持原生解析这些参数
  • 当启用 userns-remap 且 host 用户被映射到非 0 uid 时,pinns 会自动跳过 setuid/setgid 调用,而 unshare 可能因权限不足卡死

如何确认 pinns 正在生效,以及它是否真在用 user namespace

最直接的办法是进容器查 /proc/self/status 中的 Uid:Gid: 行,并比对 /proc/self/ns/user 的 inode —— 如果 uid 显示非 0 但进程能访问 /etc/passwd,说明 user namespace 已启用且 pinns 成功完成了映射。

验证步骤:

  • 启动一个带 securityContext.runAsUser: 1001 的 Pod,确保 CRI-O 配置了 userns_mode = "auto"
  • 进容器执行 cat /proc/self/status | grep -E "Uid|Gid",输出应类似 Uid: 1001 1001 1001 1001
  • 执行 ls -l /proc/self/ns/user,若显示 user:[4026532728] 这类非默认编号,说明已进入独立 user namespace
  • 检查 CRI-O 日志:journalctl -u crio | grep pinns,应看到类似 execing pinns with args [... --uid-map 0:1001:1 ...]

启用 user namespace 后,哪些操作会突然失败

不是所有系统调用都能跨 user namespace 无缝工作。典型失效点集中在需要内核级权限或全局资源访问的地方:

  • 挂载 tmpfs 或 overlayfs 时,若未显式指定 uid=/gid=,内核可能拒绝创建,因为当前 user namespace 没有对 host rootfs 的写权限
  • sethostname() 失败并报 EPERM:即使容器里是 root,user namespace 中的 root 并不等价于 host root,无法修改 UTS namespace
  • 使用 memfd_create() + seccomp 组合时,某些 seccomp 规则因 capability 检查逻辑变化而误判,需额外添加 CAP_SYS_ADMIN 到 bounding set
  • SElinux 标签继承异常:如果 host 使用 kernel.sched_autogroup_enabled=1,user namespace 内进程可能无法正确继承 context,需在 pod annotation 中显式设 container.apparmor.security.beta.kubernetes.io/pod: runtime/default

pinns 的配置项和兼容性边界

CRI-O 不直接暴露 pinns 参数,所有控制都通过 /etc/crio/crio.conf 中的 [crio.runtime] 段落完成。关键配置只有两个:

  • userns_mode = "auto":CRI-O 自动为每个容器分配独立 user namespace,pinns 接收映射规则并执行
  • userns_mode = "host":完全绕过 pinns,此时 runc 直接运行,无 user namespace 隔离

注意:CRI-O v1.26+ 要求内核 ≥ 5.12 才能稳定支持嵌套 user namespace + pinns;低于该版本时,若开启 userns_mode = "auto"pinns 可能静默降级为 host 模式,且日志中仅提示 falling back to host userns,容易被忽略。

text=ZqhQzanResources