最近我给使用Dex和AD的一个客户实现了一套认证解决方案,我会在另外一篇博客更加详细地记录这部分内容(在我们的案例里,为Dex增加了很多有趣的新机制),在本博客里,我要重点介绍我们设计和实现的一个小巧而强悍的RBAC设置。
kubernetes目前支持”用户扮演(Impersonation)”机制。我们来回顾一下我们是如何通过”用户扮演”来创建用户和组的配置,来实现即使是管理员权限也会被限制的最小集群访问权限。从而在保证较低复杂程度的情况下,提高意外执行某些不希望发生的操作的门槛。
更新(8/5/19),我的一个同事很厉害,他实现了一个叫做kubectl-sudo项目,就是利用这个点子实现的 kubectl 插件。如果你感兴趣,那么快来看一看吧!(它只支持提升到管理员权限,但是很容易修改)。
他们想做什么
在我们示例的kubernetes集群中,每个应用团队作为独立的租户都拥有他们自己的namespace。我们的开发人员对于kubernetes不是特别熟悉,所以当我们给他们管理员权限以后,他们的实际场景也不过是查看一下应用状态等,而不是做出某些修改。在我们的例子里,只有一个开发团队”app-team”。
我们也有一个运维团队”ops-team”,它们是整个集群的管理者。可即使他们有这么大的权力,他们平时做的也更多的是查看状态而不是进行修改。所以如果我们可以设计一种工具,让每个用户默认只能查看集群里的状态,但是允许他们在有需要的时候“升级”自己权限(就像Unix系操作系统的’sudo’命令一样)来做一些变更。
让我们走进”用户扮演”的世界。
通过”用户扮演”,我们设计一个每个namespace都拥有一个”admin”角色的系统,但是我们不会把这个权限直接授予应用团队。取而代之的是,我们提供了一个名为app-team-admin的用户绑定到它们之上。并且我们默认为应用团队开启了view-only权限,这样他们只能以只读权限执行常规kubectl命令。如果他们想要在集群里做某些变更,那么就需要通过 –as=app-team-admin 作为kubectl参数进行admin”用户扮演”来执行。
类似地,我们为运维团队也设计了相同的系统,利用已经存在的ClusterRole cluster-admin并绑定到cluster-admin用户来为运维团队成员提供”用户扮演”的能力。
为运维团队进行配置
为用户创建credential不在本文范围,并且我早创建了kubeconfig(alice-cfg)来通过用户alice访问集群,里面包含了她所属的运维团队信息。
首先,我们创建ClusterRoleBinding来让运维团队成员能够访问到内置的ClusterRole view,这为每个用户赋予了默认的只读权限:
apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: cluster-admin-view roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: view subjects: - apiGroup: rbac.authorization.k8s.io kind: Group name: ops-team
现在我们创建允许用户cluster-admin拥有集群cluster-admin ClusterRole权限的ClusterRoleBinding。记着我们并不是把cluster-admin直接绑定到运维团队上:
apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: cluster-admin-crb roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-admin subjects: - apiGroup: rbac.authorization.k8s.io kind: User name: cluster-admin
最终我们创建了一个名为cluster-admin-impersonator的ClusterRole,允许”用户扮演”cluster-admin用户,这样可以通过ClusterRoleBinding将权限绑定到运维团队的每个成员上:
apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: cluster-admin-impersonator rules: - apiGroups: [""] resources: ["users"] verbs: ["impersonate"] resourceNames: ["cluster-admin"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: cluster-admin-impersonate roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-admin-impersonator subjects: - apiGroup: rbac.authorization.k8s.io kind: Group name: ops-team
现在我们创建所有的RBAC资源,并通过alice-cfg进行测试:
$ kubectl apply -f ops-team/ clusterrolebinding.rbac.authorization.k8s.io/cluster-admin-view created clusterrolebinding.rbac.authorization.k8s.io/cluster-admin-crb created clusterrole.rbac.authorization.k8s.io/cluster-admin-impersonator created clusterrolebinding.rbac.authorization.k8s.io/cluster-admin-impersonate created $ KUBECONFIG=alice-kfg kubectl get configmaps No resources found. $ KUBECONFIG=alice-kfg kubectl create configmap my-config --from-literal=test=test Error from server (Forbidden): configmaps is forbidden: User "alice" cannot create resource "configmaps" in API group "" in the namespace "default"
这样我们可以执行读取命令(我们并未在default namespace里创建configmap),但是不能通过alice-cfg创建任何资源。当我们对集群做变更的时候让我们”用户扮演”cluster-admin就可以(注意kubectl的–as=cluster-admin参数):
KUBECONFIG=alice-kfg kubectl --as=cluster-admin create configmap my-config --from-literal=test=test configmap/my-config created
成功!
这种”用户扮演”操作的最厉害的地方所有操作都会记录在kubernetes的审计日志里,这样我可以查看到原始的用户登录、”用户扮演”cluster-admin和执行变更等记录。
为应用团队进行配置
对应用团队的配置非常类似于对运维团队的配置,但是权限作用在他们自己的namespace范围内,而不是整集群范围:
apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: app-team-admin namespace: app-team roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: admin subjects: - apiGroup: rbac.authorization.k8s.io kind: User name: app-team-admin --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: app-team-view namespace: app-team roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: view subjects: - apiGroup: rbac.authorization.k8s.io kind: Group name: app-team --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: app-team-impersonator rules: - apiGroups: [""] resources: ["users"] verbs: ["impersonate"] resourceNames: ["app-team-admin"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: app-team-admin-impersonate roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: app-team-impersonator subjects: - apiGroup: rbac.authorization.k8s.io kind: Group name: app-team
为此我也早已准备了另一个用户bob的kubeconfig,叫bob-cfg:
$ kubectl apply -f ops-team/ rolebinding.rbac.authorization.k8s.io/app-team-admin created rolebinding.rbac.authorization.k8s.io/app-team-view created clusterrole.rbac.authorization.k8s.io/app-team-impersonator created clusterrolebinding.rbac.authorization.k8s.io/app-team-admin-impersonate created $ KUBECONFIG=bob-kfg kubectl get configmaps Error from server (Forbidden): configmaps is forbidden: User "bob" cannot list resource "configmaps" in API group "" in the namespace "default" $ KUBECONFIG=bob-kfg kubectl get configmaps -n app-team No resources found. $ KUBECONFIG=bob-kfg kubectl create configmap my-config --from-literal=test=test -n app-team --as=app-team-admin configmap/my-config created
我希望这篇文章能够成为一个关于对集群进行最小化权限设置,且同时保证简单易用的工作流和审计能力的好教程。如果你对本文或者未来的文章有任何想法,欢迎在Twitter上与我交流,
作者:John Harris
来源:容器时代,https://mp.weixin.qq.com/s/4hB91ez-af4tB6fuv4J9Eg