基于角色的访问权限控制

本页面简要介绍了 Kubernetes 提供的 RBAC(基于角色的访问权限控制)系统,以及如何在 Google Kubernetes Engine (GKE) 中使用 Kubernetes RBAC。

概览

Kubernetes 内置了一项基于角色的访问权限控制 (RBAC) 机制,可让您配置一组特定的细化权限,以定义某一特定 Google Cloud 用户或用户组如何与集群(或集群的特定命名空间)中的任何 Kubernetes 对象互动。

默认情况下,Kubernetes RBAC 处于启用状态。

准备工作

在开始之前,请确保您已执行以下任务:

使用以下任一方法设定默认的 gcloud 设置:

  • 使用 gcloud init(如果您想要在系统引导下完成默认设置)。
  • 使用 gcloud config(如果您想单独设置项目 ID、区域和地区)。

使用 gcloud init

如果您收到 One of [--zone, --region] must be supplied: Please specify location 错误,请完成本部分。

  1. 运行 gcloud init 并按照说明操作:

    gcloud init

    如果您要在远程服务器上使用 SSH,请使用 --console-only 标志来防止命令启动浏览器:

    gcloud init --console-only
  2. 按照说明授权 gcloud 使用您的 Google Cloud 帐号。
  3. 创建新配置或选择现有配置。
  4. 选择 Google Cloud 项目。
  5. 选择默认的 Compute Engine 区域。

使用 gcloud config

  • 设置默认项目 ID
    gcloud config set project project-id
  • 如果您使用的是区域级集群,请设置默认计算区域
    gcloud config set compute/zone compute-zone
  • 如果您使用的是地区级集群,请设置默认计算地区
    gcloud config set compute/region compute-region
  • gcloud 更新到最新版本:
    gcloud components update

与 Identity and Access Management 互动

您可以使用 Identity and Access Management (IAM) Kubernetes RBAC 来控制对 GKE 集群的访问权限:

  • IAM 并非特定于 Kubernetes;它为多种 Google Cloud 产品提供身份管理,并且主要在 Google Cloud 项目级层运行。

  • Kubernetes RBAC 是 Kubernetes 的核心组成部分,可让您针对集群内的任何对象或对象类型创建和授予角色(一组权限)。

在 GKE 中,IAM 和 Kubernetes RBAC 集成在一起,您可以通过任一工具向用户授权,使其有足够的权限执行操作。这对于 GKE 集群的引导过程至关重要,因为默认情况下,Google Cloud 用户不具有任何 Kubernetes RBAC RoleBindings。

如需使用 Google Cloud 帐号向用户授权,您必须首先将客户端正确配置为使用这些帐号进行身份验证。例如,如果您使用的是 kubectl,则必须先配置 kubectl 命令以向 Google Cloud 进行身份验证,然后才能运行任何需要授权的命令。

虽然在几乎所有情况下都可以使用 Kubernetes RBAC 取代 IAM,但 GKE 用户至少需要集群所在项目中的 container.clusters.get IAM 权限。container.clusterViewer 角色以及其他具有更高权限的角色包含此权限。用户必须拥有 container.clusters.get 权限才能向项目中的集群进行身份验证,但并未获得授权在这些集群内执行任何操作。随后,授权可由 IAM 或 Kubernetes RBAC 提供。

在 v1.11.x 及更早版本的 GKE 集群上使用 Kubernetes RBAC 所需满足的前提条件

在使用 GKE v1.11.x 及更早版本的 GKE 集群中,存在一项限制,即 IAM 无法授予创建 Kubernetes RBAC Role 或 ClusterRole 的权限。但是,您可以使用 Kubernetes Engine Admin IAM 角色向用户授予为任何用户(包括他们自己)创建 Kubernetes RBAC RoleBinding 或 ClusterRoleBinding 的权限,这些对象可用于将 Google Cloud 用户绑定到预定义 RBAC 角色

具体地说,cluster-admin 预定义 RBAC 角色可向用户授予集群的所有权限。因此,要引导用户以允许他们创建 RBAC Role 和 ClusterRole,请使用以下命令,将 user-account 替换为目标用户的 Google Cloud 登录电子邮件地址。

kubectl create clusterrolebinding cluster-admin-binding \
  --clusterrole cluster-admin \
  --user user-account

Google GKE 群组

以前,您只能向 Google Cloud 用户帐号或 IAM 服务帐号授予角色。现在,您可以通过 Google GKE 群组(Beta 版)向 G Suite Google 群组的成员授予角色。得益于这项机制,用户和群组本身将可由 G Suite 管理员完全在 Kubernetes 或 Cloud Console 外部进行维护,因此您的集群管理员就不需要用户的详细信息。另外,此功能还有一项优势,那就是它集成了现有的用户帐号管理做法,例如,您可以撤消已离开组织的人员的访问权限。

如需使用此功能,请完成以下任务:

要求

使用 Google GKE 群组有以下要求:

  • 您必须订阅 G Suite 或 Cloud Identity。

配置 Google 群组以结合 RBAC 进行使用

如需了解如何将集群配置为使用此功能,以及在 Kubernetes RBAC 中引用 G Suite Google 群组的语法,请参阅本主题的后续内容。首先,您需要按照以下步骤设置 Google 群组:

  1. 在您的网域中创建一个名为 gke-security-groups@yourdomain.com 的 G Suite Google 群组。该群组的名称必须与 gke-security-groups 完全一致。确保 gke-security-groups 群组对“群组成员”拥有“查看成员”的权限。如需查看如何在 G Suite 管理控制台中设置此权限的示例,请参阅这篇文章

    如需详细了解如何管理 G Suite 中的群组,您还可以参阅群组帮助中心

  2. 创建多个群组(如果它们尚不存在),以表示对集群具有不同权限的用户组或群组。每个群组都必须对“群组成员”拥有“查看成员”的权限。

  3. 将这些群组(而非用户)添加到 gke-security-groups@yourdomain.com 的成员资格中。

GKE 会根据群组成员资格检查特定用户是否有权创建、修改或查看集群中的资源,也就是说,它会检查该用户是否属于具有访问权限的群组,以及该群组是否直接属于您的网域的 gke-security-groups 群组。用户还必须与群组和集群属于同一网域。也就是说,跨网域授权不适用于此功能。

G Suite Google 群组成员资格的相关信息会缓存一小段时间。 群组成员资格的更改可能需要几分钟才能传播到您的所有集群。除了群组更改带来的延迟之外,集群上的用户凭据的标准缓存时间约为 1 小时。

配置集群以使用 Google GKE 群组

在 G Suite Google 群组管理员设置群组后,请使用 gcloud 命令创建一个新集群,添加 --security-group="gke-security-groups@yourdomain.com" 标志,并将相关值替换为您自己的域名。

以下是 cluster create 命令的示例:

gcloud beta container clusters create cluster-name \
  --security-group="gke-security-groups@yourdomain.com"

现在,您可以随时创建 Role、ClusterRole、RoleBinding 和 ClusterRoleBinding 来引用您的 G Suite Google 群组。

定义和分配权限

您可以通过创建以下类型的 Kubernetes 对象来定义 RBAC 权限:

  • ClusterRoleRole:这些对象定义了一组资源类型和操作,以便分配给集群 (ClusterRole) 或命名空间 (Role) 中的特定用户或用户组,但它们未指定具体用户或用户组。
  • ClusterRoleBindingRoleBinding:这些对象可向特定用户或用户组分配 ClusterRole 或 Role。ClusterRoleBinding 与 ClusterRole 搭配使用,而 RoleBinding 可与 ClusterRole 或 Role 搭配使用。

RBAC 角色纯粹是为了添加权限,不存在“拒绝”规则。在构建 RBAC 角色时,您只应该考虑向用户“授予”哪些集群资源访问权限。

使用 Role 或 ClusterRole 定义权限

您可以在 Role 或 ClusterRole 对象中定义权限。Role 用于定义对单个命名空间内资源的访问权限,而 ClusterRole 用于定义对整个集群内资源的访问权限。

Role 和 ClusterRole 采用相同语法。每个对象都有一个 rules 部分,您可以在其中定义 Role 的相关命名空间、资源类型和允许的操作。例如,以下 Role 授予 accounting 命名空间内所有 Pod 的读取访问权限(getwatchlist):

kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  namespace: accounting
  name: pod-reader
rules:
- apiGroups: [""] # "" indicates the core API group
  resources: ["pods"]
  verbs: ["get", "watch", "list"]

RoleClusterRole

由于 ClusterRole 授予的权限适用于整个集群,因此您可以使用 ClusterRole 来控制与使用 Role 可以控制的不同资源的访问权限。其中包括:

  • 集群级资源(例如节点)
  • 非资源 REST 端点(例如 /healthz
  • 所有命名空间内的命名空间型资源(例如,整个集群内的所有 Pod,无论位于哪个命名空间)

使用 RoleBinding 或 ClusterRoleBinding 分配角色

创建 Role 或 ClusterRole 后,您可以通过创建 RoleBinding 或 ClusterRoleBinding 将其分配给特定用户或用户组。用户和群组被称为 subjects,可以是以下任何类型:

主体类型 kind”的值 name”的值
Google Cloud 用户帐号 User Google Cloud 注册电子邮件地址
Kubernetes 服务帐号 ServiceAccount 集群中 Kubernetes ServiceAccount 对象的名称
IAM 服务帐号 User 自动生成的 IAM 服务帐号电子邮件地址
通过验证的网域上的 G Suite Google 群组地址(Beta 版) Group Google 群组的电子邮件地址,该地址本身是 Google 群组 gke-security-groups@yourdomain.com 的成员

以下 RoleBinding 向用户、Kubernetes 服务帐号、IAM 服务帐号和 Google 群组授予 pod-reader 角色

kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: pod-reader-binding
  namespace: accounting
subjects:
# Google Cloud user account
- kind: User
  name: janedoe@example.com
# Kubernetes service account
- kind: ServiceAccount
  name: johndoe
# IAM service account
- kind: User
  name: test-account@test-project-123456.google.com.iam.gserviceaccount.com
# G Suite Google Group
- kind: Group
  name: accounting-group@example.com
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

API 用法和示例

如需全面了解如何使用 Kubernetes API 创建 RBAC 所需的 RoleClusterRoleRoleBindingClusterRoleBinding 对象,请参阅 Kubernetes 文档中的使用基于角色的访问权限控制授权

问题排查和调试

如需调试 RBAC 的问题,请使用管理员活动审核日志(默认情况下,系统会在所有集群上启用该日志)。如果由于缺少足够的权限而导致对资源或操作的访问被拒绝,则 API 服务器会记录 RBAC DENY 错误以及其他信息,例如用户的隐式和显式群组成员资格。如果您使用的是 Google GKE 群组,则日志消息中会显示 google groups

调试与 Google 群组集成相关的问题

您可以按照以下说明查看日志,以验证您的集群是否已成功配置为在 RBAC RoleBindings 中使用 Google 群组。

前提条件

在开始检查日志之前,请确保:

  • 您至少有一个小时未与要测试的集群进行交互(例如,运行任何 kubectl 命令)。身份验证信息会缓存一小时,您需要确保请求在发生时会得到记录。
  • 您是 gke-security-groups 中至少一个群组的成员。这可确保在日志中填充一些 Google 群组信息。

配置日志

如需通过 RBAC 使用日志来调试 Google 群组,请执行以下操作:

  1. 为您的 Google Cloud 项目启用数据访问日志记录。如需启用日志记录,请执行以下操作:

    1. 在 Cloud Console 中,转到 IAM 菜单中的审核日志页面。

      转到“审核日志”页面

    2. 在表格中,选择 Kubernetes Engine API

    3. 日志类型菜单中,选择:

      • 管理员读取
      • 数据读取
      • 数据写入
    4. 点击保存

    如需详细了解如何启用审核日志记录,请参阅 Cloud 管理工具文档中的使用 Cloud Console 配置数据访问日志

  2. 在集群中使用 kubectl 运行命令。这就像运行 kubectl create ns helloworld 一样简单。

  3. 日志查看器页面中输入自定义查询。如需运行查询,请执行以下操作:

    1. 在 Cloud Console 中,转到日志记录菜单中的日志查看器页面。

      转到“日志查看器”页面

    2. 点击页面顶部的查询预览框中的箭头。

    3. 在显示的下拉框中,复制并粘贴以下查询:

      resource.type="k8s_cluster"
      resource.labels.location="cluster-region"
      resource.labels.cluster_name="cluster-name"
      protoPayload.resourceName="authorization.k8s.io/v1beta1/subjectaccessreviews"
      protoPayload.response.spec.user="email-address"
      

      其中:

      • cluster-region 是您的集群的地区或区域。
      • cluster-name 是您的集群的名称。
      • email-address 是您的 Google 帐号的注册电子邮件地址。
    4. 选择运行查询。您应该至少看到一个结果。如果没有,请尝试增加时间范围。

    5. 选择要检查的集群。

    6. 点击展开嵌套字段

    7. 字段 protoPayload.request.spec.group 包含符合以下条件的群组:

      • 这些群组是 gke-security-group 的成员。
      • 您是该群组的成员。

      此列表应与您所属的群组集匹配。如果没有群组,则可能是因为群组的设置方式存在问题。

  4. 将数据访问日志记录恢复为以前的设置,以免产生更多费用(如果需要)。

限制

以下部分介绍了在使用 Kubernetes RBAC 时可能不太明显的交互。

默认发现角色

创建的集群包含一组默认 ClusterRole 和 ClusterRoleBinding。 使用有效凭据发出的请求将置于 system:authenticated 组中,而其他所有请求都将归入 system:unauthenticated。在 Kubernetes 1.14 版之前,system:authenticatedsystem:unauthenticated 均默认授予 system:basic-usersystem:discovery ClusterRole。

system:basic-user ClusterRole 可让用户进行 SelfSubjectAccessReviews,以测试其在集群中的权限。system:discovery 角色可让用户读取发现 API,这些 API 可以发现已添加到集群的 CustomResourceDefinitions 的相关信息。

从 Kubernetes 1.14 开始,匿名用户 (system:unauthenticated) 将收到 system:public-info-viewer ClusterRole,该角色会授予 /healthz/version API 的只读访问权限。

如需查看 system:discovery ClusterRole 允许的 API 端点,请运行以下命令:

kubectl get clusterroles system:discovery -o yaml

Google Cloud 虚拟机实例上的服务帐号出现“禁止使用”错误

如果虚拟机实例没有 userinfo-email 范围,则可能会发生以下错误:

Error from server (Forbidden): error when creating ... "role-name" is forbidden: attempt to grant extra privileges:...

例如,假设虚拟机具有 cloud-platform 范围,但没有 userinfo-email 范围。当虚拟机获得访问令牌时,Google Cloud 会将该令牌与 cloud-platform 范围相关联。当 Kubernetes API 服务器向 Google Cloud 请求与访问令牌相关联的身份时,它会收到服务帐号的唯一 ID,而不是服务帐号的电子邮件地址。

如需成功进行身份验证,请使用 userinfo-email 范围创建新的虚拟机,或者创建使用唯一 ID 的新角色绑定。

如需使用 userinfo-email 范围创建新的虚拟机,请运行以下命令:

gcloud compute instances create instance-name \
    --service-account service-account-email \
    --scopes userinfo-email

如需创建使用现有虚拟机的服务帐号唯一 ID 的新角色绑定,请执行以下步骤:

  1. 标识服务帐号的唯一 ID:

    gcloud iam service-accounts describe service-account-email
    

    例如,以下输出会显示 my-iam-account@somedomain.com 服务帐号的 uniqueId

    displayName: Some Domain IAM service account
    email: my-iam-account@somedomain.com
    etag: BwWWja0YfJA
    name: projects/project-name/serviceAccounts/my-iam-account@somedomain.com
    oauth2ClientId: '123456789012345678901'
    projectId: project-name
    uniqueId: '123456789012345678901'
    
  2. 使用服务帐号的 uniqueId 创建角色绑定:

    kubectl create clusterrolebinding clusterrolebinding-name \
      --clusterrole cluster-admin \
      --user unique-id
    

后续步骤