Kubernetes中每个Pod都有自己的进程命名空间,其中的进程相互隔离,互不干扰。但是,在某些情况下可能需要让多个Pod中的进程共享同一个进程命名空间,可以通过将多个Pod配置在同一个节点上并使用共享存储来实现。本教程将介绍如何为Pod配置进程命名空间共享。
在容器中以 root 用户运行的进程可以以不同的(非 root)用户在宿主机上运行;换句话说, 进程在用户名字空间内部拥有执行操作的全部特权,但在用户名字空间外部并没有执行操作的特权。
可以使用这个特性来减少有害的容器对同一宿主机上其他容器的影响。 有些安全脆弱性问题被评为 HIGH or CRITICAL,但当用户名字空间被启用时, 它们是无法被利用的。相信用户名字空间也能减轻一些未来的漏洞的影响。
在不使用用户名字空间的情况下,对于以 root 用户运行的容器而言,发生容器逃逸时, 容器将拥有在宿主机上的 root 特权。如果容器被赋予了某些权限,则这些权限在宿主机上同样有效。 当使用用户名字空间时这些都不可能发生。
一、准备
必须拥有一个 Kubernetes 的集群,同时必须配置 kubectl 命令行工具与集群通信。 建议在至少有两个不作为控制平面主机的节点的集群上运行本教程。 如果还没有集群,可以通过 Minikube 构建一个自己的集群,或者可以使用下面的 Kubernetes 练习环境之一:
- Killercoda
- 玩转 Kubernetes
Kubernetes 服务器版本必须不低于版本 v1.25. 要获知版本信息,请输入 kubectl version.
本条目指向第三方项目或产品,而该项目(产品)不是 Kubernetes 的一部分。
- 节点上的操作系统必须为 Linux;
- 需要在宿主机上执行命令;
- 需要能够通过 exec 操作进入 Pod;
- 需要启用 UserNamespacesSupport 特性门控。
注意:在用户名字空间原来仅支持无状态的 Pod 时,启用用户名字空间的特性门控先前被命名为UserNamespacesStatelessPodsSupport。 只有 Kubernetes v1.25 到 v1.27 才能识别UserNamespacesStatelessPodsSupport。
所使用的集群必须包括至少一个符合 要求 的节点,以便为 Pod 配置用户名字空间。
如果有混合节点,并且只有部分节点支持为 Pod 配置用户名字空间, 还需要确保配置了用户名字空间的 Pod 被调度到合适的节点。
- CRI-O: v1.25 支持用户名字空间。
注意:如果容器运行时环境不支持用户名字空间,那么 Pod 规约中的 hostUsers 字段将被静默忽略, 并且系统会在没有用户名字空间的环境中创建 Pod。
二、运行Pod
为一个 Pod 启用用户名字空间需要设置 .spec 的 hostUsers 字段为 false. 例如:
apiVersion: v1 kind: Pod metadata: name: userns spec: hostUsers: false containers: - name: shell command: ["sleep", "infinity"] image: debian
在集群上创建 Pod:
kubectl apply -f https://k8s.io/examples/pods/user-namespaces-stateless.yaml
挂接到容器上并执行 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