本文已超过一年。较旧的文章可能包含过时的内容。请检查页面中的信息自发布以来是否已变得不正确。
深入了解 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 spec 中运行时设置 runAsUser
。这是一个很好的实践,提供了一定程度的深度防御。例如,如果容器镜像使用用户 10001
构建,并且 Pod spec 未在其 Deployment
对象中添加 runAsuser
字段。在这种情况下,有一些边缘情况值得探索以提高认识
- 如果构建时定义的用户与 pod spec 中定义的用户不同,并且某些文件因此无法访问,则 Pod 可能无法启动。
- Pod 可能会无意中共享用户 ID。即使在容器逃逸到主机文件系统可能的情况下,即使用户 ID 为非零,也可能存在问题。一旦攻击者访问了主机文件系统,他们就可以访问由共享相同 UID 的其他无关 pod 拥有的所有文件资源。
- Pod 可能最终与其他 Kubernetes 未管理的节点级进程共享用户 ID,例如用于审计、漏洞扫描、遥测的节点级守护程序。威胁与上述类似,即主机文件系统访问可以使攻击者完全访问这些节点级守护程序,而无需成为节点上的 root 用户。
但是,这些情况都不会像以 root 用户身份运行的容器能够以主机上的 root 用户身份逃逸那样产生严重的影响,这可以使攻击者完全控制工作节点,进一步允许横向移动到其他工作或控制平面节点。
Kubernetes 1.22 引入了一个 alpha 功能,该功能专门通过用户命名空间将作为 root 用户运行的此类控制平面组件的影响减少到非 root 用户。
(alpha 阶段)对用户命名空间/无 root 模式的支持可用于以下容器运行时
一些发行版支持以无 root 模式运行,如下所示
不可变的容器文件系统
NSA/CISA Kubernetes 强化指南突出显示了一个经常被忽视的功能 readOnlyRootFileSystem
,在 附录 B 中提供了一个工作示例。此示例限制了运行时容器的执行和篡改。然后,可以使用 tmpfs
卷挂载将任何读/写活动限制在少数目录中。
但是,一些在运行时修改容器文件系统的应用程序(例如在容器启动时展开 WAR 或 JAR 文件)在启用此功能时可能会遇到问题。为了避免此问题,请考虑在可能的情况下尽可能减少运行时对文件系统的更改。
构建安全的容器镜像
Kubernetes 强化指南还建议在部署时运行扫描程序作为准入控制器,以防止易受攻击或配置错误的 pod 在集群中运行。从理论上讲,这听起来像是一个好方法,但在实践中实施之前,需要考虑几个注意事项
- 根据网络带宽、可用资源和选择的扫描程序,扫描镜像的漏洞可能需要不确定的时间。这可能会导致 pod 启动时间变慢或不可预测,这可能会导致应用程序在高峰负载时出现可用性峰值。
- 如果使用不正确或不完整的数据制定允许或拒绝 pod 启动的策略,可能会导致多个误报或漏报结果,如下所示
- 在容器镜像内部,
openssl
包被检测为易受攻击。但是,该应用程序是用 Golang 编写的,并使用 Gocrypto
包进行 TLS。因此,此漏洞不在代码执行路径中,因此如果保持未修复状态,其影响最小。 - 在 Debian 基础镜像的
openssl
包中检测到一个漏洞。但是,上游 Debian 社区认为这是一个 Minor 影响的漏洞,因此不会发布此漏洞的补丁修复程序。此镜像的所有者现在遇到无法修复的漏洞,并且由于预定义的策略没有考虑漏洞的修复是否可用,导致集群不允许镜像运行 - 一个 Golang 应用构建于 distroless 镜像之上,但它使用存在漏洞的 标准库的 Golang 版本编译而成。扫描器无法感知 Golang 版本,只能看到操作系统级别的软件包。因此,即使镜像包含使用存在漏洞的 Golang 构建的应用二进制文件,它仍然允许 Pod 在集群中运行。
- 在容器镜像内部,
需要明确的是,依赖漏洞扫描器绝对是一个好主意,但策略定义应该足够灵活,以允许:
- 通过标签为镜像或漏洞创建例外列表
- 根据漏洞的影响程度,使用风险评分覆盖严重性
- 在构建时应用相同的策略,以便在易受攻击的镜像部署到 Kubernetes 集群之前捕获它们
如果集群在隔离环境中运行,并且扫描器需要互联网访问来更新漏洞数据库,则可能还需要诸如离线漏洞数据库获取之类的特殊考虑。
Pod 安全策略
自 Kubernetes v1.21 起,PodSecurityPolicy API 和相关功能已被弃用,但本节中的一些指导将在未来几年内仍然适用,直到集群操作员将其集群升级到较新的 Kubernetes 版本。
Kubernetes 项目正在开发 PodSecurityPolicy 的替代方案。Kubernetes v1.22 包含一个名为 Pod Security Admission 的 alpha 功能,旨在允许强制执行 Pod 之间的最低隔离级别。
Pod Security Admission 的内置隔离级别源自 Pod Security Standards,它是指导中表 I 第 10 页中提到的所有组件的超集。
有关从 PodSecurityPolicy 迁移到 Pod Security Admission 功能的信息,请参阅 从 PodSecurityPolicy 迁移到内置的 PodSecurity Admission 控制器。
指导中提到的一项重要行为,在 Pod Security Policy 和其替代方案之间保持不变的是,强制执行其中任何一个都不会影响已经在运行的 Pod。无论是 PodSecurityPolicy 还是 Pod Security Admission,强制执行都发生在 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 服务器的证书。它限制了攻击面,并防止恶意攻击者访问集群。为 etcd 使用单独的 CA 可能是有益的,因为它默认信任根 CA 颁发的所有证书。
Kubeconfig 文件
除了直接指定令牌和证书外,.kubeconfig
还支持使用身份验证提供程序插件动态检索临时令牌。请注意 kubeconfig
文件中存在恶意 shell 代码执行的可能性。一旦攻击者获得对集群的访问权限,他们可以窃取 ssh 密钥/机密或更多信息。
机密
Kubernetes 机密是管理机密的本机方式,作为 Kubernetes API 对象。但是,在某些情况下,例如希望为所有应用程序机密提供单一的事实来源,无论它们是否在 Kubernetes 上运行,都可以将机密与 Kubernetes 松散耦合地管理,并通过 side-car 或 init-container 消耗,并尽量减少 Kubernetes Secrets API 的使用。
外部机密提供程序 和 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
- TGI 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) 为这篇博客文章提供的意见