客座文章最初由Juanjo Ciarlante在Bitnami上发表
https://docs.bitnami.com/tutorials/simplify-kubernetes-resource-access-rbac-impersonation/
介绍
Kubernetes,像任何其他安全系统一样,支持以下概念:
授权--处理用户对资源访问的过程--总是一个挑战,特别是当访问由团队成员身份或项目成员身份控制时。两个关键挑战是:
由于Kubernetes组(group)成员关系是由身份提供程序(Identity Provider,IdP)从外部处理到API本身的,因此集群管理员需要与身份提供程序管理员交互来设置这些组成员关系,这使得工作流可能很麻烦。身份提供者可能根本不提供组成员关系,从而迫使集群管理员按用户处理访问,即Kubernetes RoleBindings包含允许最终用户(end-user)的“完整”列表。
在本教程中,我们提出了一种使用现有Kubernetes授权特性“扮演”组成员身份的方法--可以通过团队、项目或你可能需要的任何其他聚合。
假设和前提条件
本文假设你:
Kubernetes身份验证概述
身份验证是任何集群管理员都应该遵循的策略的关键部分,以保护Kubernetes集群基础设施,并确保只有被允许的用户才能访问它。
下面简要介绍一下Kubernetes如何进行身份验证。主要有两类用户:
用户ID包含在对Kubernetes API的每次调用中,而该API又是由访问控制机制授权的。
采用OIDC进行身份验证很常见,因为它提供了单点登录(Single-Sign-On,SSO)体验,不过有些组织可能仍然使用最终用户x509证书,因为无需任何外部IdP干预就可以颁发这些证书。然而,这些共同的方法带来了以下挑战:
用户现在已经通过身份验证,我们需要看看如何授权他们使用Kubernetes集群。
Kubernetes授权和RBAC概述
在网上有许多关于Kubernetes RBAC的资源。如果你不完全熟悉这些概念,我推荐这个关于在Kubernetes中揭开RBAC神秘面纱的很棒的教程。要了解关于如何在集群中配置RBAC的更多信息,请参阅本教程。Kubernetes RBAC允许指定:
A)允许的SUBJECTS,对 B)资源种类进行VERBS(可以选择缩小到特定的资源名称)
在上面的模型中,B)被实现为一个Kubernetes Role(或ClusterRole),而A)-> B)的绑定被建模为一个Kubernetes RoleBinding(或ClusterRoleBinding),如下图所示:
使用扮演的(impersonated)“虚拟用户”来控制访问
Kubernetes RBAC包含一个特殊的impersonate(扮演)动词,可用于允许Subjects(即Users、Groups、ServiceAccounts)获得其他Kubernetes用户或组身份。
由于这些获得的身份不一定需要存在--还记得Kubernetes控制平面本身没有用户或组存储--我们将在本文中将它们称为“虚拟用户(virtual-users)”。此特性允许将“虚拟用户”设置为“角色帐户”安全主体。例如:
alice@example.com,作为应用前端(app-fe)团队的成员,可以扮演虚拟用户app-fe-user
bob@example.com,作为应用程序后端(app-be)团队的成员,可以扮演虚拟用户app-be-user
可以创建RBAC规则来允许这些“虚拟用户”访问他们需要的Kubernetes资源,如下图所示:
如上所示,利用现有的Kubernetes RBAC特性,授权处理分为:
实际的扮演操作是通过在Kubernetes API调用的头文件指定的,这是方便的由kubectl通过:
kubectl --as <user-to-impersonate> ...
kubectl --as <user-to-impersonate> --as-group <group-to-impersonate> ...
提示:没有-as参数的kubectl -as -group…是无效的。为了简化CLI的使用,本文建议使用上面的第一种形式,通过将用户扮演为表示用户组或团队成员的“虚拟用户”进行建模。
如下图所示的例子,用户“alice@example.com”可以通过重载kubectl CLI使用下面的命令轻松扮演虚拟团队用户“app-fe-user”:
kubectl --as app-fe-user ...
使用RBAC规则的工作示例
现在已经“创建”了虚拟用户,让我们看看RBAC规则在实践中的一个工作示例。对于这个用例,假设以下场景:
提示:为了简单起见,我们将使用现有的Kubernetes ClusterRoles(可用于命名空间作用域的角色绑定)来实现上述访问规则。
步骤1:准备RBAC清单
下面的例子使用k14s/ytt作为模板语言实现了这个想法(你可以找到下面的ytt源代码和生成的YAML):
https://get-ytt.io/
https://github.com/bitnami-labs/k8s-training-resources/blob/master/rbac-impersonate/fe_team.yml
https://github.com/bitnami-labs/k8s-training-resources/blob/master/rbac-impersonate/generated/fe_team.yaml
#@ load("impersonate.lib.yml",
#@ "ImpersonateCRBinding", "ImpersonateCRole", "RoleBinding"
#@ )
https://github.com/k14s/ytt
#@ members = ["alice@example.com", "alanis@example.com"]
#@ prod_namespace = "prod-app-fe"
#@ stag_namespace = "staging-app-fe"
#@ dev_namespace = "dev-app-fe"
#@ team_user = "app-fe-user"
#! Add impersonation bindings <members> -> team_user
--- #@ ImpersonateCRBinding(team_user, members)
--- #@ ImpersonateCRole(team_user)
#! Allow *team_user* virtual-user respective access to below namespaces
--- #@ RoleBinding(team_user, prod_namespace, "view")
--- #@ RoleBinding(team_user, stag_namespace, "edit")
--- #@ RoleBinding(team_user, dev_namespace, "admin")
得到的YAML输出可以通过kubectl进行推送,像往常一样执行以下命令:
$ ytt -f . | kubectl apply -f- [ --dry-run=client ]
用户身份(本例中为“alice@example.com”)可以由本文开头讨论的任何身份验证机制提供。
步骤2:测试
在将RBAC资源推到集群之后,alice@example可以使用kubectl auth can-i…命令来验证设置。例如:
$ kubectl auth can-i delete pod -n dev-app-fe
no
$ kubectl --as app-fe-user auth can-i delete pod -n dev-app-fe
yes
$ kubectl --as foo-user auth can-i get pod
Error from server (Forbidden): users "foo-user" is forbidden: User "alice@example.com" cannot impersonate resource "users" in API group "" at the cluster scope
这完全是为Kubernetes的sudo的感觉,不是吗?
步骤3:将扮演设置保存到Kubernetes配置文件中
为了预先设置扮演的配置,可以在用户的KUBECONFIG文件的“user:”条目中添加一些没有广泛文档化的字段:
- name: alice@example.com@CLUSTER
user:
as: app-fe-user
auth-provider:
config:
client-id: <...>.apps.googleusercontent.com
client-secret: <...>
id-token: <... JWT ...>
idp-issuer-url: https://accounts.google.com
refresh-token: 1//<...>
name: oidc
这个持久的设置是有用的,因为它避免了需要:
审计跟踪
Kubernetes扮演在审计跟踪方面设计得很好,因为API调用使用完整的原始身份(user)和扮演用户(impersonatedUser)进行日志记录。下面的代码片段显示了一个kube-audit日志跟踪条目,它是由kubectl –as app-fe-user get pod -n dev-app-fe触发的:
{
"kind": "Event",
"apiVersion": "audit.k8s.io/v1",
"level": "Request",
"auditID": "032beea1-8a58-434e-acc0-1d3a0a98b108",
"stage": "ResponseComplete",
"requestURI": "/api/v1/namespaces/dev-app-fe/pods?limit=500",
"verb": "list",
"user": {
"username": "alice@example.com",
"groups": ["system:authenticated"]
},
"impersonatedUser": {
"username": "app-fe-user",
"groups": ["system:authenticated"]
},
"sourceIPs": ["10.x.x.x"],
"userAgent": "kubectl/v1.18.6 (linux/amd64) kubernetes/dff82dc",
"objectRef": {
"resource": "pods",
"namespace": "dev-app-fe",
"apiVersion": "v1"
},
"responseStatus": {
"metadata": {},
"code": 200
},
"requestReceivedTimestamp": "2020-07-24T21:25:50.156032Z",
"stageTimestamp": "2020-07-24T21:25:50.161565Z",
"annotations": {
"authorization.k8s.io/decision": "allow",
"authorization.k8s.io/reason": "RBAC: allowed by RoleBinding \"rb-app-fe-user-admin\" of ClusterRole \"admin\" to User \"app-fe-user\""
}
}
挑剔的读者还会注意到,上面的“user”字段只有与用户身份相关的“username”,因为“system:authenticated”显然是一个通用的组值。
总结
通过现有的Kubernetes RBAC特性,集群管理员可以创建由角色用户扮演的虚拟用户安全主体,以建模“角色帐户”授权方案。这种方法提供了与Kubernetes安全配置相关的许多好处,如下所示:
有用的链接