对于kubernetes集群访问,用户可以使用kubectl
、客户端库或构造 REST 请求,经过kubernetes的API Server组件,访问集群资源。当请求到达 API 时,它会经历多个阶段,包括认证、鉴权和准入控制,如下图所示:
下面主要讲解鉴权环节中的RBAC鉴权模式。
RBAC,Role-Based Access Control,即基于角色的访问控制,通过自定义具有某些特定权限的 Role,然后,将 Role 和特定的 Subject(user,group,service accounts…)关联起来已达到权限控制的目的。
RBAC 中有三个比较重要的概念:
- Role:角色,本质是一组规则权限的集合,注意:RBAC 中,Role 只声明授予权限,而不存在否定规则;
- Subject:被作用者,包括 user,group,通俗来讲就是认证机制中所识别的用户;
- RoleBinding:定义了“Role”和“Subject”的绑定关系,也就是将用户以及操作权限进行绑定;
RBAC 其实就是通过创建角色(Role),通过 RoleBinding 将被作用者(subject)和角色(Role)进行绑定。
RBAC 鉴权机制使用 rbac.authorization.k8s.io
API 组来驱动鉴权决定, 允许你通过 Kubernetes API 动态配置策略。
要启用 RBAC,在启动 API 服务器时将 --authorization-mode
参数设置为一个逗号分隔的列表并确保其中包含 RBAC
。
kube-apiserver --authorization-mode=Example,RBAC --<其他选项> --<其他选项>
RBAC API 声明了四种 Kubernetes 对象:Role、ClusterRole、RoleBinding 和 ClusterRoleBinding。
Role 和 ClusterRole
RBAC 的 Role 或 ClusterRole 中包含一组代表相关权限的规则。 这些权限是纯粹累加的(不存在拒绝某操作的规则)。
Role 总是用来在某个名字空间内设置访问权限; 在你创建 Role 时,你必须指定该 Role 所属的名字空间。
与之相对,ClusterRole 则是一个集群作用域的资源。这两种资源的名字不同(Role 和 ClusterRole) 是因为 Kubernetes 对象要么是名字空间作用域的,要么是集群作用域的,不可两者兼具。
ClusterRole 有若干用法。你可以用它来:
- 定义对某名字空间域对象的访问权限,并将在各个名字空间内完成授权;
- 为名字空间作用域的对象设置访问权限,并跨所有名字空间执行授权;
- 为集群作用域的资源定义访问权限。
如果你希望在名字空间内定义角色,应该使用 Role; 如果你希望定义集群范围的角色,应该使用 ClusterRole。
Role 示例
下面是一个位于 "default" 名字空间的 Role 的示例,可用来授予对 pods 的读访问权限:
代码语言:javascript复制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
) - 跨名字空间访问的名字空间作用域的资源(如 Pod)
比如,你可以使用 ClusterRole 来允许某特定用户执行
kubectl get pods --all-namespaces
下面是一个 ClusterRole 的示例,可用来为任一特定名字空间中的 Secret 授予读访问权限, 或者跨名字空间的访问权限(取决于该角色是如何绑定的):
代码语言:javascript复制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 或 ClusterRoleBinding 对象的名称必须是合法的 路径区段名称。
RoleBinding 示例
下面的例子中的 RoleBinding 将 "pod-reader" Role 授予在 "default" 名字空间中的用户 "jane"。 这样,用户 "jane" 就具有了读取 "default" 名字空间中 pods 的权限。
代码语言:javascript复制apiVersion: rbac.authorization.k8s.io/v1
# 此角色绑定允许 "jane" 读取 "default" 名字空间中的 Pod
# 你需要在该命名空间中有一个名为 “pod-reader” 的 Role
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"。
代码语言:javascript复制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。
代码语言:javascript复制apiVersion: rbac.authorization.k8s.io/v1
# 此集群角色绑定允许 “manager” 组中的任何人访问任何名字空间中的 Secret 资源
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
设置为不可以改变,这使得可以为用户授予对现有绑定对象的update
权限, 这样可以让他们管理主体列表,同时不能更改被授予这些主体的角色。 - 针对不同角色的绑定是完全不一样的绑定。要求通过删除/重建绑定来更改
roleRef
, 这样可以确保要赋予绑定的所有主体会被授予新的角色(而不是在允许或者不小心修改了roleRef
的情况下导致所有现有主体未经验证即被授予新角色对应的权限)。
命令 kubectl auth reconcile
可以创建或者更新包含 RBAC 对象的清单文件, 并且在必要的情况下删除和重新创建绑定对象,以改变所引用的角色。 更多相关信息请参照命令用法和示例
对资源的引用
在 Kubernetes API 中,大多数资源都是使用对象名称的字符串表示来呈现与访问的。 例如,对于 Pod 应使用 "pods"。 RBAC 使用对应 API 端点的 URL 中呈现的名字来引用资源。 有一些 Kubernetes API 涉及 子资源(subresource),例如 Pod 的日志。 对 Pod 日志的请求看起来像这样:
代码语言:javascript复制GET /api/v1/namespaces/{namespace}/pods/{name}/log
在这里,pods
对应名字空间作用域的 Pod 资源,而 log
是 pods
的子资源。 在 RBAC 角色表达子资源时,使用斜线(/
)来分隔资源和子资源。 要允许某主体读取 pods
同时访问这些 Pod 的 log
子资源,你可以这样写:
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-configmap
的 ConfigMap:
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"]
说明:
你不能使用资源名字来限制 create
或者 deletecollection
请求。 对于 create
请求而言,这是因为在鉴权时可能还不知道新对象的名字。 如果你使用 resourceName
来限制 list
或者 watch
请求, 客户端必须在它们的 list
或者 watch
请求里包含一个与指定的 resourceName
匹配的 metadata.name
字段选择器。 例如,kubectl get configmaps --field-selector=
metadata.name
=my-configmap
总结:
1. RBAC是基于角色管控访问权限,管控层级:集群--namespace--资源类别(如pods)--资源名(具体资源实例)
2. namespace下,推荐ClusterRole RoleBinding方式,可以复用角色,方便管理
3. 创建了绑定之后,你不能再修改绑定对象所引用的 Role 或 ClusterRole。 试图改变绑定对象的 roleRef 将导致合法性检查错误。 如果你想要改变现有绑定对象中 roleRef 字段的内容,必须删除重新创建绑定对象。
参考资料:
Kubernetes RBAC鉴权:https://kubernetes.io/zh-cn/docs/reference/access-authn-authz/rbac/
一文读懂Kubernetes RBAC机制:https://blog.yingchi.io/posts/2020/7/k8s-rbac.html
K8S API资源—ApiGroup、Resources和Verbs:https://juejin.cn/post/6847902219761942541