Kubernetes 文档 / 概念 / 工作负载 / Pod / 用户命名空间
此文档从 Kubernetes 官网摘录
中文地址
英文地址
在容器中以 root 身份运行的进程可以在主机中以不同的(非 root)用户身份运行; 换句话说,该进程在用户命名空间内的操作具有完全的权限, 但在命名空间外的操作是无特权的。
你可以使用这个功能来减少被破坏的容器对主机或同一节点中的其他 Pod 的破坏。
准备开始
这是一个只对 Linux 有效的功能特性,且需要 Linux 支持在所用文件系统上挂载 idmap。 这意味着:
在节点上,你用于 /var/lib/kubelet/pods/ 的文件系统,或你为此配置的自定义目录, 需要支持 idmap 挂载。
Pod 卷中使用的所有文件系统都必须支持 idmap 挂载。
Linux 6.3 中支持 idmap 挂载的一些比较流行的文件系统是:btrfs、ext4、xfs、fat、 tmpfs、overlayfs。
此外,容器运行时及其底层 OCI 运行时必须支持用户命名空间。以下 OCI 运行时提供支持:
- crun 1.9 或更高版本(推荐 1.13+ 版本)
此外,需要在容器运行时提供支持, 才能在 Kubernetes Pod 中使用这一功能:
- CRI-O:1.25(及更高)版本支持配置容器的用户命名空间。
介绍
用户命名空间是一个 Linux 功能,允许将容器中的用户映射到主机中的不同用户。 此外,在某用户命名空间中授予 Pod 的权能只在该命名空间中有效,在该命名空间之外无效。
一个 Pod 可以通过将 pod.spec.hostUsers 字段设置为 false 来选择使用用户命名空间。
kubelet 将挑选 Pod 所映射的主机 UID/GID, 并以此保证同一节点上没有两个 Pod 使用相同的方式进行映射。
pod.spec 中的 runAsUser、runAsGroup、fsGroup 等字段总是指的是容器内的用户。 启用该功能时,有效的 UID/GID 在 0-65535 范围内。这以限制适用于文件和进程(runAsUser、runAsGroup 等)。
了解 Pod 的用户命名空间
在创建 Pod 时,默认情况下会使用几个新的命名空间进行隔离: 一个网络命名空间来隔离容器网络,一个 PID 命名空间来隔离进程视图等等。 如果使用了一个用户命名空间,这将把容器中的用户与节点中的用户隔离开来。
设置一个节点以支持用户命名空间
默认情况下,kubelet 会分配 0-65535 范围以上的 Pod UID/GID, 这是基于主机的文件和进程使用此范围内的 UID/GID 的假设,也是大多数 Linux 发行版的标准。 此方法可防止主机的 UID/GID 与 Pod 的 UID/GID 之间出现重叠。
kubelet 可以对 Pod 的用户 ID 和组 ID 使用自定义范围。要配置自定义范围,节点需要具有:
- 系统中的用户 kubelet(此处不能使用任何其他用户名)。
- 已安装二进制文件 getsubids(shadow-utils 的一部分)并位于 kubelet 二进制文件的 PATH 中。
- kubelet 用户的从属 UID/GID 配置 (请参阅 man 5 subuid 和 man 5 subgid)
对于分配给 kubelet 用户的从属 ID 范围, 你必须遵循一些限制:
-
启动 Pod 的 UID 范围的从属用户 ID 必须是 65536 的倍数,并且还必须大于或等于 65536。 换句话说,Pod 不能使用 0-65535 范围内的任何 ID;kubelet 施加此限制是为了使创建意外不安全的配置变得困难。
-
从属 ID 计数必须是 65536 的倍数
-
从属 ID 计数必须至少为 65536 x ,其中 是节点上可以运行的最大 Pod 数量。
-
你必须为用户 ID 和组 ID 分配相同的范围。如果其他用户的用户 ID 范围与组 ID 范围不一致也没关系。
-
所分配的范围不得与任何其他分配重叠。
-
从属配置必须只有一行。换句话说,你不能有多个范围。
例如,你可以定义 /etc/subuid 和 /etc/subgid 来为 kubelet 用户定义以下条目:
# 格式为:
# name:firstID:count of IDs
# 在哪里:
# - firstID 是 65536 (可能的最小值)
# - IDs 的数量是 110(默认数量限制)* 65536
kubelet:65536:7208960
与 Pod 安全准入检查的集成
如果你启用相关特性门控并创建了使用用户命名空间的 Pod,以下的字段不会被限制, 即使在执行了 Baseline 或 Restricted Pod 安全性标准的上下文中。这种行为不会带来安全问题, 因为带有用户命名空间的 Pod 内的 root 实际上指的是容器内的用户,绝不会映射到主机上的特权用户。 以下是在这种情况下不进行检查的 Pod 字段列表:
- spec.securityContext.runAsNonRoot
- spec.containers[*].securityContext.runAsNonRoot
- spec.initContainers[*].securityContext.runAsNonRoot
- spec.ephemeralContainers[*].securityContext.runAsNonRoot
- spec.securityContext.runAsUser
- spec.containers[*].securityContext.runAsUser
- spec.initContainers[*].securityContext.runAsUser
限制
当 Pod 使用用户命名空间时,不允许 Pod 使用其他主机命名空间。 特别是,如果你设置了 hostUsers: false,那么你就不可以设置如下属性:
- hostNetwork: true
- hostIPC: true
- hostPID: true