使用”用户扮演”来实现Kubernetes里的最小权限

最近我给使用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

K8S中文社区微信公众号

评论 抢沙发

登录后评论

立即登录