官方文档: 使用 RBAC 鉴权
API 对象
RBAC API 声明了四种 Kubernetes 对象: Role
, ClusterRole
, RoleBinding
和 ClusterRoleBinding
。
Role 和 ClusterRole
RBAC 的 Role 或 ClusterRole 中包含一组代表相关权限的规则。这些权限是存粹累加的(不存在拒绝某种操作的规则)。
Role 是用来在某个 namespace 内设置访问权限;在你创建 Role 时,必须指定该 Role 所属的 namespace。
ClusterRole 则是一个集群作用域的资源对象。这两种资源的名字不同(Role 和 ClusterRole)是因为 Kubernetes 对象要么是 namespace 作用域的,要么是集群作用域的, 不可两者兼具。
ClusterRole 有若干用法。可以用它做以下授权限制
- 定义对某 namespace 域对象的访问权限,并将在各个 namespace 内完成授权;
- 为 namespace 作用域的对象设置访问权限,并跨所有 namespace 执行授权;
- 为集群作用域的资源定义访问权限。
ClusterRole 可以和 Role 一样完成授权。 因为 ClusterRole 属于集群范围,所以它也可以为以下资源授予访问权限:
- 集群范围资源(比如节点 Node)
- 非资源端点(比如 /healthz)
- 跨 namespace 访问 namespace 作用域的资源(如 Pods),比如,你可以使用 ClusterRole 来允许某特定用户执行
kubectl get pods --all-namespaces
如果你希望在 namespace 内定义角色,应该使用 Role;如果希望定义集群范围的角色,应该使用 ClusterRole。
Role 示例
下面是一个位于 “default” 名字空间的 Role 的示例,可用来授予对 pods 的读访问权限:
1
2
3
4
5
6
7
8
9apiVersion: 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 的示例,可用来为任一特定 namespace 中的 Secret 授予读访问权限,或者跨 namespace 的访问权限(取决于该角色是如何绑定的):
1
2
3
4
5
6
7
8
9
10apiVersion: 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)是将角色中定义的权限赋予一个或者一组用户。它包含若干主体(User、Group 或 ServiceAccount)的列表和对这些主体所获得的角色的引用。RoleBinding 在指定的 namespace 中执行授权,而 ClusterRoleBinding 在集群范围执行授权。
一个 RoleBinding 可以引用同一 NameSpace 中的任何 Role。或者,一个 RoleBinding 可以引用某 ClusterRole 并将该 ClusterRole 绑定到 RoleBinding 所在的 namespace。 如果你希望将某 ClusterRole 绑定到集群中所有 namespace,你要使用 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
16apiVersion: 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.ioRoleBinding 也可以引用 ClusterRole,以将对应 ClusterRole 中定义的访问权限授予 RoleBinding 所在名字空间的资源。这种引用使得你可以跨整个集群定义一组通用的角色,之后在多个 namespace 中复用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17apiVersion: 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虽然上面的 RoleBinding 引用的是一个 ClusterRole,但是 “dave” 只能访问 “development” 名字空间中的 Secrets 对象,因为 RoleBinding 所在的 namespace 是 “development”。
ClusterRoleBinding 示例
要跨整个集群完成访问权限的授予,你可以使用一个 ClusterRoleBinding。
下面的 ClusterRoleBinding 允许 “manager” 组内的所有用户访问任何 namespace 中的 Secrets。
1
2
3
4
5
6
7
8
9
10
11
12
13apiVersion: 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 字段的内容,必须删除重新创建绑定对象。
这种限制有两个主要原因:
- 针对不同角色的绑定是完全不一样的绑定。要求通过删除/重建绑定来更改 roleRef, 这样可以确保要赋予绑定的所有主体会被授予新的角色(而不是在允许或者不小心修改了 roleRef 的情况下导致所有现有主体未经验证即被授予新角色对应的权限)。
- 将 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 对应 namespace
作用域的 Pod 资源,而 log 是 pods
的子资源。
在 RBAC 角色表达子资源时,使用斜线(/)来分隔资源和子资源。要允许某主体读取 pods 同时访问这些 Pod 的 log 子资源,你可以这么写:
1
2
3
4
5
6
7
8
9apiVersion: 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-configmap 的 ConfigMap:1
2
3
4
5
6
7
8
9
10
11apiVersion: 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"]不能针对 create 或者 deletecollection 请求来实施 resourceName 限制。 对于 create 操作而言,这是因为在鉴权时还不知道对象名称。
聚合 ClusterRole
可以将若干 ClusterRole 聚合(Aggregate) 起来,形成一个复合的 ClusterRole。 某个控制器作为集群控制面的一部分会监视带有 aggregationRule
的 ClusterRole 对象集合。aggregationRule
为控制器定义一个标签选择算符供后者匹配应该组合到当前 ClusterRole 的 roles 字段中的 ClusterRole 对象。
下面是一个聚合 ClusterRole 的示例
1
2
3
4
5
6
7
8
9apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: monitoring
aggregationRule:
clusterRoleSelectors:
- matchLabels:
rbac.example.com/aggregate-to-monitoring: "true"
rules: [] # 控制面自动填充这里的规则如果创建一个与某现有聚合 ClusterRole 的标签选择算符匹配的 ClusterRole,这一变化会触发新的规则被添加到聚合 ClusterRole 的操作。下面的例子中,通过创建一个标签同样为
rbac.example.com/aggregate-to-monitoring: true
的 ClusterRole,新的规则可被添加到 “monitoring” ClusterRole 中。1
2
3
4
5
6
7
8
9
10
11
12apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: monitoring-endpoints
labels:
rbac.example.com/aggregate-to-monitoring: "true"
# 当你创建 "monitoring-endpoints" ClusterRole 时,
# 下面的规则会被添加到 "monitoring" ClusterRole 中
rules:
- apiGroups: [""]
resources: ["services", "endpoints", "pods"]
verbs: ["get", "list", "watch"]
使用 ClusterRole 聚合。 这使得作为集群管理员的你可以为扩展默认规则,包括为定制资源设置规则, 比如通过 CustomResourceDefinitions 或聚合 API 服务器提供的定制资源。
Role 示例(资源设置部分)
参考官方文档: Role 示例
对主体的引用
RoleBinding 或者 ClusterRoleBinding 可绑定角色到某 主体(Subject)
上。 主体可以是 Group,User 或者 serviceaccount。
Kubernetes 用字符串来表示用户名。用户名可以是普通的用户名,像 “alice”;或者是邮件风格的名称,如 “bob@example.com“,或者是以字符串形式表达的数字 ID。作为 Kubernetes 管理员负责配置身份认证模块以便后者能够生成你所期望的格式的用户名。
前缀
system:
是 Kubernetes 系统保留的,所以你要确保 所配置的用户名或者组名不能出现上述system:
前缀。除了对前缀的限制之外,RBAC 鉴权系统不对用户名格式作任何要求。
在 Kubernetes 中,鉴权模块提供用户组信息。与用户名一样,用户组名也用字符串来表示,而且对该字符串没有格式要求,只是不能使用保留的前缀 system:
。
serviceaccount 的用户名前缀为 system:serviceaccount:
,属于前缀为 system:serviceaccounts:
的用户组。
说明:
- system:serviceaccount: (单数)是用于服务账户用户名的前缀;
- system:serviceaccounts: (复数)是用于服务账户组名的前缀。
RoleBinding 示例(主体设置部分)
参考官方文档: RoleBingding 示例
默认 Roles 和 RoleBindings
API 服务器创建一组默认的 ClusterRole 和 ClusterRoleBinding 对象。 这其中许多是以 system: 为前缀的,用以标识对应资源是直接由集群控制面管理的。 所有的默认 ClusterRole 和 ClusterRoleBinding 都有 kubernetes.io/bootstrapping=rbac-defaults
标签。
注意: 在修改名称包含
system:
前缀的 ClusterRole 和 ClusterRoleBinding 时要格外小心。 对这些资源的更改可能导致集群无法继续工作。
自动协商
在每次启动时,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:authenticated 和 system:unauthenticated 组 | 允许对集群的非敏感信息进行只读访问,它是在 1.14 版本中引入的。 |
面向用户的角色
一些默认的 ClusterRole 不是以前缀 system:
开头的。这些是面向用户的角色。它们包括超级用户(Super-User)角色(cluster-admin)、 使用 ClusterRoleBinding 在集群范围内完成授权的角色(cluster-status)、 以及使用 RoleBinding 在特定名字空间中授予的角色(admin、edit、view)。
面向用户的 ClusterRole 使用 聚合 ClusterRole
以允许管理员在这些 ClusterRole 上添加用于定制资源的规则。如果想要添加规则到 admin、edit 或者 view,可以创建带有以下一个或多个标签的 ClusterRole:
1 | metadata: |
默认 ClusterRole | 默认 ClusterRoleBinding | 描述 |
---|---|---|
cluster-admin | system:masters 组 | 允许超级用户在平台上的任何资源上执行所有操作。 当在 ClusterRoleBinding 中使用时,可以授权对集群中以及所有 namespace 中的全部资源进行完全控制。 当在 RoleBinding 中使用时,可以授权控制 RoleBinding 所在 namespace 中的所有资源,包括 namespace 本身。 |
admin | 无 | 允许管理员访问权限,旨在使用 RoleBinding 在 namespace 内执行授权。 如果在 RoleBinding 中使用,则可授予对 namespace 中的大多数资源的读/写权限, 包括创建角色和角色绑定的能力。 但是它不允许对资源配额或者 namespace 本身进行写操作。 |
edit | 无 | 允许对 namespace 的大多数对象进行读/写操作。 它不允许查看或者修改角色或者角色绑定。不过,此角色可以访问 Secret,以 namespace 中任何 ServiceAccount 的身份运行 Pods,所以可以用来了解 namespace 内所有服务账户的 API 访问级别。 |
view | 无 | 允许对 namespace 的大多数对象有只读权限。它不允许查看角色或角色绑定。 |
此角色不允许查看 Secrets,因为读取 Secret 的内容意味着可以访问 namespace 中 ServiceAccount 的凭据信息,进而允许利用 namespace 中任何 ServiceAccount 的 身份访问 API(这是一种特权提升)。 |
核心组件的角色
参考官方文档: 核心组件角色
其他组件角色
参考官方文档: 其他组件角色
命令行使用
创建 Role (kubectl create role)
创建 Role 对象,定义在某一 namespace 中的权限。例如:
- 创建名称为 “pod-reader” 的 Role 对象,允许用户对 Pods 执行 get、watch 和 list 操作:
1
kubectl create role pod-reader --verb=get --verb=list --verb=watch --resource=pods
- 创建名称为 “pod-reader” 的 Role 对象并指定 resourceNames
1
kubectl create role pod-reader --verb=get --resource=pods --resource-name=readablepod --resource-name=anotherpod
- 创建名为 “foo” 的 Role 对象并指定 apiGroups:
1
kubectl create role foo --verb=get,list,watch --resource=replicasets.apps
- 创建名为 “foo” 的 Role 对象并指定子资源权限:
1
kubectl create role foo --verb=get,list,watch --resource=pods,pods/status
- 创建名为 “my-component-lease-holder” 的 Role 对象,使其具有对特定名称的资源执行 get/update 的权限
1
kubectl create role my-component-lease-holder --verb=get,list,watch,update --resource=lease --resource-name=my-component
创建 ClusterRole (kubectl create clusterrole)
创建 ClusterRole 对象。例如:
- 创建名称为 “pod-reader” 的 ClusterRole对象,允许用户对 Pods 对象执行 get、watch和list` 操作:
1
kubectl create clusterrole pod-reader --verb=get,list,watch --resource=pods
- 创建名为 “pod-reader” 的 ClusterRole 对象并指定 resourceNames:
1
kubectl create clusterrole pod-reader --verb=get --resource=pods --resource-name=readablepod --resource-name=anotherpod
- 创建名为 “foo” 的 ClusterRole 对象并指定 apiGroups:
1
kubectl create clusterrole foo --verb=get,list,watch --resource=replicasets.apps
- 创建名为 “foo” 的 ClusterRole 对象并指定子资源:
1
kubectl create clusterrole foo --verb=get,list,watch --resource=pods,pods/status
- 创建名为 “foo” 的 ClusterRole 对象并指定 nonResourceURL:
1
kubectl create clusterrole "foo" --verb=get --non-resource-url=/logs/*
- 创建名为 “monitoring” 的 ClusterRole 对象并指定 aggregationRule:
1
kubectl create clusterrole monitoring --aggregation-rule="rbac.example.com/aggregate-to-monitoring=true"
创建 Rolebinding (kubectl create rolebinding)
在特定的名字空间中对 Role 或 ClusterRole 授权。例如:
- 在 namespace “acme” 中,将名为 admin 的 ClusterRole 中的权限授予名称 “bob” 的用户:
1
kubectl create rolebinding bob-admin-binding --clusterrole=admin --user=bob --namespace=acme
- 在名字空间 “acme” 中,将名为 view 的 ClusterRole 中的权限授予名字空间 “acme” 中名为 myapp 的服务账户:
1
kubectl create rolebinding myapp-view-binding --clusterrole=view --serviceaccount=acme:myapp --namespace=acme
- 在名字空间 “acme” 中,将名为 view 的 ClusterRole 对象中的权限授予名字空间 “myappnamespace” 中名称为 myapp 的服务账户:
1
kubectl create rolebinding myappnamespace-myapp-view-binding --clusterrole=view --serviceaccount=myappnamespace:myapp --namespace=acme
创建 ClusterRoleBinding (kubectl create clusterrolebinding)
在整个集群(所有名字空间)中用 ClusterRole 授权。例如:
- 在整个集群范围,将名为 cluster-admin 的 ClusterRole 中定义的权限授予名为 “root” 用户:
1
kubectl create clusterrolebinding root-cluster-admin-binding --clusterrole=cluster-admin --user=root
- 在整个集群范围内,将名为
system:node-proxier
的 ClusterRole 的权限授予名为system:kube-proxy
的用户:
1
kubectl create clusterrolebinding kube-proxy-binding --clusterrole=system:node-proxier --user=system:kube-proxy
- 在整个集群范围内,将名为 view 的 ClusterRole 中定义的权限授予 “acme” 名字空间中 名为 “myapp” 的服务账户:
1
kubectl create clusterrolebinding myapp-view-binding --clusterrole=view --serviceaccount=acme:myapp
ServiceAccount 权限
默认的 RBAC 策略为控制面组件、节点和控制器授予权限。但是不会对 kube-system namespace 之外的服务账户授予权限。(除了授予所有已认证用户的发现权限)
这使得你可以根据需要向特定服务账户授予特定权限。细粒度的角色绑定可带来更好的安全性,但需要更多精力管理。粗粒度的授权可能导致服务账户被授予不必要的 API 访问权限(甚至导致潜在的权限提升),但更易于管理。
按从最安全到最不安全的顺序,存在以下方法:
为特定应用的服务账户授予角色(最佳实践),这要求应用在其 Pod 规约中指定 serviceAccountName, 并额外创建服务账户(包括通过 API、应用程序清单、
kubectl create serviceaccount
等)。- 例如,在名字空间 “my-namespace” 中授予服务账户 “my-sa” 只读权限:
1
2
3
4kubectl create rolebinding my-sa-view \
--clusterrole=view \
--serviceaccount=my-namespace:my-sa \
--namespace=my-namespace将角色授予某名字空间中的 “default” 服务账户,如果某应用没有指定 serviceAccountName,那么它将使用 “default” 服务账户。
“default” 服务账户所具有的权限会被授予给名字空间中所有未指定 serviceAccountName 的 Pod。
- 例如,在名字空间 “my-namespace” 中授予服务账户 “default” 只读权限:
1
2
3
4kubectl create rolebinding default-view \
--clusterrole=view \
--serviceaccount=my-namespace:default \
--namespace=my-namespace许多插件组件 在 kube-system 名字空间以 “default” 服务账户运行。 要允许这些插件组件以超级用户权限运行,需要将集群的 cluster-admin 权限授予 kube-system 名字空间中的 “default” 服务账户。
1
2
3kubectl create clusterrolebinding add-on-cluster-admin \
--clusterrole=cluster-admin \
--serviceaccount=kube-system:default启用这一配置意味着在 kube-system 名字空间中包含以超级用户账号来访问 API 的 Secrets。
将角色授予名字空间中所有服务账户,如果你想要名字空间中所有应用都具有某角色,无论它们使用的什么服务账户, 可以将角色授予该名字空间的服务账户组。
- 例如,在名字空间 “my-namespace” 中的只读权限授予该名字空间中的所有服务账户:
1
2
3
4kubectl create rolebinding serviceaccounts-view \
--clusterrole=view \
--group=system:serviceaccounts:my-namespace \
--namespace=my-namespace在集群范围内为所有服务账户授予一个受限角色(不鼓励),如果你不想管理每一个名字空间的权限,你可以向所有的服务账户授予集群范围的角色。
- 例如,为集群范围的所有服务账户授予跨所有名字空间的只读权限:
1
2
3kubectl create clusterrolebinding serviceaccounts-view \
--clusterrole=view \
--group=system:serviceaccounts授予超级用户访问权限给集群范围内的所有服务帐户(强烈不鼓励),如果你不关心如何区分权限,你可以将超级用户访问权限授予所有服务账户。
1
2
3kubectl create clusterrolebinding serviceaccounts-cluster-admin \
--clusterrole=cluster-admin \
--group=system:serviceaccounts