访问控制:基于角色的权限控制
todo
一、RBAC是什么
RBAC,是Role-Based Access Control的缩写,即基于角色的访问控制。在Kubernetes项目中,负责完成认证和授权工作的就是RBAC,它主要由三个最基本的内容组成:
- Subject:使用者,即可以是“人”,也可以是“机器”,还可以是我们在Kubernetes中定义的“用户”。
- Role:角色,它就是一组权限规则,定义了一组可以对Kubernetes API对象进行操作的权限。
- RoleBinding:角色绑定,它定义了“使用者”和“角色”的绑定关系。
二、如何使用RBAC
2.1、定义Role
在Kubernetes项目中,Role就是一个API对象,它的定义如下:
1 |
|
首先,我们在名为mynamespace的Namespace下,定义了一个名为my-role的Role对象。
然后,我们通过rules字段为my-role这个Role对象定义了权限规则。如上,这条规则的含义是:允许“使用者”,对mynamespace下面的Pod对象,进行get、watch和list操作。
2.2、定义RoleBinding
在有了Role后,我们就可以将Role绑定到使用者上了,也即进行RoleBinding。在kubernetes项目中,RoleBinding也是一个API对象,它的定义如下:
1 |
|
首先,我们通过subjects字段声明了“使用者”的信息,它的类型是User,它的名字是my-user。
然后,通过roleRef字段,我们直接引用了之前创建的Role对象。
这样,我们就完成了role和"使用者"的绑定关系,是不是很简单。
三、理解Subject
在上面的例子中,我们是不是会有这样的困惑:
在Kubernets中,并没有User类型的API对象。而且,我们也没有创建过User,那这个User到底是从哪里来的呢?
其实,Kubernetes中的“User”,就是“用户”,它只是授权系统中的一个逻辑概念。它需要通过外部认证服务(比如,Keystone)来提供。此外,我们还可以直接给API Server指定一个用户名、密码文件。这样,Kubernetes的授权系统,就可以从这个文件中找到对应的“用户”了。
在大多数时候,我们其实不会使用“用户”这个功能。在私有环境中,我们只要使用Kubernetes提供的内置“用户”,就足够了。而这个内置用户,就是ServiceAccount。
3.1、实践ServiceAccount
3.1.1、定义ServiceAccount
首先,我们定义一个ServiceAccount,它也是一个API对象,定义如下:
1 |
|
可以看到,一个最简单的 ServiceAccount 对象只需要 Name 和 Namespace 这两个最基本的字段。
3.1.2、定义Role
然后,我们直接使用上面定义的Role对象:
1 |
|
3.1.3、定义RoleBinding
接着,我们定义一个RoleBinding,将Role绑定到ServiceAccount,如下:
1 |
|
可以看到,在这个 RoleBinding 对象里,subjects 字段的类型(kind),不再是一个 User,而是一个名为 my-sa 的 ServiceAccount。
3.1.4、创建对象
最后,我们用 kubectl 命令创建这三个对象:
1 |
|
3.1.5、查看ServiceAccount
当创建完成后,我们可以查看一下这个 ServiceAccount 的详细信息:
1 |
|
可以看到,Kubernetes 会为这个 ServiceAccount 自动创建并分配一个 Secret 对象(上述 ServiceAcount 定义里最下面的 secrets 字段)。而这个 Secret对象,就是这个 ServiceAccount 对应的、用来跟 APIServer 进行交互的授权文件,我们一般称它为:Token。Token 文件的内容一般是证书或者密码,它以一个 Secret 对象的方式保存在 Etcd 当中。
3.1.6、Pod使用ServiceAccount
用户有了,也进行了授权,那如何使用这个用户呢?
此时,Kubernetes中的主角Pod就该登场了,我们来看如下定义:
1 |
|
在这里,我们定义了 Pod 要使用的 ServiceAccount 的名字是:my-sa。这样,这个Pod就可以以my-sa这个内置用户的身份对APIServer进行一些操作了。
3.1.7、ServerAccount的真面目
等这个 Pod 运行起来之后,我们就可以看到,该 ServiceAccount 的 token,也就是Secret 对象,被 Kubernetes 自动挂载到了容器的 /var/run/secrets/kubernetes.io/serviceaccount 目录下,如下所示:
1 |
|
这时候,我们可以通过 kubectl exec 查看到这个目录里的文件:
1 |
|
如上所示,容器里的应用,就可以使用这个 ca.crt 来访问 APIServer 了。更重要的是,此时它只能够做 GET、WATCH 和 LIST 操作。因为 my-sa 这个 ServiceAccount 的权限,已经被我们绑定的 Role 做了限制。
3.2、默认ServiceAccount
到这里,我们可能会有这样的疑问:
我们平时定义Pod时并没有指定ServiceAccount,那是不是说Pod就不能对APIServer进行任何操作了呢?
并不是。在Kubernetes中,如果一个Pod没有声明ServiceAccount,那么Kubernetes 就会自动在它的 Namespace 下创建一个名为 default 的默认 ServiceAccount,然后分配给这个 Pod。
在默认情况下,这个默认 ServiceAccount 并没有关联任何 Role。也就是说,此时它有访问 APIServer 的绝大多数权限。当然,这个访问所需要的 Token,还是默认 ServiceAccount 对应的 Secret 对象为它提供的,如下所示:
1 |
|
可以看到,Kubernetes 会自动为默认 ServiceAccount 创建并绑定一个特殊的 Secret:它的类型是kubernetes.io/service-account-token;它的 Annotation 字段,声明了kubernetes.io/service-account.name=default,即这个 Secret 会跟同一 Namespace 下名叫 default 的 ServiceAccount 进行绑定。
注:在生产环境中,强烈建议为所有 Namespace 下的默认 ServiceAccount,绑定一个只读权限的 Role。
3.3、用户组
除了“用户”(User)外,Kubernetes 还拥有“用户组”(Group)的概念,也就是一组“用户”的意思。如果我们为 Kubernetes 配置了外部认证服务的话,这个“用户组”的概念就会由外部认证服务提供。而对于 Kubernetes 的内置“用户”ServiceAccount 来说,这个“用户组”的概念也同样适用。
3.3.1、ServiceAccount组
实际上,一个 ServiceAccount,在 Kubernetes 里对应的“用户”的名字是:
1 |
|
而它对应的内置“用户组”的名字,就是:
1 |
|
也就是说,ServiceAccount所属的Namespace就是它的组。
3.3.2、ServiceAccount组的应用
比如,现在我们可以在 RoleBinding 里定义如下的 subjects:
1 |
|
这就意味着这个 Role 的权限规则,作用于 mynamespace 里的所有 ServiceAccount。这就用到了“用户组”的概念。
四、理解ClusterRole
4.1、从rules字段说起
我们先来看一下rules字段,它由如下五个字段构成:
- apiGroups(string array):声明规则是为哪些API组下的资源定义的。如上,空(“”)表示核心API组。
- resources(string array):定义规则在哪些资源上生效。如上,Pods表示将规则应用的Pod对象上。
- verbs(string array):定义可以对资源进行哪些操作。如上,表示可以对资源进行get、watch和list等操作。
- resourceNames(string array):是一个可选字段。它是一个资源名称的白名单,即允许规则在哪些特定的资源上生效。
- nonResourceURLs(string array):定义了用户可访问的URL。它支持使用“*s”的形式,但只作用于整个url的最后一部分,因为nonResourceURL是没有namespace的,所以该形式,只适用于ClusterRole。一个规则可以在API资源(比如,Pod和Secret)上生效,也可以在非资源的URL(比如,/api)上生效,但不能同时在两者上生效。
从这里可以看出,在kubernetes项目中,还存在一种ClusterRole对象,那么ClusterRole是用来干什么的呢?
4.2、ClusterRole & ClusterRoleBinding
我们需要知道的是,Role 和 RoleBinding 对象都是 Namespaced 对象(Namespaced Object),即它们的权限规则仅在它们自己的 Namespace 内有效,roleRef 也只能引用当前 Namespace 里的 Role 对象。
那么,对于非 Namespaced(Non-namespaced)对象(比如:Node),或者,某一个 Role 想要作用于所有的 Namespace 的时候,我们又该如何去做授权呢?
这时候,我们就必须要使用 ClusterRole 和 ClusterRoleBinding 这两个组合了。这两个 API 对象的用法跟 Role 和 RoleBinding 完全一样。只不过,它们的定义里,没有了 Namespace 字段,如下所示:
1 |
|
通过如上ClusterRole 和 ClusterRoleBinding 的组合,名为 my-user 的用户,就拥有对所有 Namespace 里的 Pod 进行 GET、WATCH 和 LIST 操作的权限。
4.3、系统保留的ClusterRole
在 Kubernetes 中已经内置了很多个为系统保留的 ClusterRole,它们的名字都以 system: 开头。我们可以通过 kubectl get clusterroles
查看到它们。
一般来说,这些系统 ClusterRole,是绑定给 Kubernetes 系统组件对应的 ServiceAccount 使用的。比如,其中一个名叫 system:kube-scheduler 的 ClusterRole,定义的权限规则是 kube-scheduler(Kubernetes 的调度器组件)运行所需的必要权限。我们可以通过如下指令查看这些权限的列表:
1 |
|
这个 system:kube-scheduler 的 ClusterRole,就会被绑定给 kube-system Namesapce 下名叫 kube-scheduler 的 ServiceAccount,它正是 Kubernetes 调度器的 Pod 声明使用的 ServiceAccount。
除此之外,Kubernetes 还提供了四个预先定义好的 ClusterRole 来供用户直接使用:
- cluster-admin
- addmin
- edit
- view
通过它们的名字,我们应该能大致猜出它们都定义了哪些权限。比如,这个名叫 view 的 ClusterRole,就规定了使用者只有 Kubernetes API 的只读权限。
我们需要注意的是,上面这个 cluster-admin 角色,对应的是整个 Kubernetes 项目中的最高权限(verbs=*),如下所示:
1 |
|
所以,务必要谨慎而小心地使用 cluster-admin。
4.4、权限设置
在 Role 或者 ClusterRole 里面,如果要赋予用户 my-user 所有权限,那我们就可以给它指定一个 verbs 字段的全集,如下所示:
1 |
|
这些就是当前 Kubernetes(v1.11)里能够对 API 对象进行的所有操作了。
类似地,Role 对象的 rules 字段也可以进一步细化。比如,我们可以只针对某一个具体的对象进行权限设置,如下所示:
1 |
|
这个例子就表示,这条规则的“被作用者”,只对名叫“my-config”的 ConfigMap 对象,有进行 GET 操作的权限。
五、小结
在这篇文章中,我们主要讨论了Kubernetes项目中的RBAC机制,我们需要掌握如下几个概念:
- Subject:使用者,即认证用户,它可以是“用户”,也可以是“用户组”,在Kubernetes中通常使用的是ServiceAccount(Kubernetes系统的内置用户)。
- Role:角色,即一组权限规则,它可以分为Role和ClusterRole,前者的作用范围是特定的Namespace,后者的作用范围是所有的Namespace。
- Rolebinding:角色绑定,用于将“角色”与“使用”绑定,也即为用户分配权限。