前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >图解K8s源码 - kube-apiserver下的RBAC鉴权机制

图解K8s源码 - kube-apiserver下的RBAC鉴权机制

作者头像
才浅Coding攻略
发布2022-12-12 18:18:35
6560
发布2022-12-12 18:18:35
举报
文章被收录于专栏:才浅coding攻略才浅coding攻略

阿巩

日拱一卒

最近有大佬问了阿巩个问题,“开发PaaS平台遇到多租户的权限管理问题该如何处理”。考虑到k8s默认提供了类似的RBAC机制,于是想着借鉴或者直接利用k8s的RBAC来实现,下面是阿巩梳理的这部分内容,特来与大伙分享也让自己对这部分知识更加深化。

在介绍 RBAC 之前,先看下k8s的kube-apiserver都支持哪些授权机制。

对于访问k8s集群,用户可以通过 kubectl、客户端库或构造 REST 请求来访问。在客户端请求通过认证之后,会来到授权阶段,kube-apiserver 支持同时开启多个授权功能,并按照顺序执行授权器。6种授权机制,分别是AlwaysAllow、AlwaysDeny、ABAC、Webhook、RBAC、Node,可通过指定 --authorization-mode 参数设置授权机制。

代码语言:javascript
复制
kube-apiserver --authorization-mode=Example,RBAC --<其他选项> --<其他选项>
  • AlwaysAllow:允许所有请求。
  • AlwaysDeny:拒绝所有请求。
  • ABAC:即 Attribute-Based Access Control ,基于属性的访问控制。
  • Webhook:基于Webhook的一种http协议回调,可进行远程授权管理。
  • Node:节点授权,专门授权给kubelet发出的API请求。
  • RBAC:即Role-Based Access Control,基于角色的访问控制。

RBAC 授权器是目前使用最为广泛的授权模型,用户通过加入某些角色从而得到这些角色的操作权限,这极大地简化了权限管理。

在 kube-apiserver中的 RBAC 授权器中,新增了角色与集群绑定的概念。所以 kube-apiserver提供了4种对象来表达基于角色的授权,它们分别是RoleClusterRoleRoleBinding ClusterRoleBinding,这4种数据类型定义在vendor/k8s.io/api/rbac/v1/types.go中。

我们先来看角色与集群角色的数据结构,这里只列出较重要字段。图中的PolicyRule 规则相当于操作权限,权限控制资源的操作方法(即 Verbs):

Role 角色是一组用户的集合,与规则相关联,Role 只能被赋予某一 namespace 的权限,即创建 Role 时必须指定Role 所属的 namespace。

下面是一个位于 "ns-a" 名字空间的 Role 的示例,可用来授予对 pods 的读访问权限:

代码语言:javascript
复制
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: ns-a  # 定义于 namespace 下
  name: pod-reader
rules:
- apiGroups: [""] 
  resources: ["pods"]
  verbs: ["get", "watch", "list"]

ClusterRole 集群角色也是一组用户的集合,与规则相关联,但ClusterRole被授予集群范围的权限,即不但能够作用于某个namespace下,还可以作用于cluster范围下。

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

代码语言:javascript
复制
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  # "namespace" 被忽略,因为 ClusterRoles 不受名字空间限制
  name: secret-reader
rules:
- apiGroups: [""]  # 资源组,"" 缺省为 core 组资源,其它诸如 apps 等
  # 在 HTTP 层面,用来访问 Secret 资源的名称为 "secrets"
  resources: ["secrets"]  # 资源,比如 pods、deployments、services、secrets 等
  verbs: ["get", "watch", "list"]  # 操作动词,如 get、list、watch、create、delete、update 等

再来看角色绑定和集群角色绑定的数据结构,其中Subject主体可以是user,group 和 serviceaccounts;RoleRef 指被授予权限的角色的引用信息。

RoleBinding 角色绑定,绑定 Role/ClusterRole 及角色引用信息到 Subject,角色只生效于具体的 namespace 范围资源;ClusterRoleBinding 集群角色绑定,绑定 ClusterRole 及角色引用信息到 Subject,角色生效于 cluster 范围资源。

K8s 中权限控制的范围(namespace/cluster)是由 Binding 的类型决定的,而不是根据 Role 和 ClusterRole 决定的。

到这里时阿巩产生了一个疑问,对于作用于namespace范围,我需要使用 RoleBinding,但是应该选择 Role/ClusterRole 的哪种角色呢,如何选择呢?

我们通过示例对比来看,首先是 Role + RoleBinding 组合,要实现在namespace 范围内的 Subject 与 Role 绑定,无非是通过配置一个 RoleBinding 将两者联系起来。

下面的例子中的 RoleBinding 将 "pod-reader" Role 授予在 "ns-a" 名字空间中的用户 "jane"。 这样用户 "jane" 就具有了读取 "ns-a" 名字空间中 pods 的权限。代码如下:

代码语言:javascript
复制
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods
  namespace: ns-a
subjects:
- kind: User
  name: jane
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

使用上述方法可以完成授权,但是假如有两个或者多个namespace都需要这么一个有读取 pods 的 Role,就需要为每个 namespace 都定义一个 PodReader 的 Role 了,这样做过程不优雅而且造成资源浪费。所以我们要复用这个 Role 就需用到 ClusterRole + RoleBinding 的组合:

代码语言:javascript
复制
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods
  namespace: ns-a
subjects:
- kind: User
  name: jane
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole  # 这里使用集群角色
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

作用于集群范围的方案只有一个,就是 ClusterRoleBinding + ClusterRole,即全局方法只能使用 ClusterRole 这样的全局量:

代码语言: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 字段的内容,必须删除重新创建绑定对象。

我们在上一篇文章 k8s核心数据结构 中提到了 k8s 本质上是一个资源控制系统。在 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 子资源,可以这样写:

代码语言:javascript
复制
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:

代码语言:javascript
复制
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 字段选择器,例如:

代码语言:javascript
复制
kubectl get configmaps --field-selector=metadata.name=my-configmap

在为主体绑定角色时,我们说Subject主体可以是user,group 和 serviceaccounts。大多数时候,我们在基于k8s做二次开发时都是选择通过ServiceAccount + RBAC 的方式。这里我找了个示例,链接放到下面:

https://blog.51cto.com/u_12965094/2649513

总结:

  1. RBAC是基于角色的访问控制,它通过创建角色(Role)使用 RoleBinding 将被作用者(subject)和角色(Role)进行绑定。
  2. 作用域在namespace下,推荐 ClusterRole+RoleBinding 方式,可以复用角色,方便管理。
  3. K8s RBAC 中对于权限控制的范围不是由 Role 决定的,而是由 Binding 的类型决定的。
  4. 绑定创建后,不能再修改绑定对象所引用的 Role 或 ClusterRole。要改变现有绑定对象中 roleRef 字段的内容,必须删除重新创建绑定对象。

参考:

https://kubernetes.io/zh-cn/docs/reference/access-authn-authz/rbac/

https://blog.yingchi.io/posts/2020/7/k8s-rbac.html

END

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-11-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 才浅coding攻略 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档