Kubernetes v1.37 将 KubeletInUserNamespace 特性门控提升到 Beta,并默认开启。这个变化不会自动把现有集群变成 rootless 集群,但它标志着 Kubernetes 节点组件以非 root 用户运行的方案已经从长期实验阶段进入更稳定的使用阶段。
Rootless 模式的核心目标很明确:即使 kubelet、CRI、OCI runtime、CNI 插件或 kube-proxy 出现容器逃逸类漏洞,攻击者获得的也只是用户命名空间中的受限 root 权限,而不是宿主机真正的 root 权限。
Rootless 节点解决什么问题
传统 Kubernetes 节点上的 kubelet、容器运行时和网络组件通常以 root 身份运行。这些组件拥有较高权限,一旦存在容器逃逸或错误配置漏洞,影响范围可能直接扩大到整个宿主机。
历史上已经出现过多类风险:
- CRI-O 可能被利用设置任意 sysctl,进而触发宿主机上的任意代码执行。
- runc 曾出现绕过容器屏蔽路径、访问宿主机 procfs 文件,以及向宿主机 procfs 写入的风险。
- kubelet 的
gitRepovolume 曾被用于诱导 kubelet 以 root 执行任意命令。 - containerd 等组件也可能因恶意容器镜像元数据而在宿主机执行攻击者控制的命令。
在用户命名空间中运行节点组件后,宿主机上的普通用户 UID,例如 1000,可以被映射为命名空间内的 UID 0。这个“假 root”可以完成很多节点任务,例如挂载卷、创建 cgroup,以及配置 Pod 的网络命名空间,但它的权限边界仍然局限于用户命名空间。
这并不是完整的主机安全边界。攻击者仍可能破坏该用户拥有的文件和进程,也不能依靠用户命名空间解决 Linux 内核本身的漏洞。内核、启动加载器和固件也不会因为 rootless 模式而变得不可修改,因此仍然需要配合 seccomp、最小权限、及时升级 runtime 和节点隔离等传统加固措施。
Beta 版本具体变了什么
KubeletInUserNamespace 在 v1.37 中默认开启,但这只意味着 kubelet 可以在用户命名空间中正常工作,不代表 Kubernetes 会自动创建用户命名空间。现有以 root 运行的集群不会因为升级到 v1.37 而改变运行方式。
该特性本身的代码变化相对克制,主要让 kubelet 忽略在 rootless 环境中预期会出现的权限错误,例如设置 vm.overcommit_memory、kernel.panic 等 sysctl 时的失败,以及读取 /dev/kmsg 内核日志时的权限问题。用户命名空间必须由 Kubernetes 之外的运行环境提前创建,例如 rootless Docker、rootless Podman 或 rootless nerdctl。
v1.37 还让节点状态更容易被观察。通过以下命令,可以查看节点是否运行在用户命名空间中:
kubectl get nodes -o yaml
节点信息中会出现类似下面的字段:
status:
features:
features:
supplementalGroupsPolicy: true
nodeInfo:
architecture: amd64
runtimeHandlers: []
runningInUserNamespace: true
字段的具体位置和其他节点状态字段可能随输出版本变化,实际使用时应以当前集群返回的结构为准。管理员可以据此为 rootless 节点设置标签或污点,避免将依赖真实 root 权限的工作负载调度过去,例如某些 CNI 安装器、硬件管理组件或需要直接操作宿主机内核的 DaemonSet。
与 Pod 用户命名空间不是一回事
Rootless 节点和用户命名空间 Pod 经常被混为一谈,但它们保护的对象不同。
KubeletInUserNamespace:让 kubelet、CRI、OCI runtime、CNI 和 kube-proxy 等节点组件以非 root 用户运行。hostUsers: false:让某个 Pod 内的进程进入用户命名空间,但节点组件仍然可以以 root 运行。
两者可以同时使用。随着 Linux 6.3 对 idmapped tmpfs 的支持、Kubernetes v1.33 默认启用 UserNamespacesSupport,以及 containerd 2.1 对可写 cgroup 的支持,rootless Kubernetes 现在已经可以进一步嵌套到 hostUsers: false 的 Pod 中。这为 Kubernetes-in-Kubernetes、AI agent 沙箱和不希望获得 privileged: true 的测试环境提供了更细粒度的隔离方式。
可以这样启动一个 Rootless 集群
最容易上手的方式是先准备 rootless Docker,再使用 kind 创建集群。下面的命令假设 Docker rootless 环境已经安装,并且当前用户有权运行 rootless Docker:
# 安装并启动当前用户的 rootless Docker 服务
dockerd-rootless-setuptool.sh install
# 确认客户端连接的是 rootless Docker
docker info --format '{{.SecurityOptions}}'
# 使用 kind 创建 Kubernetes 集群
kind create cluster --name rootless-demo
# 查看节点状态
kubectl get nodes -o wide
kubectl get nodes -o yaml | rg 'runningInUserNamespace'
如果使用 rootless Podman 或 rootless nerdctl,kind 也可以作为上层集群工具使用,但需要根据本机的 socket、cgroup、内核模块和 systemd 配置调整环境。minikube 的基本用法可以是:
dockerd-rootless-setuptool.sh install
minikube start --driver=docker
kubectl get nodes
这些命令创建的是单节点本地集群,适合验证兼容性和开发流程。生产部署前,需要单独检查 CNI、CSI、存储挂载、cgroup 操作、端口转发和宿主机网络规则。某些驱动仍然假设自己拥有真实 root 权限,可能无法在 rootless 节点上工作。
适合哪些场景
Rootless 模式的价值不只在生产集群。
生产集群可以将容器运行时漏洞的潜在影响限制在专用宿主机用户账户范围内,降低单个节点组件被攻破后的破坏能力。
共享机器和 HPC 环境可以让用户在不向机器管理员申请 root 权限的前提下运行 Kubernetes,同时降低误改其他用户环境的风险。
笔记本本地集群可以避免测试集群意外修改宿主机 iptables 规则,影响 VPN、代理或其他开发服务。
AI 编码 agent 沙箱可以为 agent 创建专用本地用户账户,并让测试 Kubernetes 集群运行在该账户下。当 agent 被恶意网页、依赖包或仓库内容诱导执行危险命令时,宿主机的核心配置仍多一层保护。
Kubernetes-in-Kubernetes可以将嵌套集群放入 hostUsers: false 的 Pod,比只依赖 Kubernetes API namespace 获得更强的进程和权限隔离。
落地前的检查清单
采用 Beta 特性时,建议把“能启动”与“能承载业务”分开验证:
- 确认宿主机 Linux 内核、user namespace、cgroup 和网络转发能力满足运行时要求。
- 用真实使用的 CNI 和 CSI 驱动测试网络、卷挂载、卸载和故障恢复。
- 检查所有 DaemonSet 是否隐含依赖真实 root、宿主机路径或
privileged: true。 - 根据
runningInUserNamespace为节点设置标签或污点,隔离不兼容工作负载。 - 继续启用 seccomp,并减少容器不必要的系统调用和宿主机挂载。
- 观察 rootless 节点上的日志、cgroup 资源统计、镜像拉取和升级流程。
- 将 rootless 视为纵深防御的一层,而不是内核漏洞的替代修复方案。
KubeletInUserNamespace 从 2018 年的实验开始,经过 Kubernetes v1.22 的 Alpha 阶段,最终在 v1.37 进入 Beta。它不会改变所有集群的默认运行方式,却为生产隔离、共享机器、本地开发和嵌套 Kubernetes 提供了一条更现实的权限收敛路径。后续能否进入 GA,将取决于更多 runtime、CNI、CSI 和实际部署环境的反馈。