基于角色的访问控制最佳实践
Kubernetes RBAC 是一个关键的安全控制机制,用于确保集群用户和工作负载仅拥有执行其角色所需的资源访问权限。重要的是要确保,在为集群用户设计权限时,集群管理员应了解可能发生权限升级的领域,以减少因过度访问导致安全事件的风险。
此处提出的良好实践应结合通用的RBAC 文档阅读。
一般良好实践
最小特权
理想情况下,应为用户和服务账号分配最小的 RBAC 权限。应仅使用执行其操作明确需要的权限。虽然每个集群都不尽相同,但可以应用一些通用规则:
- 在可能的情况下,在 Namespace 级别分配权限。使用 RoleBinding 而不是 ClusterRoleBinding,以仅授予用户在特定 Namespace 内的权限。
- 尽可能避免提供通配符权限,特别是对所有资源。由于 Kubernetes 是一个可扩展的系统,提供通配符访问权限不仅授予对集群中当前存在的所有对象类型的权限,还授予对未来创建的所有对象类型的权限。
- 管理员应避免使用
cluster-admin
账号,除非特别需要。为低特权账号提供模拟权限可以避免意外修改集群资源。 - 避免将用户添加到
system:masters
组。此组中的任何用户都将绕过所有 RBAC 权限检查,并且始终拥有不受限制的超级用户访问权限,这无法通过移除 RoleBinding 或 ClusterRoleBinding 来撤销。另外,如果集群正在使用授权 Webhook,此组的成员身份也会绕过该 Webhook(该组用户的请求永远不会发送到 Webhook)。
最大限度地减少特权 Token 的分发
理想情况下,不应为 Pod 分配已授予强大权限的服务账号(例如,权限升级风险下列出的任何权限)。如果工作负载需要强大权限,请考虑以下做法:
- 限制运行高权限 Pod 的 Node 数量。确保你运行的任何 DaemonSet 都是必需的,并且以最小特权运行,以限制容器逃逸的爆炸半径。
- 避免将高权限 Pod 与不受信任或暴露于公共网络的 Pod 一起运行。考虑使用污点和容忍度、节点亲和性或Pod 反亲和性来确保 Pod 不会与不受信任或信任度较低的 Pod 一起运行。特别注意那些不可信 Pod 不满足受限 Pod 安全标准的场景。
加固
Kubernetes 默认提供的访问权限可能并非每个集群都需要。审查默认提供的 RBAC 权限可以为安全加固提供机会。通常不应更改授予 system:
账号的权限,但存在一些加固集群权限的选项:
- 审查
system:unauthenticated
组的绑定,并在可能的情况下移除它们,因为这会向任何可以在网络级别访问 API Server 的人提供访问权限。 - 通过设置
automountServiceAccountToken: false
来避免服务账号 Token 的默认自动挂载。更多详细信息,请参阅使用默认服务账号 Token。为 Pod 设置此值将覆盖服务账号的设置,需要服务账号 Token 的工作负载仍然可以挂载它们。
定期审查
定期审查 Kubernetes RBAC 设置以查找冗余条目和可能的权限升级至关重要。如果攻击者能够创建与已删除用户同名的用户账号,他们可以自动继承已删除用户的所有权限,特别是分配给该用户的权限。
Kubernetes RBAC - 权限升级风险
在 Kubernetes RBAC 中,存在一些特权,如果被授予,可能会允许用户或服务账号升级他们在集群中的权限或影响集群外部的系统。
本节旨在说明集群操作员应注意的领域,以确保他们不会无意中授予超出预期的集群访问权限。
列出 Secret
一般来说,授予对 Secret 的 get
访问权限将允许用户读取其内容。同样重要的是要注意,list
和 watch
访问权限实际上也允许用户暴露 Secret 内容。例如,当返回 List 响应时(例如,通过 kubectl get secrets -A -o yaml
),响应中包含所有 Secret 的内容。
工作负载创建
在 Namespace 中创建工作负载(无论是 Pods,还是管理 Pods 的工作负载资源)的权限隐含地授予了对该 Namespace 中许多其他资源的访问权限,例如可以在 Pod 中挂载的 Secret、ConfigMap 和 PersistentVolume。此外,由于 Pod 可以以任何服务账号的身份运行,授予创建工作负载的权限也隐含地授予了该 Namespace 中任何服务账号的 API 访问级别。
可以运行特权 Pod 的用户可以利用该访问权限获取 Node 访问权限,并可能进一步提升他们的特权。如果您不完全信任某个用户或其他主体创建足够安全和隔离的 Pod 的能力,您应该强制执行 基线 (Baseline) 或 受限 (Restricted) Pod 安全标准。您可以使用Pod 安全性准入或其他(第三方)机制来实施该强制执行。
由于这些原因,Namespace 应该用于隔离需要不同信任级别或租户的资源。遵循最小特权原则并分配最少的权限仍然被认为是最佳实践,但 Namespace 内的边界应被视为较弱。
持久卷创建
如果有人或某个应用程序被允许创建任意 PersistentVolume,则该访问权限包括创建 hostPath
卷,这意味着 Pod 将获得对相关 Node 上底层主机文件系统的访问权限。授予此能力是一种安全风险。
容器如果对主机文件系统拥有不受限制的访问权限,则可以通过多种方式提升特权,包括读取其他容器的数据,以及滥用系统服务(例如 Kubelet)的凭据。
您应该仅允许创建 PersistentVolume 对象的访问权限用于:
- 工作需要此访问权限且您信任的用户(集群操作员)。
- Kubernetes 控制平面组件,该组件基于配置为自动供给的 PersistentVolumeClaims 创建 PersistentVolume。这通常由 Kubernetes 提供商或在安装 CSI 驱动程序时由操作员进行设置。
需要访问持久化存储时,可信的管理员应创建 PersistentVolume,而受限用户应使用 PersistentVolumeClaim 来访问该存储。
访问 Node 的 proxy
子资源
拥有对 Node 对象 proxy 子资源访问权限的用户具有 Kubelet API 的权限,这允许在他们拥有权限的 Node 上的每个 Pod 上执行命令。此访问权限绕过审计日志和准入控制,因此在授予此资源权限之前应谨慎行事。
Escalate 动词
通常,RBAC 系统会阻止用户创建权限高于自身所拥有的 clusterrole。此规则的例外是 escalate
动词。正如RBAC 文档中指出的,拥有此权限的用户可以有效地升级其特权。
Bind 动词
与 escalate
动词类似,授予用户此权限允许绕过 Kubernetes 内置的权限升级保护,允许用户创建绑定到他们尚未拥有的权限的角色。
Impersonate 动词
此动词允许用户模拟集群中的其他用户并获得其权限。授予此权限时应谨慎行事,以确保无法通过被模拟的账号获得过度权限。
CSR 和证书颁发
CSR API 允许对 CSR 拥有 create
权限和对 certificatesigningrequests/approval
拥有 update
权限且签发者为 kubernetes.io/kube-apiserver-client
的用户创建新的客户端证书,这些证书允许用户对集群进行认证。这些客户端证书可以拥有任意名称,包括 Kubernetes 系统组件的重复名称。这实际上将允许权限升级。
Token 请求
对 serviceaccounts/token
拥有 create
权限的用户可以创建 TokenRequest,为现有服务账号颁发 Token。
控制准入 Webhook
对 validatingwebhookconfigurations
或 mutatingwebhookconfigurations
拥有控制权的用户可以控制 Webhook,这些 Webhook 可以读取任何被准入到集群中的对象,对于 Mutating Webhook,还可以修改被准入的对象。
Namespace 修改
能够对 Namespace 对象执行 patch 操作的用户(通过一个命名空间的 RoleBinding 绑定到一个具有该访问权限的 Role)可以修改该 Namespace 上的标签。在使用 Pod 安全性准入 的集群中,这可能允许用户为 Namespace 配置比管理员预期更宽松的策略。对于使用 NetworkPolicy 的集群,用户可能设置标签,间接允许访问管理员不打算允许的服务。
Kubernetes RBAC - 拒绝服务风险
对象创建拒绝服务
拥有在集群中创建对象权限的用户可能能够创建足够大的对象,从而根据对象的大小或数量造成拒绝服务状况,如 Kubernetes 使用的 etcd 容易受到 OOM 攻击 中讨论的。如果在多租户集群中,半信任或不受信任的用户被允许有限访问系统,这可能尤其相关。
缓解此问题的一个选项是使用资源配额来限制可以创建的对象数量。
下一步
- 要了解更多关于 RBAC 的信息,请参阅RBAC 文档。