基于角色(Role)的访问控制(RBAC)是一种基于组织中用户的角色来调节控制对 计算机或网络资源的访问的方法。RBAC 鉴权机制使用 rbac.authorization.k8s.io来驱动鉴权决定,允许你通过 Kubernetes API 动态配置策略。要启用 RBAC,在启动时将 --authorization-mode 参数设置为一个逗号分隔的列表并确保其中包含 RBAC

1
kube-apiserver --authorization-mode=Example,RBAC --<其他选项> --<其他选项>

使用 RBAC 鉴权 | Kubernetes

Api对象

RBAC API 声明了四种 Kubernetes 对象: RoleClusterRoleRoleBindingClusterRoleBinding 。你可以像使用其他 Kubernetes 对象一样, 通过类似 kubectl 这类工具 描述对象, 或修补对象。

Role&ClusterRole

RBAC 的 RoleClusterRole 中包含一组代表相关权限的规则。 这些权限是纯粹累加的(不存在拒绝某操作的规则)。Role 总是用来在某个namespace内设置访问权限;在你创建 Role 时,你必须指定该 Role 所属的namespace。

与之相对,ClusterRole 则是一个集群作用域的资源。这两种资源的名字不同(Role 和 ClusterRole)是因为 Kubernetes 对象要么是名字空间作用域的,要么是集群作用域的, 不可两者兼具。

ClusterRole 有若干用法。你可以用它来:

  1. 定义对某名字空间域对象的访问权限,并将在各个名字空间内完成授权;
  2. 为名字空间作用域的对象设置访问权限,并跨所有名字空间执行授权;
  3. 为集群作用域的资源定义访问权限。

如果你希望在名字空间内定义角色,应该使用 Role; 如果你希望定义集群范围的角色,应该使用 ClusterRole。

Role

如果需要授予对default namespace下pod的读权限,可以用如下定义

1
2
3
4
5
6
7
8
9
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: pod-reader
rules:
- apiGroups: [""] # "" 标明 core API 组
  resources: ["pods"]
  verbs: ["get", "watch", "list"]

ClusterRole

ClusterRole 可以和 Role 相同完成授权。 因为 ClusterRole 属于集群范围,所以它也可以为以下资源授予访问权限:

  • 集群范围资源(比如 [节点(Node)]
  • 非资源端点(比如 /healthz
  • 跨名字空间访问的名字空间作用域的资源(如 Pods) 比如,你可以使用 ClusterRole 来允许某特定用户执行 kubectl get pods --all-namespaces

下面是一个 ClusterRole 的示例,可用来为任一特定名字空间中的 Secret 授予读访问权限, 或者跨名字空间的访问权限(取决于该角色是如何绑定的):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  # "namespace" 被忽略,因为 ClusterRoles 不受名字空间限制
  name: secret-reader
rules:
- apiGroups: [""]
  # 在 HTTP 层面,用来访问 Secret 对象的资源的名称为 "secrets"
  resources: ["secrets"]
  verbs: ["get", "watch", "list"]

RoleBinding & ClusterRoleBinding

角色绑定(Role Binding)是将角色中定义的权限赋予一个或者一组用户。 它包含若干 主体 (用户、组或服务账户)的列表和对这些主体所获得的角色的引用。 RoleBinding 在指定的名字空间中执行授权,而 ClusterRoleBinding 在集群范围执行授权。

一个 RoleBinding 可以引用同一的名字空间中的任何 Role。 或者,一个 RoleBinding 可以引用某 ClusterRole 并将该 ClusterRole 绑定到 RoleBinding 所在的名字空间。 如果你希望将某 ClusterRole 绑定到集群中所有名字空间,你要使用 ClusterRoleBinding。

RoleBinding

下面的例子中的 RoleBinding 将 “pod-reader” Role 授予在 “default” 名字空间中的用户 “jane”。 这样,用户 “jane” 就具有了读取 “default” 名字空间中 pods 的权限。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
apiVersion: rbac.authorization.k8s.io/v1
# 此角色绑定允许 "jane" 读取 "default" 名字空间中的 Pods
kind: RoleBinding
metadata:
  name: read-pods
  namespace: default
subjects:
# 你可以指定不止一个“subject(主体)”
- kind: User
  name: jane # "name" 是区分大小写的
  apiGroup: rbac.authorization.k8s.io
roleRef:
  # "roleRef" 指定与某 Role 或 ClusterRole 的绑定关系
  kind: Role # 此字段必须是 Role 或 ClusterRole
  name: pod-reader     # 此字段必须与你要绑定的 Role 或 ClusterRole 的名称匹配
  apiGroup: rbac.authorization.k8s.io

RoleBinding 也可以引用 ClusterRole,以将对应 ClusterRole 中定义的访问权限授予 RoleBinding 所在名字空间的资源。这种引用使得你可以跨整个集群定义一组通用的角色, 之后在多个名字空间中复用。

例如,尽管下面的 RoleBinding 引用的是一个 ClusterRole,“dave”(这里的主体, 区分大小写)只能访问 “development” 名字空间中的 Secrets 对象,因为 RoleBinding 所在的名字空间(由其 metadata 决定)是 “development”。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
apiVersion: rbac.authorization.k8s.io/v1
# 此角色绑定使得用户 "dave" 能够读取 "development" 名字空间中的 Secrets
# 你需要一个名为 "secret-reader" 的 ClusterRole
kind: RoleBinding
metadata:
  name: read-secrets
  # RoleBinding 的名字空间决定了访问权限的授予范围。
  # 这里隐含授权仅在 "development" 名字空间内的访问权限。
  namespace: development
subjects:
- kind: User
  name: dave # 'name' 是区分大小写的
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: secret-reader
  apiGroup: rbac.authorization.k8s.io

ClusterRoleBinding

要跨整个集群完成访问权限的授予,你可以使用一个 ClusterRoleBinding。 下面的 ClusterRoleBinding 允许 “manager” 组内的所有用户访问任何名字空间中的 Secrets。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
apiVersion: rbac.authorization.k8s.io/v1
# 此集群角色绑定允许 “manager” 组中的任何人访问任何名字空间中的 secrets
kind: ClusterRoleBinding
metadata:
  name: read-secrets-global
subjects:
- kind: Group
  name: manager # 'name' 是区分大小写的
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: secret-reader
  apiGroup: rbac.authorization.k8s.io

创建了绑定之后,你不能再修改绑定对象所引用的 Role 或 ClusterRole。 试图改变绑定对象的 roleRef 将导致合法性检查错误。 如果你想要改变现有绑定对象中 roleRef 字段的内容,必须删除重新创建绑定对象。

这种限制有两个主要原因:

  1. 针对不同角色的绑定是完全不一样的绑定。要求通过删除/重建绑定来更改 roleRef, 这样可以确保要赋予绑定的所有主体会被授予新的角色(而不是在允许或者不小心修改 了 roleRef 的情况下导致所有现有主体未经验证即被授予新角色对应的权限)。
  2. roleRef 设置为不可以改变,这使得可以为用户授予对现有绑定对象的 update 权限, 这样可以让他们管理主体列表,同时不能更改被授予这些主体的角色。

命令 kubectl auth reconcile 可以创建或者更新包含 RBAC 对象的清单文件, 并且在必要的情况下删除和重新创建绑定对象,以改变所引用的角色。

对资源的引用

在 Kubernetes API 中,大多数资源都是使用对象名称的字符串表示来呈现与访问的。 例如,对于 Pod 应使用 “pods”。 RBAC 使用对应 API 端点的 URL 中呈现的名字来引用资源。 有一些 Kubernetes API 涉及 子资源(subresource),例如 Pod 的日志。 对 Pod 日志的请求看起来像这样:

1
GET /api/v1/namespaces/{namespace}/pods/{name}/log

pods 对应名字空间作用域的 Pod 资源,而 logpods 的子资源。 在 RBAC 角色表达子资源时,使用斜线(/)来分隔资源和子资源。 要允许某主体读取 pods 同时访问这些 Pod 的 log 子资源,你可以这么写:

1
2
3
4
5
6
7
8
9
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: pod-and-pod-logs-reader
rules:
- apiGroups: [""]
  resources: ["pods", "pods/log"]
  verbs: ["get", "list"]

对于某些请求,也可以通过 resourceNames 列表按名称引用资源。 在指定时,可以将请求限定为资源的单个实例。 下面的例子中限制可以 “get” 和 “update” 一个名为 my-configmapConfigMap

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: configmap-updater
rules:
- apiGroups: [""]
  # 在 HTTP 层面,用来访问 ConfigMap 的资源的名称为 "configmaps"
  resources: ["configmaps"]
  resourceNames: ["my-configmap"]
  verbs: ["update", "get"]

默认Roles和Role Bindings

API 服务器创建一组默认的 ClusterRole 和 ClusterRoleBinding 对象。 这其中许多是以 system: 为前缀的,用以标识对应资源是直接由集群控制面管理的。 所有的默认 ClusterRole 和 ClusterRoleBinding 都有 kubernetes.io/bootstrapping=rbac-defaults 标签。

自动协商

在每次启动时,API 服务器都会更新默认 ClusterRole 以添加缺失的各种权限,并更新 默认的 ClusterRoleBinding 以增加缺失的各类主体。 这种自动协商机制允许集群去修复一些不小心发生的修改,并且有助于保证角色和角色绑定 在新的发行版本中有权限或主体变更时仍然保持最新。

如果要禁止此功能,请将默认 ClusterRole 以及 ClusterRoleBinding 的 rbac.authorization.kubernetes.io/autoupdate 注解设置成 false。 注意,缺少默认权限和角色绑定主体可能会导致集群无法正常工作。

如果基于 RBAC 的鉴权机制被启用,则自动协商功能默认是被启用的。

API发现角色

无论是经过身份验证的还是未经过身份验证的用户,默认的角色绑定都授权他们读取被认为 是可安全地公开访问的 API( 包括 CustomResourceDefinitions)。 如果要禁用匿名的未经过身份验证的用户访问,请在 API 服务器配置中中添加 --anonymous-auth=false 的配置选项。

通过运行命令 kubectl 可以查看这些角色的配置信息:

1
kubectl get clusterroles system:discovery -o yaml

说明:

如果你编辑该 ClusterRole,你所作的变更会被 API 服务器在重启时自动覆盖,这是通过 自动协商机制完成的。要避免这类覆盖操作, 要么不要手动编辑这些角色,要么禁止自动协商机制。

默认 ClusterRole 默认 ClusterRoleBinding 描述
system:basic-user system:authenticated 允许用户以只读的方式去访问他们自己的基本信息。在 1.14 版本之前,这个角色在默认情况下也绑定在 system:unauthenticated 上。
system:discovery system:authenticated 允许以只读方式访问 API 发现端点,这些端点用来发现和协商 API 级别。 在 1.14 版本之前,这个角色在默认情况下绑定在 system:unauthenticated 上。
system:public-info-viewer system:authenticatedsystem:unauthenticated 允许对集群的非敏感信息进行只读访问,它是在 1.14 版本中引入的。