RBAC

Kubernetes 中所有的 API 对象,都保存在 Etcd 里。对这些 API 对象的操作,都是通过访问 kube-apiserver 实现的。
其中一个非常重要的原因,就是你需要 APIServer 来帮助你做授权工作。
而在 Kubernetes 项目中,负责完成授权(Authorization)工作的机制,就是 RBAC:基于角色的访问控制(Role-Based Access Control)。

K8s 在 1.3 版本中发布了 alpha 版的基于角色的访问控制 RBAC (Role-based Access Control) 的授权模式。
从 1.6 版本之后官方推荐使用RBAC 的授权方式,因为它比较灵活,而且能够很好地实现资源隔离效果。
相对于基于属性的访问控制 ABAC(Attribute-based Access Control) ,RBAC主要是引入了 角色(Role) 和 角色绑定(RoleBinding) 的抽象概念。
在ABAC中,K8s集群中的访问策略只能跟用户直接关联;而在RBAC中,访问策略可以跟某个角色关联,具体的用户在跟一个或多个角色相关联。

RBAC 引入了 4 个新的顶级资源对象 : Role 、 ClusterRole 、 RoleBinding 和 ClusterRoleBinding 。
同其他API 资源对象 一样,用户可以使用 kubectl 或者 API 调用等方式操作这些资源对象。
在这里插入图片描述
RBAC 具有如下优势:
• 对集群中的资源和非资源权限均有完整的覆盖。
• 整个 RBAC 完全由 几个 API 对象完成,同其他 API 对象一样 ,可以用 kubectl 或 API 进行操作。
• 可以在运行时进行调整,无须重新启动 API Server。
*注: 要使用 RBAC 授权模式 ,需要在 API Server 的启动 参数中 加上 --authorization-mode=RBAC

我们需要明确三个最基本的概念。
• Role:角色,它其实是一组规则,定义了一组对 Kubernetes API 对象的操作权限。
• Subject:被作用者,既可以是“人”,也可以是“机器”,也可以是你在 Kubernetes 里定义的“用户”。
• RoleBinding:定义了“被作用者”和“角色”的绑定关系。
这三个概念,其实就是整个 RBAC 体系的核心所在。

Role

Role,翻译成角色。角色本身会包含一系列的权限规则,表明某个角色能做哪些事情。
比如管理员可以操作所有的资源,而有些角色只允许读取资源。某个 namespace 的用户只能修改该 namespace的内容
角色和 pods、services 这些资源一样,可以通过 API 创建和删除,因此用户可以非常灵活地根据需求创建角色。

在RBAC API中,一个角色包含了一套表示一组权限的规则。 权限以纯粹的累加形式累积(没有”否定”的规则)。
角色可以由命名空间(namespace)内的Role对象定义,而整个Kubernetes集群范围内有效的角色则通过ClusterRole对象实现。
一个Role对象只能用于授予对某一单一命名空间中资源的访问权限。

以下示例描述了”default”命名空间中的一个Role对象的定义,用于授予对pod的读访问权限:
在这里插入图片描述

rules 中的参数说明如下:

apiGroups: 支持的API组列表,例如 “batch”、“extensions”、“apps” 等。
resources: 支持的资源对象列表,例如 pods、 deployments、 jobs等。
verbs: 对资源对象 的操作方法列表 , 例如 get、 watch、 list、 delete、 replace、 patch 等
resourceNames: 支持使用 resourceNames: [“xxx”]来指定具体的一个或多个资源

这个 Role 对象的 rules 字段,就是它所定义的权限规则。
在上面的例子里,这条规则的含义就是:允许“被作用者”,对 default 下面的 Pod 对象,进行 get、watch 和 list 操作。

那么,这个具体的“被作用者”又是如何指定的呢?这就需要通过 RoleBinding 来实现了。

RoleBinding

RoleBinding 将一个角色中定义的各种权限授予一个或者一组用户。
角色绑定包含了一组相关主体(即subject, 包括用户——User、用户组——Group、或者服务账户——Service Account)以及对被授予角色的引用。
在命名空间中可以通过RoleBinding对象授予权限,而集群范围的权限授予则通过ClusterRoleBinding对象完成。
RoleBinding可以引用在同一命名空间内定义的Role对象。

下面示例中定义的RoleBinding对象在”default”命名空间中将”pod-reader”角色授予用户”jane”。 这一授权将允许用户”jane”从”default”命名空间中读取pod。
在这里插入图片描述

在 Kubernetes 中,其实并没有一个叫作“User”的 API 对象。我们在前面和部署使用 Kubernetes 的流程里,既不需要 User,也没有创建过 User。
那这个User到底怎么来的呢?
实际上,Kubernetes 里的“User”,也就是“用户”,只是一个授权系统里的逻辑概念。它需要通过外部认证服务,比如 Keystone,来提供。
或者,你也可以直接给 APIServer 指定一个用户名、密码文件。那么 Kubernetes 的授权系统,就能够从这个文件里找到对应的“用户”了。
当然,在大多数私有的使用环境中,我们只要使用 Kubernetes 提供的内置“用户”,就足够了。SA

我们注意到有一个 roleRef 字段。引用的正是我们前面定义的 Role (pod-reader).
RoleBinding 对象的作用就是建立 roleRef 和 subject 之间的绑定关系
要注意, Role 和 RoleBinding 都是 Namespaced 对象(NamespacedObject),
它们对权限的限制规则仅在自己的 Namespace 内有效,roleRef 也只能引用当前 Namespace 里的 Role 对象。

对于非 Namespaced(Non-namespaced)对象(比如:Node),或者某一个 Role 想要作用于所有的 Namespace 的时候,我们又该如何去做授权呢?

ClusterRole和ClusterRoleBinding

这时候,我们就必须要使用 ClusterRole 和 ClusterRoleBinding 这两个组合了。
这两个 API 对象的用法跟 Role 和 RoleBinding 完全一样。只不过,它们的定义里,没有了 Namespace 字段.

ClusterRole对象可以授予与Role对象相同的权限,但由于它们属于集群范围对象, 也可以使用它们授予对以下几种资源的访问权限:
• 集群范围资源(例如节点,即node)
• 非资源类型endpoint(例如”/healthz”)
• 跨所有命名空间的命名空间范围资源(例如pod,需要运行命令kubectl get pods --all-namespaces来查询集群中所有的pod)

在这里插入图片描述
在这里插入图片描述

上面的例子定义了名叫 example-user 的用户,拥有对所有 Namespace 里的 Pod 进行 GET、WATCH 和 LIST 操作的权限。

在 Role 或者 ClusterRole 里面,如果要赋予用户 example-user 所有权限,那你就可以给它指定一个 verbs 字段的全集,如下所示:
在这里插入图片描述

ServiceAccount

在大多数时候,我们其实都不太使用“用户”这个功能,而是直接使用 Kubernetes 里的“内置用户”。
这个由 Kubernetes 负责管理的“内置用户”,就是 ServiceAccount。
定义一个 ServiceAccount。它的 API 对象非常简单,如下所示:
在这里插入图片描述

可以看到,一个最简单的 ServiceAccount 对象只需要 Name 和 Namespace 这两个最基本的字段。
然后,我们通过编写 RoleBinding 的 YAML 文件,来为这个 ServiceAccount 分配权限:
在这里插入图片描述

我们将Role, SA, RoleBinding这三个对象创建出来:

[root@master ~]# kubectl apply -f role.yaml 
[root@master ~]# kubectl apply -f sa.yaml 
[root@master ~]# kubectl apply -f sa-role-bind.yaml

查看sa
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

可以看到,Kubernetes 会为一个 ServiceAccount 自动创建并分配一个 Secret 对象
这个 Secret,就是这个 ServiceAccount 对应的、用来跟 APIServer 进行交互的授权文件,我们一般称它为:Token
Token 文件的内容一般是证书或者密码,它以一个 Secret 对象的方式保存在 Etcd 当中。

这时候,用户的 Pod,就可以声明使用这个 ServiceAccount 了,比如下面这个例子:
在这里插入图片描述

运行这个 Pod:

[root@master ~]# kubectl apply -f nginx-sa.yaml

查看 Pod 信息:

[root@master ~]# kubectl describe pod sa-token-test

在这里插入图片描述

可以看到,该 ServiceAccount 的 Token,被 Kubernetes 自动挂载到了容器的 /var/run/secrets/kubernetes.io/serviceaccount 目录下

通过 kubectl exec 查看到这个目录里的文件:

如上所示,容器里的应用,就可以使用这个 ca.crt 来访问 APIServer 了。
更重要的是,此时它只能够做 GET、WATCH 和 LIST 操作。因为 example-sa 这个 ServiceAccount 的权限,已经被我们绑定了 Role 做了限制。

如果上面连接Pod报错:

[root@master ~]# kubectl exec -it sa-token-test  /bin/bash
error: unable to upgrade connection: Forbidden (user=system:anonymous, verb=create, resource=nodes, subresource=proxy)

原因:
使用 kubectl exec 命令时,会转到kubelet,需要对 apiserver 调用 kubelet API 的授权。跟 kubectl 的其他命令有些区别。

解决方案:

[root@master ~]# kubectl create clusterrolebinding system:anonymous   --clusterrole=cluster-admin   --user=system:anonymous

注意: 这个权限给得太大了,很危险,因为 cluster-admin 具有集群最高权限。

可以只对 anonymous 用户绑定必要权限即可,修改为:

[root@master ~]# kubectl create clusterrolebinding kube-apiserver:kubelet-apis --clusterrole=system:kubelet-api-admin --user=system:anonymous 

ServiceAccount - default

每个Namespace 下有个名叫 default 的默认 ServiceAccount
如果一个 Pod 没有声明 serviceAccountName,Kubernetes 会将 default 分配给这个 Pod。
在这种情况下,这个默认 ServiceAccount 并没有关联任何 Role。此时它有访问 APIServer 的绝大多数权限。
当然,这个访问所需要的 Token,还是默认 ServiceAccount 对应的 Secret 对象为它提供的,如下所示:
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

可以看到,Kubernetes 会自动为默认 ServiceAccount (default) 创建并绑定一个特殊的 Secret:
它的类型是kubernetes.io/service-account-token;
Annotation 字段 - kubernetes.io/service-account.name:default,表示这个 Secret 会跟同一 Namespace 下名叫 default 的 ServiceAccount 进行绑定。

所以,在生产环境中,我强烈建议你为所有 Namespace 下的默认 ServiceAccount,绑定一个只读权限的 Role。

Subject - Group

除了“用户”(User),Kubernetes 还拥有“用户组”(Group)的概念,也就是一组“用户”的意思。
如果你为 Kubernetes 配置了外部认证服务的话,这个“用户组”的概念就会由外部认证服务提供。
对于 Kubernetes 的内置“用户”ServiceAccount 来说,上述“用户组”的概念也同样适用。
ServiceAccount,在 Kubernetes 里对应的“用户”的名字是: system:serviceaccount: <ServiceAccount名字>
它对应的内置“用户组”的名字,就是:system:serviceaccounts:<Namespace名字>

比如,现在我们可以在 RoleBinding 里定义如下的 subjects:
在这里插入图片描述

# 这就意味着这个 Role 的权限规则,作用于 default 里的所有 ServiceAccount
# 如果不指定 Namespace , 则表示作用于系统中所有的ServiceAccount

在 Kubernetes 中已经内置了很多个为系统保留的 ClusterRole,它们的名字都以 system: 开头。你可以通过 kubectl get clusterroles 查看到它们。
一般来说,这些系统 ClusterRole,是绑定给 Kubernetes 系统组件对应的 ServiceAccount 使用的。
比如,其中一个名叫 system:kube-scheduler 的 ClusterRole,定义的权限规则是 kube-scheduler(Kubernetes 的调度器组件)运行所需要的必要权限。
在这里插入图片描述

Kubernetes 还提供了四个预先定义好的 ClusterRole 来供用户直接使用:

• cluster-admin            # 集群超级管理
• admin                    # 管理
• edit                     # 读写
• view                     # 只读

需要提醒的是,上面这个 cluster-admin 角色,对应的是整个 Kubernetes 项目中的最高权限(verbs=*),如下所示:
在这里插入图片描述

请务必小心使用此权限

尽管权限的被作用者可以有很多种(比如,User、Group 等),但在我们平常的使用中,最普遍的用法还是 ServiceAccount。
所以,Role + RoleBinding + ServiceAccount 的权限分配方式是需要重点掌握的内容。

Reference

  1. 张磊 深入剖析kubernetes
Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐