Day 15 與 Day 16 介紹了容器錯誤設定可能造成的權限提升與主機存取風險。當容器由 K8S 管理時,類似的設定仍可能破壞隔離。今天透過兩個實驗,觀察 hostPath 掛載,以及 privileged 與 hostPID 的組合,如何讓容器接觸 Node 的資源。
先看一下 K8S 的文件讓我們知道是什麼參數可以讓它把目錄掛在容器裡面的:
從這邊我們也可以證明 K8S 裡面也會有掛載根目錄的風險,在 Day 23 的 Lab 中刻意將 hostPath.path 設為 /,並讓測試 Pod 執行於 Worker .183,我們用實作來觀察 HostPath 的風險性:
先用 mount 觀察掛載資訊,找出 /host 這個掛載點,再進一步檢查其來源與內容。
用以下指令確認掛載進來的根目錄屬於哪一台 Node?
ls /host
cat /host/etc/hostname

/host 下的目錄結構符合 Linux 系統根目錄,且 /host/etc/hostname 的內容與 Worker .183 相符,可以簡單推敲出這個根目錄是 Worker .183 的。
Lab 已將 Node 的根目錄以可讀寫方式掛載到 /host,且容器行程具備對應的檔案存取權限。接著使用 chroot /host 切換根目錄,並建立檔案,驗證對 Node 檔案系統的寫入能力。
chroot /host id
chroot /host touch /root/abc.txt

可以看到我們很輕鬆地在 183 上面建立了一個 txt 檔案,因此即便在 K8S 上面依然會碰到掛載根目錄的風險。
接下來改用另一個測試 Pod,啟用 spec.hostPID: true,並在容器的 securityContext 中設定 privileged: true。
這次使用 privileged + hostPID 的組合搭配 nsenter 來達成容器逃逸,我們先沿用 Day 16 的檢查方式先檢查我們的權限:
grep CapEff /proc/self/status
ls /dev | grep -E '^(sd|vd|nvme|dm-)'
ps | head -3

根據截圖顯示,容器行程具有廣泛的有效 capabilities,/dev 中也出現多個磁碟與 device-mapper 裝置節點。此外,ps 可見主機的 systemd 與啟用 hostPID: true 的設定相符。
接著以 Node 的 PID 1 為目標,使用 nsenter 在指定的 namespace 中執行指令,觀察主機名稱、執行身分與可存取的檔案:
nsenter -t 1 -m -u -i -n -p -- hostname
nsenter -t 1 -m -u -i -n -p -- id
nsenter -t 1 -m -u -i -n -p -- ls -l /root

這邊解釋一下甚麼是 nsenter ?我們可以依據 Linux manual page 看到官方是這樣說明的:
nsenter(1) — Linux manual page
nsenter 的常見用途之一,是讓管理者或除錯工具在目標行程的 namespace 中檢查問題。
官方手冊也提到 nsenter 會在你指定的 Linux namespace 裡執行程式;如果沒有指定程式,就啟動一個 shell。
這邊補充一下幾個基本的 nsenter 會用到的參數。
nsenter -m -u -i -n -p -t "pid" bash ;
-a, --all 進入目標行程的所有可用 namespace
-m, --mount[=<file>] 進入目標行程的 mount namespace
-u, --uts[=<file>] 進入目標行程的 UTS namespace
-i, --ipc[=<file>] 進入目標行程的 IPC namespace
-n, --net[=<file>] 進入目標行程的 network namespace
-p, --pid[=<file>] 在目標 PID namespace 中執行後續程式
-t, --target <pid> 指定用來取得 namespace 等資訊的目標行程 PID。
回到指令面,透過參數我們可以進入 host 主機的 PID 1 這個 Process 的 namespace 裡面,因為容器行程原本就以 UID 0 執行,並具備進入目標 namespace 所需的權限。nsenter 讓新執行的程式使用 Node PID 1 的指定 namespace;執行後仍呈現 root 身分:
nsenter -m -u -i -n -p -t 1 bash ;

以上就是今天的內容,會發現即使容器由 K8S 管理,掛載主機根目錄或過度授予特權,仍可能破壞容器與 Node 之間的隔離。不論是開發還是維運團隊都應該知道資訊安全的重要性,否則建立起來的 K8S 很容易被駭客攻擊。
感謝大家的收看,我們明天見!