本文发布已超过一年。较旧的文章可能包含过时的内容。请检查页面中的信息自发布以来是否已变得不正确。

用户命名空间:现在支持在 Alpha 版本中运行有状态 Pod!

Kubernetes v1.25 引入了对仅限无状态 Pod 的用户命名空间的支持。Kubernetes 1.28 在 1.27 中进行了一些设计更改后取消了该限制。

此功能的优点在于

  • 采用非常简单(您只需要在 Pod 规范中设置一个布尔值)
  • 对于大多数应用程序不需要任何更改
  • 通过大幅增强容器的隔离性并缓解被评为高危和危急的 CVE,从而提高安全性。

本文介绍了用户命名空间的基础知识,并展示了

  • 最近的 Kubernetes v1.28 版本中的更改
  • 一个被评为高危的漏洞演示,该漏洞在使用用户命名空间时无法利用
  • 使用此功能的运行时要求
  • 您对未来版本中有关用户命名空间的期望。

什么是用户命名空间?

用户命名空间是 Linux 的一项功能,可将容器的用户和组标识符(UID 和 GID)与主机上的标识符隔离。容器中的标识符可以映射到主机上的标识符,这样用于不同容器的主机 UID/GID 永远不会重叠。更重要的是,这些标识符可以映射到主机上非特权且不重叠的 UID 和 GID。这基本上意味着两件事

  • 由于不同容器的 UID 和 GID 映射到主机上的不同 UID 和 GID,即使容器逃脱了容器边界,容器也更难相互攻击。例如,如果容器 A 在主机上使用与容器 B 不同的 UID 和 GID 运行,则它对容器 B 的文件和进程所能执行的操作是有限的:只能读取/写入文件允许给其他人的内容,因为它永远不会拥有所有者或组的权限(保证不同容器的主机上的 UID/GID 是不同的)。

  • 由于 UID 和 GID 映射到主机上的非特权用户,因此如果容器逃脱了容器边界,即使它在容器内部以 root 身份运行,它在主机上也没有特权。这极大地保护了它可以读取/写入的主机文件,以及它可以向其发送信号的进程等等。

此外,授予的功能仅在用户命名空间内有效,而不在主机上有效。

如果不使用用户命名空间,以 root 身份运行的容器,在发生容器突破的情况下,将在节点上拥有 root 权限。如果某些功能被授予给容器,这些功能在主机上也有效。使用用户命名空间时,这些都不成立(当然,要排除 bug 🙂)。

1.28 中的更改

如前所述,从 1.28 开始,Kubernetes 支持具有状态ful pod 的用户命名空间。这意味着具有用户命名空间的 Pod 可以使用任何类型的卷,它们不再像以前那样仅限于某些卷类型。

用于激活此功能的功能门已重命名,不再是 UserNamespacesStatelessPodsSupport,而是从 1.28 开始应使用 UserNamespacesSupport。做了很多更改,并且对节点主机的要求也发生了变化。因此,在 Kubernetes 1.28 中,功能标志被重命名以反映这一点。

演示

Rodrigo 创建了一个演示,该演示利用了 CVE 2022-0492,并展示了如何在不使用用户命名空间的情况下发生漏洞利用。他还展示了如何无法从容器使用此功能的 Pod 中利用此漏洞。

此漏洞被评为高危,它允许没有特殊权限的容器读取/写入主机上的任何路径,并在主机上以 root 身份启动进程。

如今,容器中的大多数应用程序都以 root 身份或以半可预测的非 root 用户身份(用户 ID 65534 是一个比较受欢迎的选择)运行。当您使用 userns 运行具有容器的 Pod 时,Kubernetes 会以非特权用户的身份运行这些容器,而无需对您的应用程序进行任何更改。

这意味着以用户 65534 运行的两个容器将有效地映射到主机上的不同用户,从而限制了它们在发生逃逸的情况下可以对彼此执行的操作,并且如果它们以 root 身份运行,则主机上的特权将降低为非特权用户。

节点系统要求

使用此功能对 Linux 内核版本以及容器运行时有要求。

在 Linux 上,您需要 Linux 6.3 或更高版本。这是因为该功能依赖于一个名为 idmap mounts 的内核功能,并且在 Linux 6.3 中合并了使用 idmap mounts 和 tmpfs 的支持。

如果您将 CRI-O 与 crun 结合使用,则CRI-O 1.28.1 和 crun 1.9 或更高版本支持此功能。如果您将 CRI-O 与 runc 结合使用,则仍不支持此功能。

containerd 支持目前的目标是 containerd 2.0;无论您将其与 crun 还是 runc 结合使用,可能都无关紧要。

请注意,containerd 1.7 添加了 Kubernetes 1.25 和 1.26 中实现的对用户命名空间的实验性支持。containerd 1.7 不支持在 1.27 中完成的重新设计,因此,就用户命名空间支持而言,它仅适用于 Kubernetes 1.25 和 1.26。

containerd 1.7 中存在的一个限制是,在 Pod 启动期间,它需要更改容器镜像中每个文件和目录的所有权。这意味着它具有存储开销,并且会显着影响容器启动延迟。Containerd 2.0 可能会包含一个实现,从而消除添加的启动延迟和存储开销。如果您计划在生产中使用带有用户命名空间的 containerd 1.7,请考虑这一点。

这些 containerd 限制都不适用于 CRI-O 1.28

接下来是什么?

展望 Kubernetes 1.29,计划是与 SIG Auth 合作,将用户命名空间集成到 Pod 安全标准 (PSS) 和 Pod 安全准入中。目前,计划是在使用用户命名空间时放宽 PSS 策略中的检查。这意味着,如果正在使用用户命名空间,则字段 spec[.*].securityContext runAsUserrunAsNonRootallowPrivilegeEscalationcapabilities 将不会触发违规。该行为可能会通过利用 API Server 功能门(如 UserNamespacesPodSecurityStandards 或类似功能)来控制。

如何参与?

您可以通过多种方式联系 SIG Node

您也可以直接联系我们

  • GitHub: @rata @giuseppe @saschagrunert
  • Slack: @rata @giuseppe @sascha