安全检查表
本清单旨在提供一个基本的指导列表,并附有指向每个主题更全面文档的链接。本清单不声称是详尽的,并将不断发展。
如何阅读和使用本文档
- 主题的顺序不反映优先级。
- 一些检查清单项在每个部分的列表下方的段落中进行了详细说明。
注意
检查清单本身不足以获得良好的安全态势。良好的安全态势需要持续的关注和改进,但检查清单可以是迈向安全准备这一永无止境旅程的第一步。本检查清单中的某些建议可能对于你的特定安全需求过于严格或过于宽松。由于 Kubernetes 安全不是“一刀切”,因此应根据每个类别的检查清单项的优点进行评估。认证和授权
-
system:masters
组在引导后不用于用户或组件认证。 - kube-controller-manager 在启用
--use-service-account-credentials
的情况下运行。 - 根证书受到保护(可以是离线 CA,也可以是具有有效访问控制的托管在线 CA)。
- 中间证书和叶证书的有效期不超过 3 年。
- 存在定期访问审查流程,且审查间隔不超过 24 个月。
- 遵循 基于角色的访问控制最佳实践 中与认证和授权相关的指导。
在引导后,用户和组件都不应以 system:masters
身份向 Kubernetes API 进行认证。类似地,应避免将整个 kube-controller-manager 作为 system:masters
运行。实际上,system:masters
仅应用作紧急访问机制,而非普通管理员用户。
网络安全
- 使用的 CNI 插件支持网络策略。
- 入站和出站网络策略应用于集群中的所有工作负载。
- 每个 Namespace 中已部署默认网络策略,选择所有 Pod,拒绝所有流量。
- 如果适用,使用服务网格来加密集群内部的所有通信。
- Kubernetes API、kubelet API 和 etcd 未在互联网上公开暴露。
- 对工作负载访问云元数据 API 的流量进行过滤。
- LoadBalancer 和 ExternalIPs 的使用受到限制。
许多 容器网络接口 (CNI) 插件 提供了限制 Pod 可与之通信的网络资源的功能。这最常通过 网络策略 来实现,网络策略提供了一个带 Namespace 的资源来定义规则。每个 Namespace 中选择所有 Pod 并阻止所有出站和入站流量的默认网络策略对于采用允许列表方法以确保不遗漏任何工作负载非常有用。
并非所有 CNI 插件都提供传输中加密。如果所选插件缺少此功能,替代解决方案是使用服务网格来提供该功能。
控制平面的 etcd 数据存储应具有限制访问的控制措施,且不应在互联网上公开暴露。此外,应使用相互 TLS (mTLS) 与其安全通信。用于此目的的证书颁发机构应专用于 etcd。
应限制从外部互联网对 Kubernetes API 服务器的访问,以防止 API 公开暴露。请注意,许多托管的 Kubernetes 分发版默认会公开暴露 API 服务器。你可以使用堡垒主机来访问服务器。
应限制对 kubelet API 的访问,不应公开暴露。当没有使用 --config
标志指定配置文件时,默认的认证和授权设置过于宽松。
如果使用云提供商托管 Kubernetes,则应限制或阻止 Pod 对云元数据 API 169.254.169.254
的访问(如果不需要),因为它可能泄露信息。
有关限制 LoadBalancer 和 ExternalIPs 使用的信息,请参阅 CVE-2020-8554: 使用 LoadBalancer 或 ExternalIPs 进行中间人攻击 以及 DenyServiceExternalIPs 准入控制器。
Pod 安全
- RBAC 对工作负载的
create
、update
、patch
、delete
权限仅在必要时授予。 - 所有 Namespace 都应用并强制执行适当的 Pod Security Standards 策略。
- 为工作负载设置内存限制,且限制值等于或低于请求值。
- 对于敏感工作负载,可以设置 CPU 限制。
- 对于支持的节点,为程序启用 Seccomp 并配置适当的系统调用 profile。
- 对于支持的节点,为程序启用 AppArmor 或 SELinux 并配置适当的 profile。
RBAC 授权至关重要,但 对于 Pod 资源(或任何管理 Pod 的资源)来说,其粒度不足以对其进行授权。唯一的粒度是针对资源本身的 API 动词,例如,针对 Pod 的 create
。如果没有额外的准入控制,创建这些资源的授权将允许直接不受限制地访问集群中可调度的节点。
的Pod 安全标准 定义了三种不同的策略:privileged(特权的)、baseline(基线的)和 restricted(受限的),这些策略限制了在 PodSpec
中设置与安全相关的字段的方式。这些标准可以通过默认启用的新Pod Security 准入或第三方准入 Webhook 在 Namespace 级别强制执行。请注意,与被替换的已移除的 PodSecurityPolicy 准入不同,Pod Security 准入可以轻松地与准入 Webhook 和外部服务结合使用。
Pod Security 准入的 restricted
策略是 Pod 安全标准 中限制最严格的策略,它可以在多种模式下运行:warn
(警告)、audit
(审计)或 enforce
(强制),以便根据安全最佳实践逐步应用最合适的安全上下文。尽管如此,对于特定用例,应单独研究 Pod 的安全上下文,以便在预定义安全标准的基础上限制 Pod 可能拥有的特权和访问权限。
有关 Pod Security 的实践教程,请参阅博客文章 Kubernetes 1.23:Pod Security 升级至 Beta。
应该设置内存和 CPU 限制,以限制 Pod 在节点上可以消耗的内存和 CPU 资源,从而防止恶意或被攻陷的工作负载发动潜在的 DoS 攻击。此类策略可以通过准入控制器强制执行。请注意,CPU 限制会限制使用,因此可能对自动扩缩功能或效率产生意外影响,例如以最佳努力使用可用 CPU 资源运行进程。
注意
内存限制高于请求值可能会使整个节点面临 OOM(内存不足)问题。启用 Seccomp
Seccomp 代表安全计算模式,自 Linux 内核版本 2.6.12 起就是其特性之一。它可用于沙箱化进程的权限,限制其从用户空间向内核进行的调用。Kubernetes 允许你将加载到节点上的 seccomp profile 自动应用于你的 Pod 和容器。
seccomp 过滤模式利用 BPF 创建特定系统调用(称为 profile)的允许或拒绝列表。
自 Kubernetes 1.27 起,你可以将 RuntimeDefault
设置为所有工作负载的默认 seccomp profile。这方面提供了一个安全教程。此外,Kubernetes Security Profiles Operator 是一个方便在集群中管理和使用 seccomp 的项目。
注意
Seccomp 仅在 Linux 节点上可用。启用 AppArmor 或 SELinux
AppArmor
AppArmor 是一个 Linux 内核安全模块,可以提供一种简单的方式来实现强制访问控制 (MAC),并通过系统日志进行更好的审计。在支持 AppArmor 的节点上会强制执行默认的 AppArmor profile,也可以配置自定义 profile。与 seccomp 类似,AppArmor 也通过 profile 配置,每个 profile 可以运行在 enforcing 模式(阻止对不允许的资源的访问)或 complain 模式(仅报告违规行为)。AppArmor profile 是按容器强制执行的,通过注解的方式,允许进程获得恰当的权限。
注意
AppArmor 仅在 Linux 节点上可用,并且在一些 Linux 发行版中已启用。SELinux
SELinux 也是一个 Linux 内核安全模块,可以提供支持访问控制安全策略(包括强制访问控制 (MAC))的机制。SELinux 标签可以通过其 securityContext
部分分配给容器或 Pod。
注意
SELinux 仅在 Linux 节点上可用,并且在一些 Linux 发行版中已启用。日志和审计
- 审计日志(如果启用)受到保护,防止通用访问。
Pod 放置
- Pod 放置应根据应用程序的敏感度层级进行。
- 敏感应用程序在节点上独立运行,或使用特定的沙箱化运行时运行。
处于不同敏感度层级的 Pod(例如,应用程序 Pod 和 Kubernetes API 服务器)应该部署到不同的节点上。节点隔离的目的是防止应用程序容器逃逸后直接访问敏感度更高的应用程序,从而轻松在集群内进行横向移动。应该强制执行这种隔离,以防止 Pod 意外地部署到同一节点上。可以通过以下特性来强制执行:
- 节点选择器
- 作为 Pod 规约的一部分的键值对,用于指定部署到哪些节点。可以使用 PodNodeSelector 准入控制器在 Namespace 和集群级别强制执行这些设置。
- PodTolerationRestriction
- 一个准入控制器,允许管理员限制 Namespace 中允许的容忍度。Namespace 中的 Pod 只能使用 Namespace 对象注解键上指定的容忍度,这些注解键提供了一组默认和允许的容忍度。
- RuntimeClass
- RuntimeClass 是一个用于选择容器运行时配置的特性。容器运行时配置用于运行 Pod 的容器,可以提供与主机的隔离(程度不同),但会带来性能开销。
Secrets
- ConfigMap 不用于存放机密数据。
- 已为 Secret API 配置静态加密。
- 如果适用,部署并提供了一种机制,用于注入存储在第三方存储中的 Secret。
- 不需要 ServiceAccount 令牌的 Pod 中不挂载 ServiceAccount 令牌。
- 使用绑定 ServiceAccount 令牌卷,而不是使用不过期令牌。
Pod 所需的 Secret 应存储在 Kubernetes Secret 中,而不是 ConfigMap 等替代方案中。存储在 etcd 中的 Secret 资源应进行静态加密。
需要 Secret 的 Pod 应通过卷自动挂载这些 Secret,最好是存储在内存中,例如使用emptyDir.medium
选项。可以使用机制将第三方存储中的 Secret 作为卷注入,例如Secrets Store CSI Driver。与授予 Pod 的 ServiceAccount RBAC 访问 Secret 的权限相比,应优先采用这种方法。这将允许将 Secret 作为环境变量或文件添加到 Pod 中。请注意,由于日志中的崩溃转储以及 Linux 中环境变量的非机密性,环境变量方式可能更容易泄露,而文件上的权限机制则相对安全。
不需要 ServiceAccount 令牌的 Pod 不应挂载 ServiceAccount 令牌。可以通过在 ServiceAccount 中或特定 Pod 中将automountServiceAccountToken
设置为 false
来配置此项,以应用于整个 Namespace 或特定 Pod。对于 Kubernetes v1.22 及更高版本,使用绑定 ServiceAccount 来获取有时效的 ServiceAccount 凭据。
镜像
- 最小化容器镜像中不必要的内容。
- 容器镜像配置为以非特权用户身份运行。
- 容器镜像的引用使用 sha256 摘要(而不是标签),或者在部署时通过准入控制验证镜像的数字签名来验证镜像的来源。
- 容器镜像在创建和部署过程中定期扫描,并修补已知的漏洞软件。
容器镜像应仅包含运行其打包程序所需的最低限度内容。最好只包含程序及其依赖项,并从尽可能小的基础镜像构建。特别是,生产环境中使用的镜像不应包含 Shell 或调试工具,因为可以使用临时调试容器进行故障排除。
通过在 Dockerfile 中使用 USER
指令来构建镜像,使其直接以非特权用户启动。安全上下文允许容器镜像使用 runAsUser
和 runAsGroup
以特定用户和组启动,即使镜像清单中未指定。但是,镜像层中的文件权限可能会导致在不修改镜像的情况下无法以新的非特权用户启动进程。
避免使用镜像标签引用镜像,特别是 latest
标签,注册表中标签背后的镜像很容易被修改。优先使用唯一的完整 sha256
摘要,它对于镜像清单来说是唯一的。此策略可以通过 ImagePolicyWebhook 强制执行。镜像签名也可以在部署时通过准入控制器自动验证,以验证其真实性和完整性。
扫描容器镜像可以防止在将容器镜像部署到集群时同时部署关键漏洞。镜像扫描应在将容器镜像部署到集群之前完成,并且通常作为 CI/CD 管道中部署过程的一部分进行。镜像扫描的目的是获取容器镜像中可能存在的漏洞及其预防措施的信息,例如通用漏洞评分系统 (CVSS) 分数。如果镜像扫描结果与管道合规规则结合使用,则只有正确修补的容器镜像才会进入生产环境。
准入控制器
- 启用了一组合适的准入控制器。
- 由 Pod Security Admission 或/和 Webhook 准入控制器强制执行 Pod 安全策略。
- 准入链插件和 Webhook 已安全配置。
准入控制器可以帮助提高集群的安全性。但是,它们本身也可能带来风险,因为它们扩展了 API 服务器,因此应妥善加以保护。
以下列表介绍了一些可以考虑用于增强集群和应用程序安全态势的准入控制器。其中包含本文档其他部分可能引用的控制器。
第一组准入控制器包含默认启用的插件,除非你知道自己在做什么,否则建议保持其启用状态。
CertificateApproval
- 执行额外的授权检查,以确保批准用户有权限批准证书请求。
CertificateSigning
- 执行额外的授权检查,以确保签名用户有权限签署证书请求。
CertificateSubjectRestriction
- 拒绝任何指定 'group'(或 'organization attribute')为
system:masters
的证书请求。 LimitRanger
- 强制执行 LimitRange API 约束。
MutatingAdmissionWebhook
- 允许通过 Webhook 使用自定义控制器,这些控制器可以修改它们审查的请求。
PodSecurity
- 替换 Pod Security Policy,限制已部署 Pod 的安全上下文。
ResourceQuota
- 强制执行资源配额以防止资源过度使用。
ValidatingAdmissionWebhook
- 允许通过 Webhook 使用自定义控制器,这些控制器不会修改它们审查的请求。
第二组包含未默认启用但处于通用状态的插件,建议使用这些插件来提高你的安全态势。
DenyServiceExternalIPs
- 拒绝所有新增的
Service.spec.externalIPs
字段的使用。这是CVE-2020-8554: 使用 LoadBalancer 或 ExternalIPs 进行中间人攻击 的缓解措施。 NodeRestriction
- 限制 kubelet 的权限,仅允许修改其拥有的 Pod API 资源或代表自身的 Node API 资源。它还阻止 kubelet 使用
node-restriction.kubernetes.io/
注解,该注解可被具有 kubelet 凭据的攻击者用来影响 Pod 到受控节点的放置。
第三组包含未默认启用但可在特定用例中考虑使用的插件。
AlwaysPullImages
- 强制使用带标签镜像的最新版本,并确保部署者有权限使用该镜像。
ImagePolicyWebhook
- 允许通过 Webhook 对镜像强制执行额外的控制。
接下来
- 通过创建 Pod 进行权限提升 警告你有关特定访问控制风险;请检查你如何应对此威胁。
- 如果你使用 Kubernetes RBAC,请阅读RBAC 最佳实践 以获取有关授权的更多信息。
- 保护集群安全,获取关于如何保护集群免遭意外或恶意访问的信息。
- 集群多租户指南,获取关于多租户配置选项建议和最佳实践的信息。
- 博客文章“深入了解 NSA/CISA Kubernetes 加固指南”,获取加固 Kubernetes 集群的补充资源。