为 Pod 配置 user 名字空间

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

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

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

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

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

准备开始

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

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

🛇 本条目指向第三方项目或产品,而该项目(产品)不是 Kubernetes 的一部分。更多信息

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

说明:

在 user 名字空间原来仅支持无状态的 Pod 时,启用 user 名字空间的特性门控先前被命名为 UserNamespacesStatelessPodsSupport。 只有 Kubernetes v1.25 到 v1.27 才能识别 UserNamespacesStatelessPodsSupport

你所使用的集群必须包括至少一个符合 要求 的节点,以便为 Pod 配置 user 名字空间。

如果你有混合节点,并且只有部分节点支持为 Pod 配置 user 名字空间, 你还需要确保配置了 user 名字空间的 Pod 被调度到合适的节点。

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

为一个 Pod 启用 user 名字空间需要设置 .spechostUsers 字段为 false。例如:

pods/user-namespaces-stateless.yaml为 Pod 配置用户名字空间 - 图1

  1. apiVersion: v1
  2. kind: Pod
  3. metadata:
  4. name: userns
  5. spec:
  6. hostUsers: false
  7. containers:
  8. - name: shell
  9. command: ["sleep", "infinity"]
  10. image: debian
  1. 在你的集群上创建 Pod:

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

    1. kubectl attach -it userns bash

运行这个命令:

  1. readlink /proc/self/ns/user

输出类似于:

  1. user:[4026531837]

还运行:

  1. cat /proc/self/uid_map

输出类似于:

  1. 0 833617920 65536

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

readlink 命令显示进程运行所在的用户命名空间。在主机上和容器内运行时应该有所不同。

容器内 uid_map 文件的最后一个数字必须是 65536,在主机上它必须是更大的数字。

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

  1. readlink /proc/$pid/ns/user

使用 kubelet 的进程号代替 $pid