K8s RBAC 提供了三个具有隐藏权限的权限,这些权限可能会被恶意使用。了解如何控制其使用。
译自 Kubernetes RBAC Permissions You Might Not Know About, but Should,作者 Dmitrii Bubnov。
基于角色的访问控制 (RBAC ) 是 Kubernetes (K8s) 中的默认访问控制方法。此模型使用特定动词对权限进行分类,以定义与资源的允许交互。在此系统中,三个鲜为人知的权限 —— escalate, bind 和 impersonate ——可以覆盖现有的角色限制,授予对受限区域的未经授权的访问权限,公开机密数据,甚至允许完全控制集群。本文解释了这些强大的权限,提供了对其功能的见解以及减轻其相关风险的指导。
如果你还不熟悉Kubernetes RBAC 的关键概念 ,请参阅 Kubernetes 文档 。
但是,我确实需要简要描述一个与本文直接相关的重要的概念:角色。这描述了特定命名空间内对 K8s 资源的访问权限和可用操作。角色由规则列表组成。规则包括动词——已定义资源的可用操作。
以下是从 K8s 文档中获取的一个角色的示例,该角色授予对 Pod 的读取访问权限:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: view-pod
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "watch", "list"]
诸如 get
、watch
和 list
的动词通常使用。但是,也存在更有趣的动词。
对于更精细和复杂的权限管理,K8s RBAC 具有以下动词:
-
escalate
: 允许用户创建和编辑角色,即使他们最初没有这样做权限。 -
bind
: 允许用户创建和编辑角色绑定和集群角色绑定,而无需分配权限。 -
impersonate
: 允许用户模拟其他用户并在集群或不同组中获得其权限。可以使用此动词访问关键数据。
下面,你将更详细地了解这些动词。但首先,创建一个测试命名空间并将其命名为
rbac
:
kubectl create ns rbac
然后,在刚创建的 rbac
命名空间中创建一个名为 privsec
的测试服务帐户 (SA) 资源:
kubectl -n rbac create sa privesc
你将在本教程的其余部分中使用它们。
默认情况下,Kubernetes RBAC API 不允许用户通过简单地编辑角色或角色绑定来提升权限。即使禁用了 RBAC 授权器,此限制也在 API 级别起作用。唯一的例外是如果角色具有
Escalate
动词。
在下图中,仅具有 update
和 patch
权限的 SA 无法向角色添加新动词。但是,如果你添加一个具有 Escalate
动词的新角色,则可以实现。
向角色添加 Escalate
动词允许用户更改角色权限并添加新动词。
创建一个角色,允许在该命名空间中只读访问 Pod 和角色:
kubectl -n rbac create role view --verb=list,watch,get --resource=role,pod
将此角色绑定到 SA privsec
:
kubectl -n rbac create rolebinding view --role=view --serviceaccount=rbac:privesc
检查是否可以更新角色:
kubectl auth can-i update role -n rbac --as=system:serviceaccount:rbac:privesc
SA 可以读取角色,但不能编辑角色。
创建一个新角色,允许在 rbac
命名空间中编辑角色:
kubectl -n rbac create role edit --verb=update,patch --resource=role
将此新角色绑定到 SA privsec
:
kubectl -n rbac create rolebinding edit --role=edit --serviceaccount=rbac:privesc
检查是否可以更新角色:
kubectl auth can-i update role -n rbac --as=system:serviceaccount:rbac:privesc
检查是否可以删除角色:
kubectl auth can-i delete role -n rbac --as=system:serviceaccount:rbac:privesc
SA 现在可以编辑角色,但不能删除角色。
为了实验的准确性,请使用 JSON Web 令牌 (JWT) 检查 SA 功能:
TOKEN=$(kubectl -n rbac create token privesc --duration=8h)
从配置中删除旧的身份验证参数,因为 Kubernetes 将首先检查用户的证书 ,如果它已经知道证书,则不会检查令牌。
cp ~/.kube/config ~/.kube/rbac.conf
export KUBECONFIG=~/.kube/rbac.conf
kubectl config delete-user kubernetes-admin
kubectl config set-credentials privesc --token=$TOKEN
kubectl config set-context --current --user=privesc
此角色显示你可以编辑其他角色:
kubectl -n rbac get role edit -oyaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: edit
namespace: rbac
rules:
- apiGroups:
- rbac.authorization.k8s.io
resources:
- roles
verbs:
- update
- patch
尝试添加一个新动词,list
,你已经在只读视图角色中使用过它:
kubectl -n rbac edit role edit
OK
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: edit
namespace: rbac
rules:
- apiGroups:
- rbac.authorization.k8s.io
resources:
- roles
verbs:
- update
- patch
- list # the new verb we added
成功。
现在,尝试添加一个新动词,delete ,您在其他角色中未使用的:
kubectl -n rbac edit role edit
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: edit
namespace: rbac
rules:
- apiGroups:
- rbac.authorization.k8s.io
resources:
- roles
verbs:
- update
- patch
- delete # trying to add a new verb
这确认了 Kubernetes 不允许用户或服务帐户添加新权限,如果他们没有这些权限,则只能在用户或服务帐户绑定到具有此类权限的角色时。
因此,扩展 privesc SA 权限。通过使用管理员配置并添加一个具有 escalate 动词的新角色来执行此操作:
KUBECONFIG=~/.kube/config kubectl -n rbac create role escalate --verb=escalate --resource=role
现在,将 privesc SA 绑定到新角色:
KUBECONFIG=~/.kube/config kubectl -n rbac create rolebinding escalate --role=escalate --serviceaccount=rbac:privesc
检查您现在是否可以向角色添加新动词:
kubectl -n rbac edit role edit
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: edit
namespace: rbac
rules:
- apiGroups:
- rbac.authorization.k8s.io
resources:
- roles
verbs:
- update
- patch
- delete # the new verb we added
role.rbac.authorization.k8s.io/edit edited
现在可以了。用户可以通过编辑现有角色来提升 SA 权限。这意味着 escalate 动词授予适当的管理员权限,包括命名空间管理员甚至集群管理员的权限。
bind 动词允许用户编辑 RoleBinding 或 ClusterRoleBinding 对象以进行权限提升,类似于 escalate,它允许用户编辑 Role 或 ClusterRole。
在下图中,具有具有 update、patch 和 create 动词的角色绑定的 SA 无法添加 delete,直到您使用 bind 动词创建新角色。
使用 bind 动词添加新角色允许用户扩展角色的绑定权限。
仔细了解其工作原理。
将 kubeconfig 文件更改为管理员:
export KUBECONFIG=~/.kube/config
删除旧角色和绑定:
kubectl -n rbac delete rolebinding view edit escalate
kubectl -n rbac delete role view edit escalate
允许 SA 查看和编辑命名空间中的角色绑定和 pod 资源:
kubectl -n rbac create role view --verb=list,watch,get --resource=role,rolebinding,pod
kubectl -n rbac create rolebinding view --role=view --serviceaccount=rbac:privesc
kubectl -n rbac create role edit --verb=update,patch,create --resource=rolebinding,pod
kubectl -n rbac create rolebinding edit --role=edit --serviceaccount=rbac:privesc
创建单独的角色来处理 pod,但仍不绑定角色:
kubectl -n rbac create role pod-view-edit --verb=get,list,watch,update,patch --resource=pod
kubectl -n rbac create role delete-pod --verb=delete --resource=pod
将 kubeconfig 更改为 SA privesc 并尝试编辑角色绑定:
export KUBECONFIG=~/.kube/rbac.conf
kubectl -n rbac create rolebinding pod-view-edit --role=pod-view-edit --serviceaccount=rbac:privesc
rolebinding.rbac.authorization.k8s.io/pod-view-edit created
新角色已成功绑定到 SA。请注意,pod-view-edit 角色包含动词和资源,这些动词和资源已通过绑定 view 和 edit 的角色绑定到 SA。
现在,尝试绑定具有新动词的角色,delete,该动词在绑定到 SA 的角色中缺失:
kubectl -n rbac create rolebinding delete-pod --role=delete-pod --serviceaccount=rbac:privesc
error: failed to create rolebinding: rolebindings.rbac.authorization.k8s.io "delete-pod" is forbidden: user "system:serviceaccount:rbac:privesc" (groups=["system:serviceaccounts" "system:serviceaccounts:rbac" "system:authenticated"]) is attempting to grant RBAC permissions not currently held:
{APIGroups:[""], Resources:["pods"], Verbs:["delete"]}
即使您有权编辑和创建角色绑定,Kubernetes 也不允许这样做。但您可以使用 bind 动词修复此问题。使用管理员配置执行此操作:
KUBECONFIG=~/.kube/config kubectl -n rbac create role bind --verb=bind --resource=role
role.rbac.authorization.k8s.io/bind created
KUBECONFIG=~/.kube/config kubectl -n rbac create rolebinding bind --role=bind --serviceaccount=rbac:privesc
rolebinding.rbac.authorization.k8s.io/bind created
再次尝试使用新 delete 动词创建角色绑定:
kubectl -n rbac create rolebinding delete-pod --role=delete-pod --serviceaccount=rbac:privesc
rolebinding.rbac.authorization.k8s.io/delete-pod created
现在可以了。因此,使用 bind 动词,SA 可以将任何角色绑定到自身或任何用户。
K8s 中的 impersonate 动词类似于 Linux 中的 sudo。如果用户拥有 impersonate 访问权限,他们可以以其他用户身份进行身份验证并代表他们运行命令。kubectl 工具具有 --as、--as-group 和 --as-uid 选项,分别允许以不同的用户、组或通用唯一标识符 (UUID) 运行命令。如果用户被授予模拟权限,他们将成为命名空间管理员,或者——如果命名空间中存在 cluster-admin 服务帐户——甚至成为集群管理员。
impersonate 动词有助于检查委派给用户的 RBAC 权限。管理员应根据模板执行命令 kubectl auth can-i --as=$USERNAME -n $NAMESPACE $VERB $RESOURCE
并检查授权是否按设计工作。
在此示例中,SA 不会通过仅执行 kubectl -n rbac get pod
来获取 rbac 命名空间中 Pod 的信息。但如果存在具有 impersonate 动词的角色,则可以实现:
kubectl auth can-i get pod -n rbac --as=system:serviceaccount:rbac:privesc
yes
KUBECONFIG=~/.kube/config kubectl -n rbac create sa impersonator
serviceaccount/impersonator created
现在,创建一个具有 impersonate 动词和角色绑定的角色:
KUBECONFIG=~/.kube/config kubectl -n rbac create role impersonate --resource=serviceaccounts --verb=impersonate --resource-name=privesc
(看看上面的指令中的 --resource-name 参数:它只允许模拟为 privesc SA。)
role.rbac.authorization.k8s.io/impersonate created
KUBECONFIG=~/.kube/config kubectl -n rbac create rolebinding impersonator --role=impersonate --serviceaccount=rbac:impersonator
rolebinding.rbac.authorization.k8s.io/impersonator created
获取具有 impersonate 动词的角色的 Pod 信息。
创建一个新上下文:
TOKEN=$(KUBECONFIG=~/.kube/config kubectl -n rbac create token impersonator --duration=8h)
kubectl config set-credentials impersonate --token=$TOKEN
User "impersonate" set.
kubectl config set-context impersonate@kubernetes --user=impersonate --cluster=kubernetes
Context "impersonate@kubernetes" created.
kubectl config use-context impersonate@kubernetes
Switched to context "impersonate@kubernetes".
检查权限:
kubectl auth can-i --list -n rbac
Resources Non-Resource URLs Resource Names Verbs
selfsubjectaccessreviews.authorization.k8s.io [] [] [create]
selfsubjectrulesreviews.authorization.k8s.io [] [] [create]
...
serviceaccounts []
除了角色中指定的 impersonate 之外,不存在其他附加权限。但如果你将 impersonator SA 作为 privsec SA 进行 impersonate,则会获得 privsec SA 拥有的相同权限:
kubectl auth can-i --list -n rbac --as=system:serviceaccount:rbac:privesc
Resources Non-Resource URLs Resource Names Verbs
roles.rbac.authorization.k8s.io [] [edit] [bind escalate]
selfsubjectaccessreviews.authorization.k8s.io [] [] [create]
selfsubjectrulesreviews.authorization.k8s.io [] [] [create]
pods [] [] [get list watch update patch delete create]
...
rolebindings.rbac.authorization.k8s.io [] [] [list watch get update patch create bind escalate]
roles.rbac.authorization.k8s.io [] [] [list watch get update patch create bind escalate]
configmaps [] [] [update patch create delete]
secrets [] [] [update patch create delete]
因此,impersonate SA 拥有其自身的所有权限以及它所 impersonate 的 SA 的所有权限,包括命名空间管理员拥有的权限。
escalate、bind 和 impersonate 动词可用于创建灵活的权限,从而实现对 K8s 基础设施的访问的精细管理。但这些动词也为恶意使用打开了大门,因为在某些情况下,它们使用户能够以管理员权限访问关键的基础设施组件。
三种做法可以帮助你减轻这些动词被滥用或恶意使用的潜在危险:
- 定期检查 RBAC 清单。
- 在 Role 和 ClusterRole 清单中使用 resourceNames 字段。
- 使用外部工具来监视角色。
依次查看每种做法。
为了防止未经授权的访问和 RBAC 配置错误,请定期检查你的集群 RBAC 清单:
kubectl get clusterrole -A -oyaml | yq '.items[] | select (.rules[].verbs[] | contains("esalate" | "bind" | "impersonate")) | .metadata.name'
kubectl get role -A -oyaml | yq '.items[] | select (.rules[].verbs[] | contains("esalate" | "bind" | "impersonate")) | .metadata.name'
为了限制使用 escalate、bind、impersonate 或任何其他动词,请在 Role 和 ClusterRole 清单中配置 resourceNames 字段。在那里,你可以(并且应该)输入可以使用的资源的名称。
以下是一个 ClusterRole 的示例,它允许使用名为 edit 和 view 的 roleRef 创建 ClusterRoleBinding:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: role-grantor
rules:
- apiGroups: ["rbac.authorization.k8s.io"]
resources: ["clusterroles"]
verbs: ["bind"]
resourceNames: ["edit","view"]
你可以对 escalate 和 impersonate 执行相同的操作。
请注意,在 bind 的情况下,管理员为角色设置权限,并且用户仅在 resourceNames 中被允许这样做时才能将该角色绑定到自己。使用 escalate,用户可以在角色中编写任何参数,并成为命名空间或集群的管理员。因此,bind 限制了用户,而 escalate 为他们提供了更多选项。如果你需要授予这些权限,请记住这一点。
考虑使用自动系统来监控创建或编辑具有可疑内容的角色,例如 Falco 或 Tetragon。
您还可以将 Kubernetes 审计日志重定向到日志管理系统,例如 Gcore 托管日志记录,这对于分析和解析 K8s 日志非常有用。为防止意外删除资源,请创建一个具有 delete
动词的单独服务帐户,并允许用户仅模拟该服务帐户。这是最小权限原则。为简化此过程,您可以使用 kubectl 插件 kubectl-sudo。
在 Gcore,我们使用这些方法来使我们的 托管 Kubernetes 服务 更加安全;我们建议所有客户也这样做。使用托管服务并不能保证您的服务在默认情况下完全安全,但在 Gcore,我们尽一切可能确保客户的保护,包括鼓励 RBAC 最佳实践。
escalate
、bind
和 impersonate
动词允许管理员灵活地管理对 K8s 基础设施的访问,并允许用户提升其权限。这些是功能强大的工具,如果滥用,可能会对 K8s 集群造成重大损害。仔细查看这些动词的任何用法,并确保遵循最小权限规则。用户必须拥有操作所需的最低权限,不得更多。