本文发表于一年多前。旧文章可能包含过时内容。请检查页面中的信息自发布以来是否已变得不正确。
深入了解 NSA/CISA Kubernetes 强化指南
免责声明
本文列出的开源工具仅作为示例,绝不代表 Kubernetes 社区或作者的直接推荐。背景
美国国家安全局 (NSA) 和网络安全和基础设施安全局 (CISA) 于 2021 年 8 月 3 日发布了 Kubernetes 安全强化指南。该指南详细阐述了 Kubernetes 环境面临的威胁,并提供了安全的配置指南以最大程度地降低风险。
本博客的以下部分与 NSA/CISA 指南中的部分相关联。任何缺失的部分均因无法为现有内容添加任何新内容而被跳过。
注意:本博客文章不能替代阅读指南。建议在继续之前阅读已发布的指南,因为以下内容是补充性的。
更新,2023年11月
国家安全局 (NSA) 和网络安全与基础设施安全局 (CISA) 于 2021 年 8 月发布了 Kubernetes 强化指南的 1.0 版,并根据行业反馈于 2022 年 3 月对其进行了更新(1.1 版)。
最新版本的 Kubernetes 强化指南于 2022 年 8 月发布,其中包含更正和澄清。1.2 版概述了针对强化 Kubernetes 集群的许多建议。
引言与威胁模型
请注意,NSA/CISA 认为重要的威胁,或本指南的预期受众,可能与其他 Kubernetes 企业用户认为重要的威胁有所不同。本节对于关注数据、资源盗窃和服务不可用的组织仍然有用。
该指南强调了以下三种泄露来源:
- 供应链风险
- 恶意威胁行为者
- 内部威胁(管理员、用户或云服务提供商)
威胁模型试图退一步审视不仅存在于 Kubernetes 集群边界内的威胁,还包括 Kubernetes 不管理的底层基础设施和周边工作负载。
例如,当集群外部的工作负载共享同一物理网络时,它就可以访问 kubelet 和控制平面组件:etcd、控制器管理器、调度器和 API 服务器。因此,指南建议进行网络级别隔离,将 Kubernetes 集群与其他不需要连接到 Kubernetes 控制平面节点的工作负载分开。具体来说,调度器、控制器管理器、etcd 只需要对 API 服务器可访问。从集群外部与 Kubernetes 的任何交互都可以通过提供 API 服务器端口的访问权限来完成。
每个组件的端口和协议列表在 Kubernetes 文档中的端口和协议中定义。
特别提示:kube-scheduler 和 kube-controller-manager 使用的端口与指南中提到的端口不同
CNCF 云原生安全白皮书 + 地图中的威胁建模部分提供了从云原生角度进行 Kubernetes 威胁建模的另一种视角。
Kubernetes Pod 安全
Kubernetes 默认不保证同一集群中运行的 Pod 之间严格的工作负载隔离。但是,该指南提供了几种技术来增强现有隔离并减少在发生泄露时的攻击面。
“非 root”容器和“无 root”容器引擎
有几个与最小权限基本安全原则相关的最佳实践值得重新审视,即只提供所需的权限;不多,不少。
该指南建议在构建时设置非 root 用户,而不是依赖在 Pod 规范中运行时设置 `runAsUser`。这是一个很好的实践,并提供了一定程度的纵深防御。例如,如果容器镜像使用用户 `10001` 构建,并且 Pod 规范在其 `Deployment` 对象中缺少添加 `runAsuser` 字段。在这种情况下,有一些值得探索的边缘情况需要注意:
- 如果构建时定义的用户与 Pod 规范中定义的用户不同,并且某些文件因此无法访问,Pod 可能会启动失败。
- Pod 可能会无意中共享用户 ID。即使在容器逃逸到主机文件系统可能发生的情况下,用户 ID 非零也可能出现问题。一旦攻击者获得主机文件系统访问权限,他们就可以访问由共享相同 UID 的其他不相关 Pod 拥有的所有文件资源。
- Pod 可能会与其他不受 Kubernetes 管理的节点级进程(例如用于审计、漏洞扫描、遥测的节点级守护进程)共享用户 ID。其威胁与上述情况类似,攻击者可以通过主机文件系统访问获得对这些节点级守护进程的完全访问权限,而无需在节点上拥有 root 权限。
然而,上述任何情况的影响都不会像以 root 用户身份运行的容器能够逃逸到主机上并获得 root 权限那样严重,因为这可能使攻击者完全控制工作节点,从而进一步横向移动到其他工作节点或控制平面节点。
Kubernetes 1.22 引入了一个alpha 功能,通过用户命名空间专门将此类以 root 用户身份运行的控制平面组件的影响降低到非 root 用户。
在以下容器运行时中,对用户命名空间/无根模式的alpha 阶段支持可用:
一些发行版支持以无根模式运行,例如以下:
不可变容器文件系统
NSA/CISA Kubernetes 安全强化指南强调了一个经常被忽视的功能 `readOnlyRootFileSystem`,并在附录 B 中提供了一个工作示例。此示例限制了容器在运行时的执行和篡改。任何读/写活动都可以通过使用 `tmpfs` 卷挂载来限制到少数几个目录。
但是,一些在运行时修改容器文件系统的应用程序(例如在容器启动时解压 WAR 或 JAR 文件)在启用此功能时可能会遇到问题。为了避免此问题,请考虑在可能的情况下,在运行时对文件系统进行最小的更改。
构建安全的容器镜像
Kubernetes 强化指南还建议在部署时以准入控制器的形式运行扫描器,以防止易受攻击或配置错误的 Pod 在集群中运行。理论上,这听起来像是一个好方法,但在实际实施之前需要考虑几个注意事项:
- 根据网络带宽、可用资源和所选扫描器,扫描镜像漏洞所需的时间可能不确定。这可能导致 Pod 启动时间变慢或不可预测,从而在应用程序达到高峰负载时导致不可用性峰值。
- 如果用于允许或拒绝 Pod 启动的策略是使用不正确或不完整的数据制定的,可能会导致以下几种误报或漏报结果:
- 在容器镜像中,`openssl` 包被检测为存在漏洞。但是,应用程序是用 Golang 编写的,并使用 Go 的 `crypto` 包进行 TLS。因此,此漏洞不在代码执行路径中,因此即使未修复,影响也最小。
- Debian 基础镜像中的 `openssl` 包被检测到存在漏洞。然而,上游 Debian 社区认为这是一个影响较小的漏洞,因此没有发布此漏洞的补丁。该镜像的所有者现在陷入了一个无法修复的漏洞和一个不允许镜像运行的集群,因为预定义的策略没有考虑漏洞的修复是否可用。
- 一个 Golang 应用程序构建在 distroless 镜像之上,但它使用一个存在漏洞的 标准库 的 Golang 版本进行编译。扫描器无法查看 Golang 版本,只能查看操作系统级别的包。因此,即使镜像包含一个基于存在漏洞的 Golang 构建的应用程序二进制文件,它也允许 Pod 在集群中运行。
需要明确的是,依赖漏洞扫描器绝对是个好主意,但策略定义应足够灵活以允许:
- 通过标签创建镜像或漏洞的例外列表
- 根据漏洞的影响,用风险评分覆盖严重性
- 在构建时应用相同的策略,以便在易受攻击的镜像部署到 Kubernetes 集群之前发现它们的可修复漏洞
如果集群在气隙环境中运行且扫描器需要互联网访问才能更新漏洞数据库,则可能还需要考虑特殊因素,例如离线漏洞数据库获取。
Pod 安全策略
自 Kubernetes v1.21 起,PodSecurityPolicy API 及相关功能已被弃用,但本节中的某些指南在未来几年内仍将适用,直到集群操作员将其集群升级到较新的 Kubernetes 版本。
Kubernetes 项目正在开发 PodSecurityPolicy 的替代方案。Kubernetes v1.22 包含一个名为 Pod 安全准入 的 Alpha 功能,旨在强制 Pod 之间达到最低限度的隔离。
Pod 安全准入的内置隔离级别源自 Pod 安全标准,该标准是指南 第 10 页 表 I 中提及的所有组件的超集。
关于从 PodSecurityPolicy 迁移到 Pod 安全准入功能的信息可在从 PodSecurityPolicy 迁移到内置 PodSecurity 准入控制器中找到。
指南中提到的一个重要行为,Pod 安全策略及其替代方案之间保持不变的是,强制执行其中任何一个都不会影响已经运行的 Pod。PodSecurityPolicy 和 Pod 安全准入的强制执行都发生在 Pod 创建阶段。
强化容器引擎
有些容器工作负载信任度较低,但可能需要在同一个集群中运行。在这些情况下,将它们运行在专用节点上,这些节点包含提供更严格 Pod 隔离边界的强化容器运行时,可以作为一种有用的安全控制。
Kubernetes 支持一个名为 RuntimeClass 的 API,该 API 在 Kubernetes v1.20 中已达到稳定/通用可用 (GA) 阶段(因此默认启用)。RuntimeClass 允许你确保需要强隔离的 Pod 被调度到能够提供这种隔离的节点上。
一些可以与 RuntimeClass 结合使用的第三方项目是:
正如本文和指南中讨论的那样,Kubernetes 内部及周边存在许多功能和工具,可以增强 Pod 之间的隔离边界。根据相关的威胁和风险态势,您应该选择其中的一部分,而不是试图应用所有建议。话虽如此,集群级隔离,即在专用集群中运行工作负载,仍然是最严格的工作负载隔离机制,尽管本文和指南中提到了改进。
网络隔离与强化
Kubernetes 网络可能很复杂,本节重点介绍如何保护和强化相关配置。指南将以下内容确定为关键要点:
- 使用 NetworkPolicies 创建资源间的隔离,
- 保护控制平面
- 加密流量和敏感数据
网络策略
网络策略可以在网络插件的帮助下创建。为了方便用户创建和可视化,Cilium 支持一个Web GUI 工具。该 Web GUI 允许您创建 Kubernetes NetworkPolicies(一个通用 API,但需要兼容的 CNI 插件),和/或 Cilium 网络策略(CiliumClusterwideNetworkPolicy 和 CiliumNetworkPolicy,它们仅适用于使用 Cilium CNI 插件的集群)。您可以使用这些 API 来限制 Pod 之间的网络流量,从而最大程度地减少攻击向量。
另一个值得探讨的场景是外部 IP 的使用。某些服务在配置不当的情况下会创建随机的外部 IP。攻击者可以利用这种配置错误,轻松拦截流量。此漏洞已在 CVE-2020-8554 中报告。使用 externalip-webhook 可以通过阻止服务使用随机外部 IP 来缓解此漏洞。externalip-webhook 只允许创建不需要外部 IP 或其外部 IP 在管理员指定范围内的服务。
CVE-2020-8554 - 所有版本的 Kubernetes API 服务器都允许攻击者在能够创建 ClusterIP 服务并设置 `spec.externalIPs` 字段的情况下,拦截流向该 IP 地址的流量。此外,攻击者如果能够修补 LoadBalancer 服务的 `status`(这被认为是一个特权操作,通常不应授予用户),则可以将 `status.loadBalancer.ingress.ip` 设置为类似的效果。
资源策略
除了配置 ResourceQuotas 和限制外,还应考虑限制给定 Pod 可以使用的进程 ID (PID) 数量,并为节点级使用保留一些 PID,以避免资源耗尽。有关应用这些限制的更多详细信息,请参见进程 ID 限制和保留。
控制平面强化
在下一节中,指南介绍了控制平面强化。值得注意的是,从 Kubernetes 1.20 开始,API 服务器中的不安全端口已被移除。
Etcd
通常,etcd 服务器应配置为仅信任分配给 API 服务器的证书。这限制了攻击面,并防止恶意攻击者获取对集群的访问权限。使用单独的 CA 对 etcd 可能会有益,因为它默认信任根 CA 颁发的所有证书。
Kubeconfig 文件
除了直接指定令牌和证书外,`kubeconfig` 还支持使用身份验证提供程序插件动态检索临时令牌。请注意 `kubeconfig` 文件中恶意 shell 代码执行的可能性。一旦攻击者获得集群访问权限,他们就可以窃取 ssh 密钥/秘密或更多信息。
Secrets
Kubernetes Secrets 是将秘密作为 Kubernetes API 对象进行管理的本机方式。但是,在某些情况下,例如希望为所有应用程序秘密拥有单一真相来源,无论它们是否在 Kubernetes 上运行,秘密都可以与 Kubernetes 松散耦合地进行管理,并通过 Sidecar 或 Init 容器(最小化使用 Kubernetes Secrets API)供 Pod 使用。
外部秘密提供程序和 csi-secrets-store 是 Kubernetes Secrets 的一些替代方案。
日志审计
NSA/CISA 指南强调基于日志进行监控和警报。关键点包括主机级别、应用程序级别和云上的日志记录。在生产环境中运行 Kubernetes 时,了解每个日志记录层的责任人和负责人至关重要。
Kubernetes API 审计
一个值得更多关注的领域是应该精确地触发哪些警报或记录哪些信息。该文档在附录 L:审计策略中概述了一个示例策略,该策略记录所有 RequestResponse,包括元数据以及请求/响应正文。虽然对于演示很有用,但对于生产环境可能不切实际。
每个组织都需要评估自己的威胁模型,并制定一个审计策略,以补充或帮助解决事件响应。思考攻击者将如何攻击您的组织,以及哪些审计线索可以识别出来。请参阅官方审计日志文档中更高级的审计日志调优选项。调整审计日志以仅包含符合您的威胁模型的事件至关重要。一个以 `metadata` 级别记录所有内容的最小审计策略也可以是一个很好的起点。
审计日志配置也可以按照这些说明使用 Kind 进行测试。
流式日志和审计
日志记录对于威胁和异常检测至关重要。正如文档所概述的,最佳实践是尽可能接近实时地扫描和警报日志,并在发生泄露时保护日志不被篡改。重要的是要反思日志记录的各个级别并识别关键区域,例如 API 端点。
Kubernetes API 审计日志可以流式传输到 webhook,在附录 N:Webhook 配置中有一个示例。使用 webhook 可以是一种在集群外存储日志和/或集中所有审计日志的方法。一旦日志集中管理,就可以根据关键事件启用警报。还要确保您了解正常活动的基本情况。
警报识别
虽然指南强调了通知的重要性,但并没有一个通用的事件列表来触发警报。警报要求根据您自己的需求和威胁模型而异。示例包括以下事件:
- Pod 的 `securityContext` 更改
- 准入控制器配置更新
- 访问某些文件/URL
其他日志资源
- Seccomp 安全配置文件与您:实用指南 - Duffie Cooley
- 本周 Kubernetes 119:Gatekeeper 和 OPA
- 滥用 Kubernetes 审计策略的缺失
- 使用新的 v1.22 Alpha 特性为所有工作负载启用 seccomp
- 本周云原生:审计 / Pod 安全
升级和应用程序安全实践
Kubernetes 每年发布三次,因此升级相关的繁重工作是运行生产集群的人们面临的常见问题。除此之外,操作员必须定期升级底层节点的操作系统和运行的应用程序。这是确保持续支持并减少错误或漏洞可能性的最佳实践。
Kubernetes 支持三个最新的稳定版本。尽管每个 Kubernetes 版本在发布之前都经过了大量的测试,但一些团队并不习惯在一段时间过去之前运行最新的稳定版本。无论您运行哪个版本,请确保补丁升级频繁或自动进行。更多信息可以在版本倾斜策略页面中找到。
在考虑如何管理节点操作系统升级时,请考虑使用短暂节点。能够销毁和添加节点可以让您的团队更快地响应节点问题。此外,具有能够容忍节点不稳定性的部署(以及鼓励频繁部署的文化)可以使集群升级更容易。
此外,值得重申的是,指南建议对各种系统组件进行定期漏洞扫描和渗透测试,以主动发现不安全的配置和漏洞。
查找发布和安全信息
要查找最新的 Kubernetes 支持版本,请参阅 https://k8s.io/releases,其中包括次要版本。及时更新次要版本补丁是一个好习惯。
如果您正在运行托管的 Kubernetes 产品,请查阅其发布文档并找到其各种安全渠道。
订阅 Kubernetes Announce 邮件列表。Kubernetes Announce 邮件列表可以通过诸如 "安全公告" 等术语进行搜索。只要您知道要警报的关键字,就可以设置警报和电子邮件通知。
结论
总而言之,很高兴看到安全从业者公开分享如此详细的指南。这份指南进一步强调了 Kubernetes 正在走向主流,以及如何保护 Kubernetes 集群和运行在 Kubernetes 上的应用程序容器仍然需要从业者的关注和重视。在指南发布仅几周后,一个开源工具 kubescape 就可用于根据此指南验证集群。
此工具可以成为检查集群当前状态的绝佳起点,之后您可以使用本博客文章和指南中的信息来评估可以在哪些方面进行改进。
最后,值得重申的是,并非所有指南中的控制措施都适用于所有从业者。了解哪些控制措施重要的最佳方法是依赖于您自己的 Kubernetes 环境的威胁模型。
特别感谢 Rory McCune (@raesene) 对本博客文章的贡献。