關鍵功能和優勢
所有容器上的 Linux 使用者名稱空間
透過增強型容器隔離,所有使用者容器都利用了 Linux 使用者名稱空間 以實現額外的隔離。這意味著容器中的 root 使用者對映到 Docker Desktop Linux 虛擬機器中的非特權使用者。
例如
$ docker run -it --rm --name=first alpine
/ # cat /proc/self/uid_map
0 100000 65536
輸出 0 100000 65536
是 Linux 使用者名稱空間的簽名。這意味著容器中的 root 使用者 (0) 對映到 Docker Desktop Linux 虛擬機器中的非特權使用者 100000,並且對映擴充套件到 64K 使用者 ID 的連續範圍。同樣適用於組 ID。
每個容器都獲得一個獨佔的對映範圍,由 Sysbox 管理。例如,如果啟動第二個容器,則對映範圍會有所不同
$ docker run -it --rm --name=second alpine
/ # cat /proc/self/uid_map
0 165536 65536
相反,如果沒有增強型容器隔離,容器的 root 使用者實際上是主機上的 root(即“真實 root”),這適用於所有容器
$ docker run -it --rm alpine
/ # cat /proc/self/uid_map
0 0 4294967295
透過使用 Linux 使用者名稱空間,增強型容器隔離確保容器程序永遠不會以使用者 ID 0(真實 root)的形式執行在 Linux 虛擬機器中。事實上,它們永遠不會以 Linux 虛擬機器中任何有效的使用者 ID 執行。因此,它們的 Linux 功能限制在容器內的資源,與常規容器相比,隔離度顯著提高,包括容器到主機和跨容器隔離。
特權容器也已得到保護
特權容器 docker run --privileged ...
不安全,因為它們賦予容器對 Linux 核心的完全訪問許可權。也就是說,容器以真實 root 身份執行,並啟用所有功能,停用 seccomp 和 AppArmor 限制,公開所有硬體裝置,例如。
對於希望在其開發人員機器上保護 Docker Desktop 的組織來說,特權容器存在問題,因為它們允許容器工作負載(無論良性還是惡意)獲取對 Docker Desktop 虛擬機器中 Linux 核心的控制權,從而修改安全相關的設定,例如登錄檔訪問管理和網路代理。
透過增強型容器隔離,特權容器不再能夠做到這一點。Linux 使用者名稱空間與 Sysbox 使用的其他安全技術的組合確保特權容器內的程序只能訪問分配給該容器的資源。
注意
增強型容器隔離不會阻止使用者啟動特權容器,而是透過確保它們只能修改與容器相關的資源來安全地執行它們。修改全域性核心設定的特權工作負載(例如載入核心模組或更改 BPF 設定)將無法正常工作,因為它們在嘗試執行此類操作時會收到“許可權被拒絕”錯誤。
例如,增強型容器隔離確保特權容器無法訪問透過 Berkeley Packet Filters (BPF) 配置的 Linux 虛擬機器中 Docker Desktop 網路設定
$ docker run --privileged djs55/bpftool map show
Error: can't get next map: Operation not permitted
相反,如果沒有增強型容器隔離,特權容器可以輕鬆地做到這一點
$ docker run --privileged djs55/bpftool map show
17: ringbuf name blocked_packets flags 0x0
key 0B value 0B max_entries 16777216 memlock 0B
18: hash name allowed_map flags 0x0
key 4B value 4B max_entries 10000 memlock 81920B
20: lpm_trie name allowed_trie flags 0x1
key 8B value 8B max_entries 1024 memlock 16384B
請注意,一些高階容器工作負載需要特權容器,例如 Docker-in-Docker、Kubernetes-in-Docker 等。使用增強型容器隔離,您仍然可以執行這些工作負載,但比以前更加安全。
容器無法與 Linux 虛擬機器共享名稱空間
啟用增強型容器隔離後,容器無法與主機共享 Linux 名稱空間(例如,pid、網路、uts 等),因為這實際上會破壞隔離。
例如,共享 pid 名稱空間將失敗
$ docker run -it --rm --pid=host alpine
docker: Error response from daemon: failed to create shim task: OCI runtime create failed: error in the container spec: invalid or unsupported container spec: sysbox containers can't share namespaces [pid] with the host (because they use the linux user-namespace for isolation): unknown.
同樣,共享網路名稱空間也會失敗
$ docker run -it --rm --network=host alpine
docker: Error response from daemon: failed to create shim task: OCI runtime create failed: error in the container spec: invalid or unsupported container spec: sysbox containers can't share a network namespace with the host (because they use the linux user-namespace for isolation): unknown.
此外,--userns=host
標誌(用於停用容器上的使用者名稱空間)將被忽略
$ docker run -it --rm --userns=host alpine
/ # cat /proc/self/uid_map
0 100000 65536
最後,Docker 構建 --network=host
和 Docker buildx 權利(network.host
、security.insecure
)不允許。需要這些的構建將無法正常工作。
繫結掛載限制
啟用增強型容器隔離後,Docker Desktop 使用者可以繼續將主機目錄繫結掛載到容器中,如透過**設定**>**資源**>**檔案共享**配置的那樣,但他們不再允許將任意 Linux 虛擬機器目錄繫結掛載到容器中。
這可以防止容器修改 Docker Desktop Linux 虛擬機器中的敏感檔案,這些檔案可以儲存登錄檔訪問管理、代理、Docker 引擎配置等的配置。
例如,將 Docker 引擎的配置檔案(Linux 虛擬機器內的 /etc/docker/daemon.json
)繫結掛載到容器中將受到限制,因此會失敗
$ docker run -it --rm -v /etc/docker/daemon.json:/mnt/daemon.json alpine
docker: Error response from daemon: failed to create shim task: OCI runtime create failed: error in the container spec: can't mount /etc/docker/daemon.json because it's configured as a restricted host mount: unknown
相反,如果沒有增強型容器隔離,此掛載將生效,並賦予容器對 Docker 引擎配置的完全讀寫訪問許可權。
當然,主機檔案的繫結掛載將照常工作。例如,假設使用者配置 Docker Desktop 以共享她的 $HOME 目錄,她可以將其繫結掛載到容器中
$ docker run -it --rm -v $HOME:/mnt alpine
/ #
注意
預設情況下,增強型容器隔離不允許將 Docker 引擎套接字 (/var/run/docker.sock) 繫結掛載到容器中,因為這樣做實際上會賦予容器對 Docker 引擎的控制權,從而破壞容器隔離。但是,由於某些合法用例需要這樣做,因此可以為受信任的容器映象放寬此限制。請參閱 Docker 套接字掛載許可權.
審查敏感系統呼叫
增強型容器隔離的另一個功能是它會攔截並審查容器內的一些高度敏感的系統呼叫,例如 mount
和 umount
。這可以確保具有執行這些系統呼叫功能的程序無法使用它們來破壞容器。
例如,具有 CAP_SYS_ADMIN
(執行 mount
系統呼叫所需的)的容器無法使用該功能將只讀繫結掛載更改為讀寫掛載
$ docker run -it --rm --cap-add SYS_ADMIN -v $HOME:/mnt:ro alpine
/ # mount -o remount,rw /mnt /mnt
mount: permission denied (are you root?)
由於 $HOME
目錄以只讀形式掛載到容器的 /mnt
目錄中,因此無法從容器內部將其更改為讀寫,即使容器程序具有執行此操作的功能也是如此。這可以確保容器程序無法使用 mount
或 umount
來破壞容器的根檔案系統。
但是請注意,在上面的示例中,容器仍然可以在容器內建立掛載,並根據需要將其掛載為只讀或讀寫。這些掛載是允許的,因為它們發生在容器內,因此不會破壞其根檔案系統
/ # mkdir /root/tmpfs
/ # mount -t tmpfs tmpfs /root/tmpfs
/ # mount -o remount,ro /root/tmpfs /root/tmpfs
/ # findmnt | grep tmpfs
├─/root/tmpfs tmpfs tmpfs ro,relatime,uid=100000,gid=100000
/ # mount -o remount,rw /root/tmpfs /root/tmpfs
/ # findmnt | grep tmpfs
├─/root/tmpfs tmpfs tmpfs rw,relatime,uid=100000,gid=100000
此功能與使用者名稱空間一起,確保即使容器程序具有所有 Linux 功能,它們也無法用於破壞容器。
最後,增強型容器隔離以不會影響大多數情況下容器效能的方式執行系統呼叫審查。它會攔截在大多數容器工作負載中很少使用的控制路徑系統呼叫,但不會攔截資料路徑系統呼叫。
檔案系統使用者 ID 對映
如上所述,增強型容器隔離在所有容器上啟用 Linux 使用者名稱空間,這可以確保容器的使用者 ID 範圍 (0->64K) 對映到 Docker Desktop Linux 虛擬機器中“真實”使用者 ID 的非特權範圍(例如,100000->165535)。
此外,每個容器在 Linux 虛擬機器中都獲得一個獨佔的真實使用者 ID 範圍(例如,容器 0 可能對映到 100000->165535,容器 2 對映到 165536->231071,容器 3 對映到 231072->296607,依此類推)。同樣適用於組 ID。此外,如果容器已停止並重新啟動,則無法保證它會收到與之前相同的對映。這是經過設計的,並且進一步提高了安全性。
但是,在將 Docker 卷掛載到容器中時,上述情況會帶來問題,因為寫入此類卷的檔案將具有真實的使用者/組 ID,因此在容器的啟動/停止/重新啟動期間或容器之間將無法訪問,因為每個容器的真實使用者 ID/組 ID 不同。
為了解決此問題,Sysbox 透過 Linux 核心的 ID 對映掛載功能(在 2021 年新增)或名為 shiftfs 的備用模組使用“檔案系統使用者 ID 重新對映”。這些技術將來自容器的真實使用者 ID(例如,範圍 100000->165535)的檔案系統訪問對映到 Docker Desktop 的 Linux 虛擬機器內的範圍 (0->65535)。這樣,現在可以跨容器掛載或共享卷,即使每個容器都使用獨佔的 使用者 ID 範圍。使用者無需擔心容器的真實使用者 ID。
請注意,儘管檔案系統使用者 ID 重新對映可能會導致容器以真實使用者 ID 0(即 root)的形式訪問掛載到容器中的 Linux 虛擬機器檔案,但上面描述的 受限掛載功能 確保不會將任何 Linux 虛擬機器敏感檔案掛載到容器中。
Procfs & Sysfs 模擬
增強容器隔離的另一個特性是在每個容器內部部分模擬了 procfs("/proc")和 sysfs("/sys")檔案系統。這可以實現幾個目的,例如隱藏容器內部敏感的主機資訊,以及對 Linux 核心本身尚未名稱空間的主機核心資源進行名稱空間。
舉個簡單的例子,當啟用增強容器隔離時,/proc/uptime
檔案顯示的是容器本身的執行時間,而不是 Docker Desktop Linux 虛擬機器的執行時間。
$ docker run -it --rm alpine
/ # cat /proc/uptime
5.86 5.86
相反,在沒有啟用增強容器隔離的情況下,你將看到 Docker Desktop Linux 虛擬機器的執行時間。雖然這是一個簡單的例子,但它展示了增強容器隔離如何防止 Linux 虛擬機器的配置和資訊洩露到容器中,從而更難入侵虛擬機器。
此外,在 /proc/sys
下,一些 Linux 核心尚未名稱空間的資源,也會在容器內部被模擬。每個容器都看到這些資源的不同檢視,而 Sysbox 會在對相應的 Linux 核心設定程式設計時,協調容器之間的這些值。
這具有以下優勢:即使是那些原本需要真正特權容器才能訪問未名稱空間的核心資源的容器工作負載,也能在啟用增強容器隔離的情況下執行,從而提高安全性。