26 | 基于角色的权限控制:RBAC
下载APP
关闭
渠道合作
推荐作者
26 | 基于角色的权限控制:RBAC
2018-10-22 张磊 来自北京
《深入剖析Kubernetes》
课程介绍
讲述:张磊
时长14:03大小6.44M
你好,我是张磊。今天我和你分享的主题是:基于角色的权限控制之 RBAC。
在前面的文章中,我已经为你讲解了很多种 Kubernetes 内置的编排对象,以及对应的控制器模式的实现原理。此外,我还剖析了自定义 API 资源类型和控制器的编写方式。
这时候,你可能已经冒出了这样一个想法:控制器模式看起来好像也不难嘛,我能不能自己写一个编排对象呢?
答案当然是可以的。而且,这才是 Kubernetes 项目最具吸引力的地方。
毕竟,在互联网级别的大规模集群里,Kubernetes 内置的编排对象,很难做到完全满足所有需求。所以,很多实际的容器化工作,都会要求你设计一个自己的编排对象,实现自己的控制器模式。
而在 Kubernetes 项目里,我们可以基于插件机制来完成这些工作,而完全不需要修改任何一行代码。
不过,你要通过一个外部插件,在 Kubernetes 里新增和操作 API 对象,那么就必须先了解一个非常重要的知识:RBAC。
我们知道,Kubernetes 中所有的 API 对象,都保存在 Etcd 里。可是,对这些 API 对象的操作,却一定都是通过访问 kube-apiserver 实现的。其中一个非常重要的原因,就是你需要 APIServer 来帮助你做授权工作。
而在 Kubernetes 项目中,负责完成授权(Authorization)工作的机制,就是 RBAC:基于角色的访问控制(Role-Based Access Control)。
如果你直接查看 Kubernetes 项目中关于 RBAC 的文档的话,可能会感觉非常复杂。但实际上,等到你用到这些 RBAC 的细节时,再去查阅也不迟。
而在这里,我只希望你能明确三个最基本的概念。
Role:角色,它其实是一组规则,定义了一组对 Kubernetes API 对象的操作权限。
Subject:被作用者,既可以是“人”,也可以是“机器”,也可以是你在 Kubernetes 里定义的“用户”。
RoleBinding:定义了“被作用者”和“角色”的绑定关系。
而这三个概念,其实就是整个 RBAC 体系的核心所在。
我先来讲解一下 Role。
实际上,Role 本身就是一个 Kubernetes 的 API 对象,定义如下所示:
首先,这个 Role 对象指定了它能产生作用的 Namepace 是:mynamespace。
Namespace 是 Kubernetes 项目里的一个逻辑管理单位。不同 Namespace 的 API 对象,在通过 kubectl 命令进行操作的时候,是互相隔离开的。
比如,kubectl get pods -n mynamespace。
当然,这仅限于逻辑上的“隔离”,Namespace 并不会提供任何实际的隔离或者多租户能力。而在前面文章中用到的大多数例子里,我都没有指定 Namespace,那就是使用的是默认 Namespace:default。
然后,这个 Role 对象的 rules 字段,就是它所定义的权限规则。在上面的例子里,这条规则的含义就是:允许“被作用者”,对 mynamespace 下面的 Pod 对象,进行 GET、WATCH 和 LIST 操作。
那么,这个具体的“被作用者”又是如何指定的呢?这就需要通过 RoleBinding 来实现了。
当然,RoleBinding 本身也是一个 Kubernetes 的 API 对象。它的定义如下所示:
可以看到,这个 RoleBinding 对象里定义了一个 subjects 字段,即“被作用者”。它的类型是 User,即 Kubernetes 里的用户。这个用户的名字是 example-user。
可是,在 Kubernetes 中,其实并没有一个叫作“User”的 API 对象。而且,我们在前面和部署使用 Kubernetes 的流程里,既不需要 User,也没有创建过 User。
这个 User 到底是从哪里来的呢?
实际上,Kubernetes 里的“User”,也就是“用户”,只是一个授权系统里的逻辑概念。它需要通过外部认证服务,比如 Keystone,来提供。或者,你也可以直接给 APIServer 指定一个用户名、密码文件。那么 Kubernetes 的授权系统,就能够从这个文件里找到对应的“用户”了。当然,在大多数私有的使用环境中,我们只要使用 Kubernetes 提供的内置“用户”,就足够了。这部分知识,我后面马上会讲到。
接下来,我们会看到一个 roleRef 字段。正是通过这个字段,RoleBinding 对象就可以直接通过名字,来引用我们前面定义的 Role 对象(example-role),从而定义了“被作用者(Subject)”和“角色(Role)”之间的绑定关系。
需要再次提醒的是,Role 和 RoleBinding 对象都是 Namespaced 对象(Namespaced Object),它们对权限的限制规则仅在它们自己的 Namespace 内有效,roleRef 也只能引用当前 Namespace 里的 Role 对象。
那么,对于非 Namespaced(Non-namespaced)对象(比如:Node),或者,某一个 Role 想要作用于所有的 Namespace 的时候,我们又该如何去做授权呢?
这时候,我们就必须要使用 ClusterRole 和 ClusterRoleBinding 这两个组合了。这两个 API 对象的用法跟 Role 和 RoleBinding 完全一样。只不过,它们的定义里,没有了 Namespace 字段,如下所示:
上面的例子里的 ClusterRole 和 ClusterRoleBinding 的组合,意味着名叫 example-user 的用户,拥有对所有 Namespace 里的 Pod 进行 GET、WATCH 和 LIST 操作的权限。
更进一步地,在 Role 或者 ClusterRole 里面,如果要赋予用户 example-user 所有权限,那你就可以给它指定一个 verbs 字段的全集,如下所示:
这些就是当前 Kubernetes(v1.11)里能够对 API 对象进行的所有操作了。
类似地,Role 对象的 rules 字段也可以进一步细化。比如,你可以只针对某一个具体的对象进行权限设置,如下所示:
这个例子就表示,这条规则的“被作用者”,只对名叫“my-config”的 ConfigMap 对象,有进行 GET 操作的权限。
而正如我前面介绍过的,在大多数时候,我们其实都不太使用“用户”这个功能,而是直接使用 Kubernetes 里的“内置用户”。
这个由 Kubernetes 负责管理的“内置用户”,正是我们前面曾经提到过的:ServiceAccount。
接下来,我通过一个具体的实例来为你讲解一下为 ServiceAccount 分配权限的过程。
首先,我们要定义一个 ServiceAccount。它的 API 对象非常简单,如下所示:
可以看到,一个最简单的 ServiceAccount 对象只需要 Name 和 Namespace 这两个最基本的字段。
然后,我们通过编写 RoleBinding 的 YAML 文件,来为这个 ServiceAccount 分配权限:
可以看到,在这个 RoleBinding 对象里,subjects 字段的类型(kind),不再是一个 User,而是一个名叫 example-sa 的 ServiceAccount。而 roleRef 引用的 Role 对象,依然名叫 example-role,也就是我在这篇文章一开始定义的 Role 对象。
接着,我们用 kubectl 命令创建这三个对象:
然后,我们来查看一下这个 ServiceAccount 的详细信息:
可以看到,Kubernetes 会为一个 ServiceAccount 自动创建并分配一个 Secret 对象,即:上述 ServiceAcount 定义里最下面的 secrets 字段。
这个 Secret,就是这个 ServiceAccount 对应的、用来跟 APIServer 进行交互的授权文件,我们一般称它为:Token。Token 文件的内容一般是证书或者密码,它以一个 Secret 对象的方式保存在 Etcd 当中。
这时候,用户的 Pod,就可以声明使用这个 ServiceAccount 了,比如下面这个例子:
在这个例子里,我定义了 Pod 要使用的要使用的 ServiceAccount 的名字是:example-sa。
等这个 Pod 运行起来之后,我们就可以看到,该 ServiceAccount 的 token,也就是一个 Secret 对象,被 Kubernetes 自动挂载到了容器的 /var/run/secrets/kubernetes.io/serviceaccount 目录下,如下所示:
这时候,我们可以通过 kubectl exec 查看到这个目录里的文件:
如上所示,容器里的应用,就可以使用这个 ca.crt 来访问 APIServer 了。更重要的是,此时它只能够做 GET、WATCH 和 LIST 操作。因为 example-sa 这个 ServiceAccount 的权限,已经被我们绑定了 Role 做了限制。
此外,我在第 15 篇文章《深入解析 Pod 对象(二):使用进阶》中曾经提到过,如果一个 Pod 没有声明 serviceAccountName,Kubernetes 会自动在它的 Namespace 下创建一个名叫 default 的默认 ServiceAccount,然后分配给这个 Pod。
但在这种情况下,这个默认 ServiceAccount 并没有关联任何 Role。也就是说,此时它有访问 APIServer 的绝大多数权限。当然,这个访问所需要的 Token,还是默认 ServiceAccount 对应的 Secret 对象为它提供的,如下所示。
可以看到,Kubernetes 会自动为默认 ServiceAccount 创建并绑定一个特殊的 Secret:它的类型是kubernetes.io/service-account-token;它的 Annotation 字段,声明了kubernetes.io/service-account.name=default,即这个 Secret 会跟同一 Namespace 下名叫 default 的 ServiceAccount 进行绑定。
所以,在生产环境中,我强烈建议你为所有 Namespace 下的默认 ServiceAccount,绑定一个只读权限的 Role。这个具体怎么做,就当作思考题留给你了。
除了前面使用的“用户”(User),Kubernetes 还拥有“用户组”(Group)的概念,也就是一组“用户”的意思。如果你为 Kubernetes 配置了外部认证服务的话,这个“用户组”的概念就会由外部认证服务提供。
而对于 Kubernetes 的内置“用户”ServiceAccount 来说,上述“用户组”的概念也同样适用。
实际上,一个 ServiceAccount,在 Kubernetes 里对应的“用户”的名字是:
而它对应的内置“用户组”的名字,就是:
这两个对应关系,请你一定要牢记。
比如,现在我们可以在 RoleBinding 里定义如下的 subjects:
这就意味着这个 Role 的权限规则,作用于 mynamespace 里的所有 ServiceAccount。这就用到了“用户组”的概念。
而下面这个例子:
就意味着这个 Role 的权限规则,作用于整个系统里的所有 ServiceAccount。
最后,值得一提的是,在 Kubernetes 中已经内置了很多个为系统保留的 ClusterRole,它们的名字都以 system: 开头。你可以通过 kubectl get clusterroles 查看到它们。
一般来说,这些系统 ClusterRole,是绑定给 Kubernetes 系统组件对应的 ServiceAccount 使用的。
比如,其中一个名叫 system:kube-scheduler 的 ClusterRole,定义的权限规则是 kube-scheduler(Kubernetes 的调度器组件)运行所需要的必要权限。你可以通过如下指令查看这些权限的列表:
这个 system:kube-scheduler 的 ClusterRole,就会被绑定给 kube-system Namesapce 下名叫 kube-scheduler 的 ServiceAccount,它正是 Kubernetes 调度器的 Pod 声明使用的 ServiceAccount。
除此之外,Kubernetes 还提供了四个预先定义好的 ClusterRole 来供用户直接使用:
cluster-admin;
admin;
edit;
view。
通过它们的名字,你应该能大致猜出它们都定义了哪些权限。比如,这个名叫 view 的 ClusterRole,就规定了被作用者只有 Kubernetes API 的只读权限。
而我还要提醒你的是,上面这个 cluster-admin 角色,对应的是整个 Kubernetes 项目中的最高权限(verbs=*),如下所示:
所以,请你务必要谨慎而小心地使用 cluster-admin。
总结
在今天这篇文章中,我主要为你讲解了基于角色的访问控制(RBAC)。
其实,你现在已经能够理解,所谓角色(Role),其实就是一组权限规则列表。而我们分配这些权限的方式,就是通过创建 RoleBinding 对象,将被作用者(subject)和权限列表进行绑定。
另外,与之对应的 ClusterRole 和 ClusterRoleBinding,则是 Kubernetes 集群级别的 Role 和 RoleBinding,它们的作用范围不受 Namespace 限制。
而尽管权限的被作用者可以有很多种(比如,User、Group 等),但在我们平常的使用中,最普遍的用法还是 ServiceAccount。所以,Role + RoleBinding + ServiceAccount 的权限分配方式是你要重点掌握的内容。我们在后面编写和安装各种插件的时候,会经常用到这个组合。
思考题
请问,如何为所有 Namespace 下的默认 ServiceAccount(default ServiceAccount),绑定一个只读权限的 Role 呢?请你提供 ClusterRoleBinding(或者 RoleBinding)的 YAML 文件。
感谢你的收听,欢迎你给我留言,也欢迎分享给更多的朋友一起阅读。
分享给需要的人,Ta购买本课程,你将得20元
生成海报并分享
赞 46
提建议
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
上一篇
25 | 深入解析声明式API(二):编写自定义控制器
下一篇
27 | 聪明的微创新:Operator工作原理解读
精选留言(64)
- huan2018-10-22kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: readonly-all-default subjects: - kind: User name: system.serviceaccount.default roleRef: kind: ClusterRole name: view apiGroup: rbac.authorization.k8s.io展开共 12 条评论63
- 喜剧。2018-11-28kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: readonly-all-default subjects: - kind: ServiceAccount name: system.serviceaccount.default roleRef: kind: ClusterRole name: view apiGroup: rbac.authorization.k8s.io 前面的朋友写的问题在于,default应该是serciveacount展开共 3 条评论38
- 无痕飞客2018-10-22老师,怎么优雅的卸载掉kubernetes呢?
作者回复: kubeadm reset
共 4 条评论32 - 单朋荣2018-12-11为什么要生命这类service account,不能直接使用role进行权限分配吗?这个中间代理的好处是啥呢?
作者回复: 所有的中间层都是为了解耦
21 - 蹦蹦2020-07-23kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: readonly-all-default subjects: - kind: ServiceAccount name: default roleRef: kind: ClusterRole name: view apiGroup: rbac.authorization.k8s.io kind是ServiceAccount,不是Group。name直接写default,不指定namespace展开共 3 条评论11
- runner2018-10-23老师还是之前的问题,现在机器上有一个手动起的容器(比如是老的业务容器),想把他加到pod里管理起来,比如pod生成的时候发现已经有这个容器了,就关联这个容器,不再创建了。有办法实现么?
作者回复: kubernetes 里最小的调度单位是pod,所以不可以的
11 - 芒果少侠2020-03-04老师,我查阅了相关资料。觉得思考题中的场景(为【所有namespace】下的【default service account】添加只读权限)无法实现。ClusterRoleBinding的subjects字段最多能允许我们给【default namespace】下的【所有service account】或者所有namespace下的所有 service account添加只读权限。不知道老师是否有其他方式实现?恳请回答,感谢。 思考题请问: 如何为所有 Namespace 下的默认 ServiceAccount(default ServiceAccount),绑定一个只读权限的 Role 呢?请你提供 ClusterRoleBinding(或者 RoleBinding)的 YAML 文件。展开共 3 条评论9
- 张振宇2019-02-23老师rbac怎么结合企业自己的ldap用户数据进行外部登录自研的web平台9
- yuanlinios2018-12-28虽然 clusterrole/clusterrolebinding 不受 namespace 限制, 但是 serviceaccount 总是存在于 namespace 下. 为一个 namespace 下的 default sa 做只读限制很容易. 那么怎么为"所有" (包括现有的和未来的) 的 namespace 下的 default sa 做只读的限制? 希望给点提示共 4 条评论7
- 艾利特-G2020-03-18关于课后思考,我看了官方文档的这个例子。 > https://kubernetes.io/docs/reference/access-authn-authz/rbac/#rolebinding-and-clusterrolebinding 暂时得出的结论是通过ClusterRoleBinding做不到让每个NameSpace下的"default" ServiceAccount拥有namespaced resources的只读权限。 这里面描述了如何在ClusterRolebinding中将ClusterRole与"manager"这个group绑定。但是这个"manager" group,是一个user的group,不是ServiceAccount的group。 我想,将ClusterRolebinding其中的subjects[0].kind属性指定为ServiceAccount,name指定为system:serviceaccount:*:default,应该是无效的吧。 如果这样不行的话,那就只有subjects[0].kind属性指定为group,然后name指定为system:serviceaccounts,这将会对所有ServiceAccount绑定"view"这个ClusterRole,包括"default"之外的ServiceAccount。这样会对所有ServiceAccount授权集群级别的只读权限,也就是不能限制在该ServiceAccount所在的Namespace下。 如果在每个Namespace下创建RoleBinding,subjects[0].kind属性指定为ServiceAccount,name指定为default,namespace指定为该namespace,则可以使每个NameSpace下的"default" ServiceAccount拥有该Namespace的只读权限。展开共 3 条评论6
- 虎虎❤️2018-10-22但在这种情况下,这个默认 ServiceAccount 并没有关联任何 Role。也就是说,此时它有访问 APIServer 的绝大多数权限。 为什么没有关联role,就会有绝大多数权限呢?有一个默认的role么,都有什么权限呢? 另外,建议在所有的namespace给default serviceaccount绑定view,是出于安全的考虑是么?展开
作者回复: 就是为了安全。role是用来做限制的,你没限制当然就撒野了。
共 4 条评论7 - 芒果少侠2020-03-04kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: readonly-all-default subjects: - kind: ServiceAccount name: default namespace: system:systemaccounts roleRef: kind: ClusterRole name: view apiGroup: rbac.authorization.k8s.io 老师,请问这样写对吗?展开共 2 条评论4
- tianfeiyu2019-08-09老师,我就想问一下,namespace 下的 default sa 没有关联任何 role,它到底有哪些权限呢?3
- 虎虎❤️2018-10-23Prior to Kubernetes 1.6, many deployments used very permissive ABAC policies, including granting full API access to all service accounts. Default RBAC policies grant scoped permissions to control-plane components, nodes, and controllers, but grant no permissions to service accounts outside the kube-system namespace (beyond discovery permissions given to all authenticated users). Quoting from https://kubernetes.io/docs/reference/access-authn-authz/rbac/#service-account-permissions 按我对官方文档的理解,RBAC策略下 default service account 是不是并没有任何权限,ABAC才会grant full access? 如果给所有namespace的default service account都赋予view 权限。会不会出现如下风险? Warning: This allows any user with read access to secrets or the ability to create a pod to access super-user credentials.展开
作者回复: 是的,这个风险肯定的
共 6 条评论3 - 诗泽2019-05-14“实际上,一个 ServiceAccount,在 Kubernetes 里对应的“用户”的名字是:” ServiceAccount 有namespace 但是用户没有,那serviceaccount 与用户的映射关系是怎样的呢,所有namespace 的default ServiceAccount 对应同一个user 吗?即system.serviceaccount.default ?2
- Pixar2018-10-26role roleBanding serviceAccount 都是 namespaced , 那跨namespace 操作会怎么样?
作者回复: 找不到对象
共 2 条评论2 - tale2021-12-01思考题正解在此: kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: readonly-all-default subjects: - kind: Group name: system:serviceaccounts apiGroup: rbac.authorization.k8s.io roleRef: kind: ClusterRole name: view apiGroup: rbac.authorization.k8s.io 关于subjects中kind的解释: 1、kind为ServiceAccount的话,官方文档明确说了必须指定namespace的,所以排除这种方式。 2、kind为User时,name中一定会带有<namespace>信息,与题目要求“所有namespace”不符,所以也排除。 3、kind为Group时,name中填system:serviceaccounts即可。很多人担心这个Group过大,可能不止包含了所有default“用户”。但经我查明,这个Group只有Get权限,所以符合View规则,即使包含了其他“用户”也无妨。展开共 1 条评论2
- 神毓逍遥2021-11-12课代表来了,最近使用部署的 AWS 上的项目,由于config 中是 aws 特质的 CLI 命令,需要重新生成一个账号与去哪先,我自己使用的 LEN 工具,图形化界面操作,非常好用;另外这张内容蛮重要的,结合自己的经验主要在,1. 学会如何创建 账号、角色、绑定,方便授权权限,2则理解 system:serviceaccount:<Namespace名字>:<ServiceAccount名字> 这个结构的含义,一定要注意,因为操作中报错,极大的概率会遇到这个问题,理解概念方便排查展开1
- ch_ort2020-05-19实测通过,所有默认default serviceaccount有了list pod的权限 #cat example-clusterrolebinding.yaml kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: example-clusterrolebinding subjects: - kind: Group name: system:serviceaccounts apiGroup: rbac.authorization.k8s.io roleRef: kind: ClusterRole name: example-clusterrole apiGroup: rbac.authorization.k8s.io展开共 2 条评论1
- Brown羊羊2019-01-28kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: example-rolebinding subjects: - kind: Group name: system:serviceaccounts roleRef: kind: ClusterRole name: view apiGroup: rbac.authorization.k8s.io展开共 1 条评论1