Pod 是 Kubernetes 中最小的可部署单元,由一个或多个容器组成。Pod 通常是网络行为者在利用容器时的初始执行环境。出于这个原因,Pod 应该被加固,以使利用更加困难,并限制成功入侵的影响。

image
图3:有 sidecar 代理作为日志容器的 Pod 组件

“非 root”容器和“无 root”容器引擎

默认情况下,许多容器服务以有特权的 root 用户身份运行,应用程序在容器内以 root 用户身份执行,尽管不需要有特权的执行。

通过使用非 root 容器或无 root 容器引擎来防止 root 执行,可以限制容器受损的影响。这两种方法都会对运行时环境产生重大影响,因此应该对应用程序进行全面测试,以确保兼容性。

非 root 容器:容器引擎允许容器以非 root 用户和非 root 组成员身份运行应用程序。通常情况下,这种非默认设置是在构建容器镜像的时候配置的。附录 A:非 root 应用的 Dockerfile 示例 显示了一个 Dockerfile 示例,它以非 root 用户身份运行一个应用。

非 root 用户。另外,Kubernetes 可以在 SecurityContext:runAsUser 指定一个非零用户的情况下,将容器加载到 Pod。虽然 runAsUser 指令在部署时有效地强制非 root 执行,但 NSA 和 CISA 鼓励开发者构建的容器应用程序,以非 root 用户身份执行。在构建时集成非 root 用户执行,可以更好地保证应用程序在没有 root 权限的情况下正常运行。

无 root 的容器引擎:一些容器引擎可以在无特权的上下文中运行,而不是使用以 root 身份运行的守护程序。在这种情况下,从容器化应用程序的角度来看,执行似乎是使用 root 用户,但执行被重新映射到主机上的引擎用户上下文。虽然无 root 容器引擎增加了一个有效的安全层,但许多引擎目前是作为实验性发布的,不应该在生产环境中使用。管理员应该了解这一新兴技术,并在供应商发布与 Kubernetes 兼容的稳定版本时寻求采用无 root 容器引擎。

不可变的容器文件系统

默认情况下,容器在自己的上下文中被允许不受限制地执行。在容器中获得执行权限的网络行为者可以在容器中创建文件、下载脚本和修改应用程序。Kubernetes 可以锁定一个容器的文件系统,从而防止许多暴露后的活动。

然而,这些限制也会影响合法的容器应用程序,并可能导致崩溃或异常行为。为了防止损害合法的应用程序,Kubernetes 管理员可以为应用程序需要写访问的特定目录挂载二级读 / 写文件系统。附录 B:只读文件系统的部署模板示例 显示了一个具有可写目录的不可变容器的例子。

构建安全的容器镜像

容器镜像通常是通过从头开始构建容器或在从存储库中提取的现有镜像基础上创建的。除了使用可信的存储库来构建容器外,镜像扫描是确保部署的容器安全的关键。在整个容器构建工作流程中,应该对镜像进行扫描,以识别过时的库、已知的漏洞或错误配置,如不安全的端口或权限。

image
图4:容器的构建工作流程,用 webhook 和准入控制器进行优化

实现镜像扫描的一种方法是使用准入控制器。准入控制器是 Kubernetes 的原生功能,可以在对象的持久化之前,但在请求被验证和授权之后,拦截和处理对 Kubernetes API 的请求。可以实现一个自定义或专有的 webhook,以便在集群中部署任何镜像之前执行扫描。如果镜像符合 webhook 配置中定义的组织的安全策略,这个准入控制器可以阻止部署。

Pod 安全策略

Pod 的创建应遵守最小授权原则。

Pod 安全策略(PSP)1是一个集群范围内的策略,它规定了 Pod 在集群内执行的安全要求 / 默认值。虽然安全机制通常是在 Pod/Deployment 配置中指定的,但 PSP 建立了一个所有 Pod 必须遵守的最低安全门槛。一些 PSP 字段提供默认值,当 Pod 的配置省略某个字段时使用。其他 PSP 字段被用来拒绝创建不符合要求的 Pod。PSP 是通过 Kubernetes 准入控制器执行的,所以 PSP 只能在 Pod 创建期间执行要求。PSP 并不影响已经在集群中运行的 Pod。

PSP 很有用,可以在集群中强制执行安全措施。PSP 对于由具有分层角色的管理员管理的集群特别有效。在这些情况下,顶级管理员可以施加默认值,对低层级的管理员强制执行要求。NSA 和 CISA 鼓励企业根据自己的需要调整 附录 C:Pod 安全策略示例 中的 Kubernetes 加固 PSP 模板。下表描述了一些广泛适用的 PSP 组件。

表 1: Pod 安全策略组件

字段名称 使用方法 建议
privileged 控制 Pod 是否可以运行有特权的容器。 设置为 false。
hostPID、hostIPC 控制容器是否可以共享主机进程命名空间。 设置为 false。
hostNetwork 控制容器是否可以使用主机网络。 设置为 false。
allowedHostPaths 将容器限制在主机文件系统的特定路径上。 使用一个 “假的” 路径名称(比如 /foo 标记为只读)。省略这个字段的结果是不对容器进行准入限制。
readOnlyRootFilesystem 需要使用一个只读的根文件系统。 可能时设置为 true。
runAsUser, runAsGroup, supplementalGroups, fsGroup 控制容器应用程序是否能以 root 权限或 root 组成员身份运行。 - 设置 runAsUserMustRunAsNonRoot。- 将 runAsGroup 设置为非零(参见附录 C 中的例子:Pod 安全策略示例)。
supplementalGroups 设置为非零(见附录 C 的例子)。将 fsGroup 设置为非零(参见附录 C 中的例子:Pod 安全策略示例)。
allowPrivilegeEscalation 限制升级到 root 权限。 设置为 false。为了有效地执行 runAsUser: MustRunAsNonRoot 设置,需要采取这一措施。
seLinux 设置容器的 SELinux 上下文。 如果环境支持 SELinux,可以考虑添加 SELinux 标签以进一步加固容器。
AppArmor 注解 设置容器所使用的 AppArmor 配置文件。 在可能的情况下,通过采用 AppArmor 来限制开发,以加固容器化的应用程序。
seccomp 注解 设置用于沙盒容器的 seccomp 配置文件。 在可能的情况下,使用 seccomp 审计配置文件来识别运行中的应用程序所需的系统调用;然后启用 seccomp 配置文件来阻止所有其他系统调用。

注意:由于以下原因,PSP 不会自动适用于整个集群:

  • 首先,在应用 PSP 之前,必须为 Kubernetes 准入控制器启用 PodSecurityPolicy 插件,这是 kube-apiserver 的一部分。
  • 第二,策略必须通过 RBAC 授权。管理员应从其集群组织内的每个角色中验证已实施的 PSP 的正确功能。

在有多个 PSP 的环境中,管理员应该谨慎行事,因为 Pod 的创建会遵守最小限制性授权策略。以下命令描述了给定命名空间的所有 Pod 安全策略,这可以帮助识别有问题的重叠策略。

kubectl get psp -n <namespace>

保护 Pod 服务账户令牌

默认情况下,Kubernetes 在创建 Pod 时自动提供一个服务账户(Service Account),并在运行时在 Pod 中挂载该账户的秘密令牌(token)。许多容器化的应用程序不需要直接访问服务账户,因为 Kubernetes 的协调工作是在后台透明进行的。如果一个应用程序被破坏了。Pod 中的账户令牌可以被网络行为者收集并用于进一步破坏集群。当应用程序不需要直接访问服务账户时,Kubernetes 管理员应确保 Pod 规范禁用正在加载的秘密令牌。这可以通过 Pod 的 YAML 规范中的 automountServiceAccountToken: false 指令来完成。

加固容器引擎

一些平台和容器引擎提供了额外的选项来加固容器化环境。一个强有力的例子是使用管理程序来提供容器隔离。管理程序依靠硬件来执行虚拟化边界,而不是操作系统。管理程序隔离比传统的容器隔离更安全。在 Windows® 操作系统上运行的容器引擎可以被配置为使用内置的 Windows 管理程序 Hyper-V®,以增强安全性。

此外,一些注重安全的容器引擎将每个容器部署在一个轻量级的管理程序中,以实现深度防御。由管理程序支持的容器可以减少容器的突破。


  1. 译者注:Pod Security Policy 已在 1.21 版本中宣布弃用,作为替代,1.22 引入了内置的 Pod Security Admission 控制器以及新的 Pod Security Standards 标准。来源 ↩︎