Kubernetes 1.30:Pod 支援使用者命名空間的 Beta 版本
Linux 提供不同的命名空間來隔離彼此的進程。例如,典型的 Kubernetes Pod 在網路命名空間中運行,以隔離網路身分,並在 PID 命名空間中運行以隔離進程。
有一個 Linux 命名空間被遺漏了,那就是 使用者命名空間。這個命名空間允許我們將容器內部使用的使用者和群組識別碼 (UID 和 GID) 與主機上的識別碼隔離。
這是一個強大的抽象概念,允許我們以「root」身分運行容器:我們在容器內部是 root,並且可以執行 root 在 Pod 內部可以執行的所有操作,但我們與主機的互動僅限於非特權使用者可以執行的操作。這對於限制容器突破的影響非常有用。
容器突破是指容器內部的進程可以利用容器運行時或核心中某些未修補的漏洞突破到主機上,並存取/修改主機或其他容器上的檔案。如果我們使用使用者命名空間運行 Pod,則容器對主機其餘部分擁有的權限會降低,並且它可以存取的容器外部檔案也會受到限制。
在 Kubernetes v1.25 中,我們引入了僅適用於無狀態 Pod 的使用者命名空間支援。Kubernetes 1.28 解除了該限制,現在,在 Kubernetes 1.30 中,我們正邁向 Beta 階段!
什麼是使用者命名空間?
注意:Linux 使用者命名空間與 Kubernetes 命名空間 是不同的概念。前者是 Linux 核心功能;後者是 Kubernetes 功能。
使用者命名空間是 Linux 的一項功能,可將容器的 UID 和 GID 與主機上的 UID 和 GID 隔離。容器中的識別碼可以映射到主機上的識別碼,使得用於不同容器的主機 UID/GID 永遠不會重疊。此外,識別碼可以映射到主機上非特權、非重疊的 UID 和 GID。這帶來了兩個主要好處
防止橫向移動:由於不同容器的 UID 和 GID 映射到主機上不同的 UID 和 GID,即使容器逃脫容器邊界,它們也很難互相攻擊。例如,假設容器 A 在主機上運行的 UID 和 GID 與容器 B 不同。在這種情況下,它可以對容器 B 的檔案和進程執行的操作受到限制:只能讀取/寫入檔案允許其他人的內容,因為它永遠不會擁有所有者或群組權限(主機上的 UID/GID 保證對於不同的容器是不同的)。
提高主機隔離性:由於 UID 和 GID 映射到主機上的非特權使用者,因此如果容器逃脫容器邊界,即使它在容器內部以 root 身分運行,它在主機上也沒有任何權限。這極大地保護了它可以讀取/寫入的主機檔案、它可以向其發送訊號的進程等。此外,授予的功能僅在使用者命名空間內有效,而不在主機上有效,從而限制了容器逃脫可能產生的影響。
使用者命名空間 ID 分配
在不使用使用者命名空間的情況下,在容器突破的情況下,以 root 身分運行的容器在節點上具有 root 權限。如果某些功能被授予容器,則這些功能在主機上也有效。當使用使用者命名空間時,這些都不成立(當然,錯誤除外 🙂)。
1.30 版本的變更
在 Kubernetes 1.30 中,除了將使用者命名空間移至 Beta 版之外,參與此功能的貢獻者
- 引入了一種讓 kubelet 可以使用自訂範圍進行 UID/GID 映射的方法
- 新增了一種讓 Kubernetes 強制運行時支援使用者命名空間所需的所有功能的方法。如果它們不受支援,Kubernetes 將在嘗試建立具有使用者命名空間的 Pod 時顯示明確的錯誤。在 1.30 之前,如果容器運行時不支援使用者命名空間,則可以建立沒有使用者命名空間的 Pod。
- 新增了更多測試,包括 cri-tools 儲存庫中的測試。
您可以查看關於使用者命名空間的 文件,了解如何為映射配置自訂範圍。
演示
幾個月前,CVE-2024-21626 被揭露。此漏洞的漏洞評分為 8.6(高)。它允許攻擊者逃脫容器並讀取/寫入節點和託管在同一節點上的其他 Pod 上的任何路徑。
Rodrigo 建立了一個演示,利用 CVE 2024-21626,並展示了在不使用使用者命名空間的情況下有效的漏洞,在使用使用者命名空間時如何被緩解。
請注意,使用使用者命名空間,攻擊者可以在主機檔案系統上執行「其他人」權限位允許的操作。因此,CVE 並未完全阻止,但影響已大大降低。
節點系統需求
使用此功能對 Linux 核心版本和容器運行時有要求。
在 Linux 上,您需要 Linux 6.3 或更高版本。這是因為該功能依賴於名為 idmap mounts 的核心功能,並且在 Linux 6.3 中合併了將 idmap mounts 與 tmpfs 一起使用的支援。
假設您正在使用 CRI-O 和 crun;與往常一樣,您可以期望 CRI-O 1.30 支援 Kubernetes 1.30。請注意,您還需要 crun 1.9 或更高版本。如果您正在使用 CRI-O 和 runc,則仍不支援此功能。
Containerd 支援目前目標是 containerd 2.0,並且適用相同的 crun 版本要求。如果您正在使用 containerd 和 runc,則仍不支援此功能。
請注意,containerd 1.7 新增了對使用者命名空間的實驗性支援,如 Kubernetes 1.25 和 1.26 中實作的那樣。我們在 Kubernetes 1.27 中進行了重新設計,這需要在容器運行時中進行變更。這些變更不存在於 containerd 1.7 中,因此它僅適用於 Kubernetes 1.25 和 1.26 中的使用者命名空間支援。
containerd 1.7 的另一個限制是它需要在 Pod 啟動期間變更容器映像內部每個檔案和目錄的所有權。這會產生儲存開銷,並可能顯著影響容器啟動延遲。Containerd 2.0 可能會包含一個實作,消除增加的啟動延遲和儲存開銷。如果您計劃在生產環境中使用 containerd 1.7 和使用者命名空間,請考慮這一點。
這些 containerd 1.7 的限制都不適用於 CRI-O。
我該如何參與?
您可以透過幾種方式聯繫 SIG Node
您也可以直接聯繫我們
- GitHub:@rata @giuseppe @saschagrunert
- Slack:@rata @giuseppe @sascha