在生產環境中以 root 身份運行容器是最常見的——也是最危險的——誤設定之一。它無聲地擴大了每個工作負載的攻擊面,大多數團隊直到事件發生才意識到這一點。
「以 Root 身份運行」的實際含義
根據預設,許多容器映像(特別是最小化或舊版的映像)在容器內以 UID 0 身份執行其主程序。由於容器與其他容器和主機共享主機核心,容器內的 root 與完全隔離虛擬機上的 root 不同——但它仍然遠比應有的要強大得多。如果攻擊者在 root 擁有的容器內實現程式碼執行,他們就會獲得:
- 對掛載到容器中的任何檔案的完全讀寫存取,無論預期的權限如何
- 安裝套件、修改二進位檔或篡改應用程式狀態的能力
- 在核心或執行時漏洞可被利用時,通往容器逃逸的更容易路徑
- 當與配置不當的捲結合時提高槓桿作用,例如已掛載的 Docker socket 或主機檔案系統路徑
即使沒有核心漏洞,容器內的 root 存取也會大幅增加任何應用層級漏洞(SSRF、反序列化漏洞、任意檔案寫入等)的影響半徑。
為什麼這在協調環境中更為重要
在 Kubernetes 叢集中,root 容器加上過多的 Linux 能力或寬鬆的安全內容可以讓攻擊者:
- 修改
/proc或/sys,以影響主機 - 如果啟用了
hostPID、hostNetwork或hostIPC,則提升權限 - 濫用已掛載的服務帳戶令牌在整個叢集中橫向移動
- 如果設定了
privileged: true或授予了SYS_ADMIN等危險能力,則逃逸到節點
root 使用者本身不一定是漏洞——它是 root 加上過於寬鬆的核心能力、主機掛載或命名空間共享的組合,將受限制的洩露轉變為全叢集級別的洩露。
實用加固步驟
1. 在映像中設定非 Root 使用者
在 Dockerfile 中明確定義非 root 使用者,而不是依賴預設值:
FROM node:20-slim
RUN useradd --uid 10001 --shell /usr/sbin/nologin appuser
USER appuser
2. 在協調器級別強制執行
不要只信任映像——在執行時強制執行政策。在 Kubernetes 中,使用 securityContext:
securityContext:
runAsNonRoot: true
runAsUser: 10001
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
runAsNonRoot: true 會導致 pod 在映像試圖以 UID 0 身份運行時在准入時失敗,給予你硬性保證而不是盡力而為的約定。
3. 捨棄不必要的能力
大多數應用程式不需要授予容器的任何預設 Linux 能力。捨棄所有內容,然後僅新增嚴格要求的內容(罕見情況下,例如綁定到低連接埠可能需要 NET_BIND_SERVICE)。
4. 避免特權模式和主機命名空間共享
privileged: true、hostNetwork: true 和 hostPID: true 應保留用於非常特定的基礎設施工作負載(如某些 CNI 或監視代理)——絕不用於一般應用程式容器。
5. 使用政策工具掃描和強制執行
使用准入控制器或政策引擎(例如 Kyverno、OPA/Gatekeeper)自動拒絕違反這些規則的部署,而不是依賴手動程式碼審查。將其與 CI 中的映像掃描配對,以在根使用者映像到達叢集之前捕獲它們。
分層的、而非完美的防禦
以非 root 身份運行並不能完全消除風險——與容器內使用者無關的核心級容器逃逸存在——但它消除了大量低效率的權限提升和橫向移動技術。結合唯讀檔案系統、捨棄的能力和限制性網路政策,它形成了深度防禦容器安全策略中最便宜和最有效的層之一。
想更深入地瞭解雲原生工作負載的加固?探索相關的 Korra Studio 段落,了解雲安全和 DevOps 管線加固,以構建防禦策略的其餘部分。