作者介绍:洪家铭,就职于谷歌云,Issue Killer。
写这篇文章的动机是,我发现网上对k8s用户安全机制分析的文章几乎都落入对一般人很不友好的两个类别:要么集中介绍k8s使用的某些具体安全协议细节,要么集中介绍k8s中某个安全机制的概念。看了一圈下来总有些只见树木不见森林的感觉。所以,我这篇文章主要是从整体上介绍k8s的安全机制是如何实现的,特别是“信任的链条”是如何传递的。
在一个系统中的安全系统究竟需要完成什么目标?一句话说就是:控制“谁”可以对“什么”做“哪些操作”。其实这句话还隐藏了一个前提,就是安全系统需要能够识别确认一个尝试/正在和系统交互的用户是“谁”。接下的文章就从这个前提入手,介绍k8s的安全模型。
在接下来的阅读前,读者至少需要了解:
•k8s的整体master-worker框架和其中apiServer和etcd的地位和作用(文章1[1],文章2[2])。•k8s中namespace,secret等API资源的概念(文章[3])•非对称加密的应用场景,比如CA证书[4]
1. 发出请求的是谁?
首先需要确定k8s含有哪些身份模型,好比工厂的安保人员对于一个要求开门的请求方可能有如下分类:人类,动物,无人驾驶汽车,对于不同的模型自然有不同的流程去验证。k8s集群中的身份只有两种:用户(User)和服务账号(Service Account)。
为什么需要这两种呢?因为与k8s交互的实际上有两类东西,一是真实的人类,另一个是程序。一个k8s中的user数量一般较少,添加/删除这一类账户往往伴随着人员调动,商业合作等技术之外的变化。而供程序使用的service account则往往数量相对较多,贯穿在整个服务的开发和维护过程中,并且不应该因为人员变化等技术外原因变化。
1.1 用户(User)账户
对于User账户,k8s没有打算附带一套员工管理系统而是采取了极简主义,通过创建k8s集群时自带的管理员(admin)权限(几乎)手动管理master中的凭证文件,并且将每个凭证文件和一个字符串对应起来,只要用户请求中有信息(一般来自本地保存的.kube/config文件中)能够证明自己有任意一个凭证文件的授权,那么这个请求就被认为是一个合法用户发出的,同时这个用户的用户名就是凭证文件对应的字符串。同时,在证书中还可以加入用户所在的组(group)的信息,k8s可以据此认为user在一个组中。
X509客户端证书的一部分:Subject中O(organization)的值代表用户组,CN (common name)代表用户名
凭证文件有三种,分别是X509客户端证书,静态token文件,静态账号密码文件。可以参考这篇文章[5]去详细了解。
user账户管理的本质是管理员将凭证文件和一个字符串对应
1.2 服务账号(Service Account)
Service Account贯穿了服务的开发维护全部流程,比如当有pod需要运行时,必须以一个service account的身份去运行他。这很好理解,一个Pod不应该区分究竟是开发的张三,运维的李四,还是已经离职的王五正在操作自己。由于其重要且常见,k8s提供了创建和管理service account的API,将每一个service account当作一个object存在etcd中。Service account也是像user一样,利用的CA证书进行认证,但是证书保存在etcd,而不是单个文件中。当任何用户或代码可以访问某个serivce account资源时,它们便可以使用etcd中存储的证书以这个service account的名义与apiService交互。
同时重要的一点,service account有namespace这一属性。这很好理解,web和game的namespace中可能都有dev这一个service accout,我们希望可以将同名的service account通过不同的命名空间隔开。但是对于用户(user),前面介绍过k8s只将其对应在一个字符串上而已,可以认为user是全局的。
service account和secret都是储存在etcd中的object
1.3 User与Service Account的关系
这是比较令人疑惑的地方,也是驱使我写这篇文章的最初动力。从前面的介绍看,user和service account两者完全是割裂的:user由凭证文件认证,而service account是一种k8s的api资源。那么当张三使用本地的.kube/config文件作为一个user登录了集群后,他可以使用任意的service account吗?答案肯定是否定的,但是在哪里规定了张三能使用哪些service account呢?换句话说,user是如何与某些service account联系起来的呢?答案是:两者是由一系列存储在etcd中的api资源(Cluster)RoleBinding和(Cluster)Role联系起来的。
service account也是一种资源(resource)。一个(Cluster)Role能否使用某个service account定义在(Cluster)Role.Rules中
举个例子,根据官方文档[6]使用kubeadm创建一个k8s集群,默认账户的状态和配置是怎样的呢?为什么可以使用默认账户以默认service account(default)创建pod呢?我们进行如下探索:
1.首先可以查看登录时使用的证书信息,可以发现context.user=kubernetes-admin
。2.但是在集群中使用kubectl get rolebindings --all-namespaces
或 kubectl get clusterrolebindings
都没有发现相应的用户信息。这时,猜想授权是以用户组的形式发生的而不是单独用户。3.按照前文截图中的方法查看本地证书中的用户组信息,发现Subject: O = system:masters, CN = kubernetes-admin
。进一步发现kubectl get clusterrolebindings -o yaml
中存在一个binding有.roleRef.name=cluster-admin
,.subjects[0].kind=Group
和 .subjects[0].name=system:masters
。4.最后使用kubectl get clusterrole cluster:admin
查看其权限,发现其拥有所有资源的所有操作权限,包括使用service account运行pod的权限。
cluster-admin拥有所有权限
综上,这个例子中user和service account发生联系的路线为:
1.用户kubernetes-admin属于用户组system:masters (证书中定义)2.用户组system:masters拥有ClusterRole cluster-admin (ClusterRoleBinding中定义)3.ClusterRole中cluster-admin拥有所有service account的使用权限(ClusterRole中定义)
所有和k8s系统的交互都是通过apiServer进行HTTP(S),用户请求到达apiServer后集群会基于以上的方式对请求进行身份认证。
2. “谁”可以对“什么”做“哪些操作”。
当认证完成,“谁”的问题被明确后,后剩下的‘对“什么”做“哪些操作”’就十分简单了。k8s默认拒绝用户(user/service account)的任何操作请求,只有用户通过(cluster)rolebinding拥有的(cluster)role中定义了相应权限,这个请求才会被apiServer认为是合法,进入后续的处理过程。
以上就是用户安全管理模型的简介,在我写这篇文章中还发现了其它一些不错的相关链接,有兴趣的读者可以参考阅读:
•k8s集群各种用户认证方式的详细操作介绍:文章[7]•签发X509证书的具体方法和其他的安全管理简介:文章[8]•什么是JWT(认证方式的一种):文章[9]•Api资源(Cluster)RoleBinding和(Cluster)Role官方文档及示例[10](英文)•对多租户用户行为的进一步安全管理概述:文章[11]
引用链接
[1]
文章1: https://link.zhihu.com/?target=https://www.infoq.cn/article/KNMAVdo3jXs3qPKqTZBw
[2]
文章2: https://zhuanlan.zhihu.com/p/40927470
[3]
文章: https://zhuanlan.zhihu.com/p/115903242
[4]
CA证书: https://www.zhihu.com/question/24294477/answer/74783418
[5]
这篇文章: https://zhuanlan.zhihu.com/p/43237959
[6]
官方文档: https://link.zhihu.com/?target=https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/
[7]
文章: https://zhuanlan.zhihu.com/p/97797321
[8]
文章: https://zhuanlan.zhihu.com/p/113853969
[9]
文章: https://link.zhihu.com/?target=https://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html
[10]
官方文档及示例: https://link.zhihu.com/?target=https://kubernetes.io/docs/reference/access-authn-authz/rbac/
[11]
文章: https://zhuanlan.zhihu.com/p/102467110