作者:馬辛·瓦西奧內克(Marcin Wasiucionek)
引言
在Kubernetes安全領域,一個常見的建議是讓容器以非root用戶身份運行。但是,在容器中以root身份運行,實際會帶來哪些安全隱患呢?在Docker鏡像和Kubernetes配置中,這一最佳實踐常常被重點強調。在Kubernetes清單文件中,可以通過以下代碼實現:
securityContext:runAsNonRoot: true # 確保runAsUser指定的用戶ID不是0。如果用戶ID設置為0,Pod將無法運行。runAsUser: 1000 # 將容器中運行的進程的用戶ID設置為1000。
你可以只設置runAsUser
字段,而不包含runAsNonRoot
。然而,如果你指定了runAsNonRoot
,那么也必須定義runAsUser
。
容器以root身份運行為何危險??
當容器以root身份運行時,會出現多種潛在的攻擊途徑。讓我們通過實驗來探究一下。
搭建實驗環境🛠?
為了說明以root身份運行容器的風險,我們將使用兩個相似的容器進行實際測試:
- 一個默認以root身份運行的
alpine:3.20.2
容器。 - 一個自定義的
alpine:3.20.2
容器,配置為以非root用戶身份運行。
以下是用于創建非root容器的Dockerfile:
# 使用Alpine鏡像作為基礎鏡像
FROM alpine:3.20.2# 添加一個名為'nonroot'的非root用戶,用戶ID為1000
RUN adduser -D -u 1000 nonroot# 將后續命令的用戶設置為'nonroot'
USER nonroot
# 可選:設置默認命令
CMD ["sh"]
在本地環境中,我們使用Minikube 1.32.0和Kubernetes版本v1.28.3。通過以下命令構建鏡像,并使其在Minikube集群中可用:
eval $(minikube docker-env)
docker build. -t nonroot:1.0.0
接下來,我們在Kubernetes中部署這些容器。在這個演示中,我使用hostPath
卷來測試權限,不過強烈建議不要在家庭實驗室之外使用hostPath
(我會在另一篇文章中解釋原因)!
root用戶的Pod定義如下:
apiVersion: v1
kind: Pod
metadata:name: root
spec:containers:- name: alpineimage: alpine:3.20.2command: ["/bin/sh", "-c"]args: ["while true; do sleep 100; done"]volumeMounts:- mountPath: /hostname: hostvolumes:- name: hosthostPath:path: /etc/kubernetes/manifests # 掛載節點上的靜態Pod目錄type: Directory
非root用戶的Pod定義如下:
apiVersion: v1
kind: Pod
metadata:name: nonroot
spec:containers:- name: alpineimage: nonroot:1.0.0command: ["/bin/sh", "-c"]args: ["while true; do sleep 100; done"]securityContext:runAsUser: 1000 # 確保容器以用戶ID為1000的非root用戶運行volumeMounts:- mountPath: /hostname: hostvolumes:- name: hosthostPath:path: /etc/kubernetes/manifests # 掛載節點上的靜態Pod目錄type: Directory
測試潛在攻擊🧪
- 下載惡意軟件🦠
一種常見的攻擊方式是下載并執行惡意軟件包。我通過嘗試從dev.to獲取一些數據來測試這一點。
由于容器中最初未安裝curl
,我嘗試安裝它:
在root容器中安裝成功,但在非root容器中安裝失敗。讓我們嘗試獲取數據。
在root容器中操作正常,但在非root容器中被阻止。這表明以非root用戶身份運行可以有效地緩解這種攻擊。其他措施,如使用只讀文件系統,可以進一步增強安全性,我將在未來的文章中介紹。
- 訪問主機資源🔒
我將一個主機目錄掛載到了Pod(再次強調 —— 請不要在家庭實驗室之外這樣做!)。通過這種訪問權限,攻擊者可以嘗試訪問包含靜態Pod manifests 的目錄,并嘗試運行惡意Pod(盡管下載惡意鏡像應該會被集群策略阻止)。這可以通過向靜態清單目錄(通常是Kubernetes節點上的/etc/kubernetes/manifests
)添加新的清單文件來實現。有了這種訪問權限,攻擊者可以嘗試:- 通過部署攔截集群內網絡流量的Pod來執行中間人攻擊,并捕獲敏感信息。
- 部署帶有反向shell的后門Pod(你可以在https://www.revshells.com/ 找到示例),接受來自黑客機器的連接。
- 運行一個Pod,將包含敏感數據的卷中的數據傳輸到外部實體。
- 通過從ETCD存儲中讀取機密信息來擴大攻擊范圍,并進一步滲透基礎設施。
- 使用你的資源運行加密貨幣挖掘程序以獲取經濟利益。
讓我們使用以下清單文件部署一個加密貨幣挖掘程序的模擬:
apiVersion: v1
kind: Pod
metadata:name: crypto - miner
spec:containers:- name: miner - containerimage: busyboxcommand: ["/bin/sh", "-c", "while true; do echo 'Mining in progress...'; sleep 5; done"]
并從兩個Pod中添加靜態Pod文件:
如你所見,非root用戶的Pod上的命令被拒絕。它在root用戶的Pod上成功運行,并將加密貨幣挖掘程序的清單文件添加到了靜態Pod目錄中。集群中創建了這個Pod嗎?
是的,它在集群中運行,并且在出現故障或重啟時將被重新調度。
攻擊者通過訪問節點上的hostPath
還可以做的另一件事是讀取主機上的/etc/passwd
文件。該文件不包含明文密碼,但它讓攻擊者了解系統中存在的用戶。結合其他一些數據源和/etc/shadow
,這些信息可能會讓攻擊者進一步利用系統。
- 權限提升🚫
你難道不能將非root用戶切換為root用戶,然后做同樣的事情嗎?讓我們試試。
不,你不能。從非root用戶切換到root用戶的嘗試失敗了,這表明在沒有sudo
權限的情況下,權限提升是不可行的。因此,如果非root用戶不在sudoers
列表中,風險就會降低。
如何預防?🛡?
為了防止與以root身份運行容器相關的安全問題,請遵循以下最佳實踐:
- 使用非root用戶:始終在你的Docker容器中定義并使用非root用戶。🧑?💻
- 利用Kubernetes安全上下文:使用Kubernetes安全上下文(Security Context)指定容器執行的用戶。🔐
結論?
在Kubernetes中以非root用戶身份運行容器,通過緩解常見的攻擊途徑,顯著增強了安全性。希望本文能讓你了解這一最佳實踐的重要性。
參考文獻
- Understanding the Docker USER instruction
- Kubernetes Security Context
- Alpine Docker images on Docker Hub
- Kubernetes Pod Security Standards
- https://medium.com/@marcin.wasiucionek/why-is-running-as-root-in-kubernetes-containers-dangerous-e5f1a116080e