主要特性和優勢
所有容器的 Linux 使用者名稱空間
啟用增強型容器隔離後,所有使用者容器都會利用 Linux 使用者名稱空間 以獲得額外的隔離。這意味著容器中的 root 使用者會對映到 Docker Desktop Linux VM 中的一個非特權使用者。
例如
$ docker run -it --rm --name=first alpine
/ # cat /proc/self/uid_map
0 100000 65536
輸出 0 100000 65536
是 Linux 使用者名稱空間的標識。它表示容器中的 root 使用者 (0) 被對映到 Docker Desktop Linux VM 中的非特權使用者 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 使用者名稱空間,增強型容器隔離確保容器程序在 Linux VM 中絕不以使用者 ID 0(真正 root)身份執行。實際上,它們在 Linux VM 中不以任何有效使用者 ID 身份執行。因此,它們的 Linux 能力僅限於容器內的資源,與常規容器相比,大大增強了容器到主機以及跨容器的隔離。
特權容器也受到保護
特權容器 docker run --privileged ...
不安全,因為它賦予容器對 Linux 核心的完全訪問許可權。也就是說,容器以真正 root 身份執行,啟用了所有能力,seccomp 和 AppArmor 限制被停用,所有硬體裝置都暴露在外,等等。
希望確保開發者機器上 Docker Desktop 安全的組織面臨特權容器帶來的挑戰。這些容器,無論執行的是良性工作負載還是惡意工作負載,都可能獲得 Docker Desktop VM 內 Linux 核心的控制權,可能會更改與安全相關的設定,例如倉庫訪問管理和網路代理。
啟用增強型容器隔離後,特權容器將無法再做到這一點。Linux 使用者名稱空間與 Sysbox 使用的其他安全技術的結合,確保特權容器內的程序只能訪問分配給容器的資源。
注意
增強型容器隔離並不會阻止使用者啟動特權容器,而是透過確保它們只能修改與容器關聯的資源來安全地執行它們。修改全域性核心設定的特權工作負載,例如載入核心模組或更改 Berkeley Packet Filters (BPF) 設定,將無法正常工作,因為在嘗試此類操作時會收到“許可權被拒絕”錯誤。
例如,增強型容器隔離確保特權容器無法訪問透過 BPF 在 Linux VM 中配置的 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 VM 共享名稱空間
啟用增強型容器隔離後,容器不能與主機共享 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 build 的 `--network=host` 和 Docker buildx 許可權(`network.host`、`security.insecure`)不被允許。需要這些設定的構建將無法正常工作。
繫結掛載限制
啟用增強型容器隔離後,Docker Desktop 使用者可以繼續將主機目錄繫結掛載到容器中,就像透過 Settings > Resources > File sharing 配置的那樣,但不再允許將任意 Linux VM 目錄繫結掛載到容器中。
這可以防止容器修改 Docker Desktop Linux VM 中的敏感檔案,這些檔案可能包含倉庫訪問管理、代理、Docker Engine 配置等資訊。
例如,將 Docker Engine 配置檔案(Linux VM 中的 /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 Engine 配置檔案的完全讀寫訪問許可權。
當然,主機檔案的繫結掛載像往常一樣繼續工作。例如,假設使用者將 Docker Desktop 配置為檔案共享其 $HOME
目錄,她可以將其繫結掛載到容器中。
$ docker run -it --rm -v $HOME:/mnt alpine
/ #
注意
預設情況下,增強型容器隔離不允許將 Docker Engine socket(
/var/run/docker.sock
)繫結掛載到容器中,因為這樣做會賦予容器對 Docker Engine 的控制權,從而破壞容器隔離。然而,由於某些合法的使用場景需要此功能,可以針對受信任的容器映象放寬此限制。請參閱Docker socket 掛載許可權。
審查敏感系統呼叫
增強型容器隔離的另一個特性是,它會攔截並審查容器內部一些高度敏感的系統呼叫,例如 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 對映
如前所述,ECI 會在所有容器上啟用 Linux 使用者名稱空間。這確保了容器的使用者 ID 範圍(0->64K)對映到 Docker Desktop Linux VM 中“真實”使用者 ID 的非特權範圍(例如 100000->165535)。
此外,每個容器在 Linux VM 中都獲得專屬的真實使用者 ID 範圍(例如,容器 0 可能對映到 100000->165535,容器 2 對映到 165536->231071,容器 3 對映到 231072->296607,依此類推)。組 ID 也是如此。此外,如果容器停止並重新啟動,不能保證它會獲得與之前相同的對映。這是設計使然,旨在進一步提高安全性。
然而,這在將 Docker 資料卷掛載到容器中時會帶來問題。寫入此類資料卷的檔案會具有真實使用者/組 ID,因此由於每個容器具有不同的真實使用者 ID/組 ID,它們在容器啟動/停止/重新啟動後或容器之間將無法訪問。
為了解決這個問題,Sysbox 透過 Linux 核心的 ID 對映掛載功能(2021 年新增)或替代的 shiftsfs
模組來使用“檔案系統使用者 ID 重對映”。這些技術將容器真實使用者 ID(例如範圍 100000->165535)的檔案系統訪問對映到 Docker Desktop Linux VM 內部的範圍(0->65535)。這樣,即使每個容器使用專屬的使用者 ID 範圍,資料卷現在也可以在容器之間掛載或共享。使用者無需擔心容器的真實使用者 ID。
儘管檔案系統使用者 ID 重對映可能導致容器以真實使用者 ID 0 訪問掛載到容器中的 Linux VM 檔案,但受限掛載功能確保敏感的 Linux VM 檔案無法掛載到容器中。
Procfs & sysfs 模擬
增強型容器隔離的另一個特性是,在每個容器內部,/proc
和 /sys
檔案系統會進行部分模擬。這有幾個目的,例如隱藏容器內部的敏感主機資訊,以及對 Linux 核心本身尚未名稱空間化的主機核心資源進行名稱空間化。
舉個簡單的例子,啟用增強型容器隔離後,/proc/uptime
檔案顯示的是容器本身的執行時長,而不是 Docker Desktop Linux VM 的執行時長。
$ docker run -it --rm alpine
/ # cat /proc/uptime
5.86 5.86
相反,如果沒有增強型容器隔離,您會看到 Docker Desktop Linux VM 的執行時長。儘管這是一個簡單的例子,但它顯示了增強型容器隔離如何旨在防止 Linux VM 的配置和資訊洩露到容器中,從而更難攻破 VM。
此外,/proc/sys
下的一些 Linux 核心尚未名稱空間化的其他資源也在容器內部進行模擬。每個容器看到的是這些資源的獨立檢視,Sysbox 在程式設計相應的 Linux 核心設定時會協調跨容器的值。
這樣做的好處是,原本需要真正特權容器才能訪問此類非名稱空間化核心資源的容器工作負載,現在可以在啟用增強型容器隔離的情況下執行,從而提高了安全性。