GKE RBAC 的最佳做法

使用集合让一切井井有条 根据您的偏好保存内容并对其进行分类。

本页面介绍了规划基于角色的访问权限控制 (RBAC) 政策的最佳做法。如需了解如何在 Google Kubernetes Engine (GKE) 中实现 RBAC,请参阅配置基于角色的访问权限控制

RBAC 是 Kubernetes 中的一个核心安全功能,可让您创建精细的权限,以管理用户和工作负载可以对集群中的资源执行的操作。作为平台管理员,您可以创建 RBAC 角色并将这些角色绑定到主体,这些主体是经过身份验证的用户,例如服务帐号或群组。

准备工作

确保熟悉以下概念:

如需查看本指南的核对清单,请参阅核对清单摘要

RBAC 的工作原理

RBAC 支持以下类型的角色和绑定:

  • ClusterRole:一组可以应用于任何命名空间或整个集群的权限。
  • 角色:一组仅限于单个命名空间的权限。
  • ClusterRoleBinding:将 ClusterRole 绑定到集群中所有命名空间的用户或群组。
  • RoleBinding:将 RoleClusterRole 绑定到特定命名空间中的用户或群组。

您可以在 RoleClusterRole 中将权限定义为 rules。角色中的每个 rules 字段都包含 API 组、该 API 组中的 API 资源以及允许对这些资源使用的动词(操作)。(可选)您可以使用 resourceNames 字段将动词的范围限定为已命名的 API 资源实例。如需查看示例,请参阅仅限访问特定资源实例

定义角色后,使用 RoleBindingClusterRoleBinding 将该角色绑定到主体。根据您要在单个命名空间中还是在多个命名空间中授予权限,选择绑定类型。

RBAC 角色设计

遵循最小权限原则

在 RBAC 角色中分配权限时,请遵循最小权限原则并授予执行任务所需的最低权限。使用最小权限原则可以降低集群被盗用时提升权限的可能性,并降低过度访问导致安全事件的可能性。

设计角色时,请仔细考虑常见的提升权限风险,例如 escalatebind 动词、PersistentVolume 的 create 访问权限或证书签名请求的 create 访问权限。如需查看风险列表,请参阅 Kubernetes RBAC - 提升权限风险

避免使用默认角色和群组

Kubernetes 会自动创建一组 ClusterRoleClusterRoleBinding 对象,可用于 API 发现和启用代管式组件功能。这些默认角色授予的权限可能比较广泛。例如,cluster-admin ClusterRole 可向某个主体授予对任何资源执行任何操作的权限。如果您使用 ClusterRoleBindingcluster-admin ClusterRole 绑定到用户或服务帐号,则该主体在集群中的权限不受限制。

在将默认角色绑定到主体之前,请根据您的用例评估该角色授予的权限。确保您了解相关风险。如需查看 Kubernetes 创建的默认角色和绑定的完整列表,请参阅默认角色和角色绑定

Kubernetes 还会创建绑定到默认角色的默认群组。例如,cluster-admin ClusterRole 绑定到 system:masters 组,以便为代管组件提供对 API 服务器的完整访问权限。避免将自己的主体添加到 system:masters

如果可能,请使用以下准则:

  • 请勿将您自己的主体添加到 system:masters 组。
  • 请勿将 system:unauthenticated 群组绑定到任何 RBAC 角色。
  • 请勿将 cluster-admin ClusterRole 绑定到您自己的主体。
  • 在绑定主体之前评估其他默认角色授予的权限。
  • 在修改这些群组的成员之前,请评估绑定到默认群组的角色。

将权限限制到命名空间级别

根据工作负载或用户的需求,使用如下绑定和角色:

  • 要授予对一个命名空间中的资源的访问权限,请使用 RoleRoleBinding
  • 要授予对多个命名空间中资源的访问权限,请在每个命名空间中使用 ClusterRoleRoleBinding
  • 要授予对每个命名空间中资源的访问权限,请使用 ClusterRoleClusterRoleBinding

在尽可能少的命名空间中授予权限。

请勿使用通配符

* 字符是一个适用于所有内容的通配符。避免在规则中使用通配符。在 RBAC 规则中明确指定 API 组、资源和动词。例如,在 verbs 字段中指定 * 将授予 getlistwatchpatchupdatedeletecollectiondelete 权限。下表举例说明了如何避免在规则中使用通配符:

推荐 不推荐

- rules:
    apiGroups: ["apps","extensions"]
    resources: ["deployments"]
    verbs: ["get","list","watch"]

专门向 appsextensions API 组授予 getlistwatch 动词。


- rules:
    apiGroups: ["*"]
    resources: ["deployments"]
    verbs: ["get","list","watch"]

将动词授予任何 API 组中的 deployments


- rules:
    apiGroups: ["apps", "extensions"]
    resources: ["deployments"]
    verbs: ["get", "list", "watch"]

仅将 getlistwatch 动词授予 appsextensions API 组中的部署。


- rules:
    apiGroups: ["apps", "extensions"]
    resources: ["deployments"]
    verbs: ["*"]

授予所有动词,包括 patchdelete

使用单独规则对特定资源授予最小访问权限

规划规则时,请尝试以下简要步骤,在每个角色中采用更高效的最小权限规则设计:

  1. 为主体需要访问的每项资源上的动词草拟单独的 RBAC 规则。
  2. 草拟规则后,分析规则,以检查多条规则是否具有相同的 verbs 列表。将这些规则合并为一条规则。
  3. 请将其余的所有规则彼此分散。

这种方法可实现更有条理的规则设计,将对多个资源授予相同动词的规则组合起来,将为资源授予不同动词的规则彼此分散。

例如,如果您的工作负载需要获取 deployments 资源的权限,但需要 daemonsets 资源的 listwatch 权限,则您应该在创建角色是使用单独规则。当您将 RBAC 角色绑定到工作负载时,该角色将无法对 deployments 使用 watch

再举一例,如果您的工作负载需要 pods 资源和 daemonsets 资源的 getwatch 权限,您可以将它们组合成一条规则,因为工作负载需要在这两个资源上使用相同的动词。

在下表中,这两种规则设计均有效,但拆分规则会根据需要更精细地限制资源访问权限:

推荐 不推荐

- rules:
    apiGroups: ["apps"]
    resources: ["deployments"]
    verbs: ["get"]
- rules:
    apiGroups: ["apps"]
    resources: ["daemonsets"]
    verbs: ["list", "watch"]

为 Deployment 授予 get 访问权限,为 DaemonSet 授予 watchlist 访问权限。 主体无法列出 Deployment。


- rules:
    apiGroups: ["apps"]
    resources: ["deployments", "daemonsets"]
    verbs: ["get","list","watch"]

将动词同时授予 Deployment 和 DaemonSet。可能对 deployments 对象不需要 list 访问权限的主体仍会获得该访问权限。


- rules:
    apiGroups: ["apps"]
    resources: ["daemonsets", "deployments"]
    verbs: ["list", "watch"]

组合两条规则,因为主体需要对 daemonsetsdeployments 资源使用相同的动词。


- rules:
    apiGroups: ["apps"]
    resources: ["daemonsets"]
    verbs: ["list", "watch"]
- rules:
    apiGroups: ["apps"]
    resources: ["deployments"]
    verbs: ["list", "watch"]

这些拆分规则的结果将与组合规则相同,但会导致角色清单产生不必要的杂乱

仅限访问特定资源实例

通过 RBAC,您可以使用规则中的 resourceNames 字段仅限访问资源的特定命名实例。例如,如果您正在编写仅需要 update seccomp-high ConfigMap 的 RBAC 角色,则可以使用 resourceNames 仅指定该 ConfigMap。尽可能使用 resourceNames

推荐 不推荐

- rules:
    apiGroups: [""]
    resources: ["configmaps"]
    resourceNames: ["seccomp-high"]
    verbs: ["update"]

仅限主体更新 seccomp-high ConfigMap。主体无法更新命名空间中的任何其他 ConfigMap。


- rules:
    apiGroups: [""]
    resources: ["configmaps"]
    verbs: ["update"]

主体可以更新命名空间中的 seccomp-high ConfigMap 以及任何其他 ConfigMap。


- rules:
    apiGroups: [""]
    resources: ["configmaps"]
    verbs: ["list"]
- rules:
    apiGroups: [""]
    resources: ["configmaps"]
    resourceNames: ["seccomp-high"]
    verbs: ["update"]

向命名空间中所有 ConfigMap 授予 list 访问权限,包括 seccomp-high。将 update 访问权限仅限于 seccomp-high ConfigMap。这些规则是拆分的,因为您无法为命名资源授予 list


- rules:
    apiGroups: [""]
    resources: ["configmaps"]
    verbs: ["update", "list"]

为所有 ConfigMap 授予 update 访问权限以及 list 访问权限。

不允许服务帐号修改 RBAC 资源

请勿将对 rbac.authorization.k8s.io API 组具有 bindescalatecreateupdatepatch 权限的 RoleClusterRole 资源绑定到任何命名空间中的服务帐号。特别是 escalatebind 可让攻击者绕过 RBAC 中内置的升级预防机制

Kubernetes 服务帐号

为每个工作负载创建 Kubernetes 服务帐号

为每个工作负载创建单独的 Kubernetes 服务帐号。将最小权限 RoleClusterRole 绑定到该服务帐号。

请勿使用默认服务帐号

Kubernetes 会在每个命名空间中创建一个名为 default 的服务帐号。default 服务帐号会自动分配给未在清单中明确指定服务帐号的 Pod。避免将 RoleClusterRole 绑定到 default 服务帐号。Kubernetes 可能会将 default 服务帐号分配给不需要在这些角色中授予的访问权限的 Pod。

请勿自动装载服务帐号令牌

Pod 规范中的 automountServiceAccountToken 字段指示 Kubernetes 将 Kubernetes 服务帐号的凭据注入 Pod。Pod 可以使用此令牌向 Kubernetes API 服务器发出经过身份验证的请求。此字段的默认值为 true

在所有 GKE 版本中,如果您的 Pod 不需要与 API 服务器通信,请在 Pod 规范中设置 automountServiceAccountToken=false

首选临时令牌而不是基于 Secret 的令牌

创建和使用服务帐号令牌时,请避免使用 Kubernetes Secret 存储令牌。基于 Secret 的服务帐号令牌是不会过期且不会自动轮替的旧版凭据。如果您需要服务帐号的凭据,请使用 TokenRequest API 获取可自动轮替的短期令牌。

持续审核 RBAC 权限

定期审核 RBAC 角色和访问权限,以确定潜在的上报路径和冗余规则。例如,假设您没有删除将具有特殊权限的 Role 绑定到已删除用户的 RoleBinding。如果攻击者在该命名空间中创建一个与已删除用户同名的用户帐号,则他们将绑定到该 Role 并继承相同的访问权限。定期审核可将此风险降至最低。

核对清单摘要

后续步骤