为 Pod 配置用户名字空间

特性状态: Kubernetes v1.25 [alpha]

本页展示如何为无状态 Pod 配置用户名字空间。可以将容器内的用户与主机上的用户隔离开来。

在容器中以 root 用户运行的进程可以以不同的(非 root)用户在宿主机上运行;换句话说, 进程在用户名字空间内部拥有执行操作的全部特权,但在用户名字空间外部并没有执行操作的特权。

你可以使用这个特性来减少有害的容器对同一宿主机上其他容器的影响。 有些安全脆弱性问题被评为 HIGH or CRITICAL,但当用户名字空间被启用时, 它们是无法被利用的。相信用户名字空间也能减轻一些未来的漏洞的影响。

在不使用用户名字空间的情况下,对于以 root 用户运行的容器而言,发生容器逃逸时, 容器将拥有在宿主机上的 root 特权。如果容器被赋予了某些权限,则这些权限在宿主机上同样有效。 当使用用户名字空间时这些都不可能发生。

准备开始

你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。 建议在至少有两个节点的集群上运行本教程,且这些节点不作为控制平面主机。 如果你还没有集群,你可以通过 Minikube 构建一个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:

你的 Kubernetes 服务器版本必须不低于版本 v1.25. 要获知版本信息,请输入 kubectl version.

  • 节点上的操作系统必须为 Linux
  • 你需要在宿主机上执行命令
  • 你需要能够通过 exec 操作进入 Pod
  • 特性 UserNamespacesStatelessPodsSupport 需要被启用。

此外, 需要容器运行时提供相应的支持, 才能将此特性与 Kubernetes 无状态 Pod 一起使用:

  • CRI-O: v1.25 支持用户名字空间。

请注意 如果你的容器运行时环境不支持用户名字空间,字段 pod.spec 将被忽略, 并且系统会在没有用户名字空间的环境中创建 Pod。

运行一个使用用户名字空间的 Pod

为一个无状态的 Pod 启用用户名字空间需要设置 .spechostUsers 字段 为 false. 例如:

apiVersion: v1
kind: Pod
metadata:
  name: userns
spec:
  hostUsers: false
  containers:
  - name: shell
    command: ["sleep", "infinity"]
    image: debian
  1. 在你的集群上创建 Pod:

    kubectl apply -f https://k8s.io/examples/pods/user-namespaces-stateless.yaml
    
  1. 挂接到容器上并执行 readlink /proc/self/ns/user

    kubectl attach -it userns bash
    

执行命令的输出类似于:

readlink /proc/self/ns/user
user:[4026531837]
cat /proc/self/uid_map
0          0 4294967295

然后,在主机中打开一个 Shell 并运行相同的命令。

输出一定是不同的。这意味着主机和 Pod 使用不同的用户名字空间。当未启用用户名字空间时, 宿主机和 Pod 使用相同的用户名字空间。

如果你在用户名字空间中运行 kubelet,则需要将在 Pod 中运行命令的输出与在主机中运行的输出进行比较:

readlink /proc/$pid/ns/user
user:[4026534732]

使用 kubelet 的进程号代替 $pid

本页面中的条目引用了第三方产品或项目,这些产品(项目)提供了 Kubernetes 所需的功能。Kubernetes 项目的开发人员不对这些第三方产品(项目)负责。请参阅CNCF 网站指南了解更多细节。

在提交更改建议,向本页添加新的第三方链接之前,你应该先阅读内容指南。

最后修改 February 22, 2023 at 9:09 AM PST: 更新编辑 (f4a7975)