Security

如何在 docker 容器內的命名空間內掛載私有 /proc?

  • March 16, 2020

我需要在 Docker 容器中創建命名空間。作為其中的一部分,我需要將/proc私有掛載到內部命名空間。我意識到我必須以某些特權執行容器才能實現這一點,但我更願意啟用最小的集合。

這有效:

$ sudo docker run --privileged --security-opt=seccomp=unconfined \
-it fedora:rawhide /usr/bin/unshare -Ufmp -r \
/bin/sh -c 'mount -t proc proc /proc'

這不會:

$ sudo docker run --cap-add=sys_admin --security-opt=seccomp=unconfined \
 -it fedora:rawhide /usr/bin/unshare -Ufmp -r \
  /bin/sh -c 'mount -t proc proc /proc'
mount: /proc: cannot mount proc read-only.

因此,僅關閉 seccomp 過濾器並添加CAP_SYS_ADMIN是不夠的。什麼足夠的?

更新: Selinux 是問題的一部分。如果你在全域範圍內關閉 selinux 強制,它會起作用。但是,您也可以使用 關閉對特定容器的強制執行--security-opt label:disable,這在線上 Docker 手冊的安全配置部分中有記錄:

sudo docker run --cap-add=sys_admin --security-opt label:disable \
-it fedora:rawhide /usr/bin/unshare -fmp /bin/sh -c \
'mount --make-private / ; mount -t proc proc /proc'

但是,如果將-U-r標誌添加回unshare. 而且,當然,添加--privileged到 docker run 命令即使使用-Uand-r標誌也可以正常工作。

我目前正在嘗試使用核心跟踪的東西來弄清楚究竟是什麼給了我一個 EPERM。這是一個非常無用的非特定錯誤。

此命令有效:

sudo docker run --cap-add=sys_admin --security-opt label:disable -it fedora:rawhide /bin/sh -c 'for dir in $(awk '"'"'/\/proc\// { print $5; }'"'"' /proc/1/mountinfo ); do umount "$dir"; done; /usr/bin/unshare -Ufmp -r /bin/sh -c '"'"'mount --make-private / ; mount -t proc proc /proc ; ls /proc'"'"

我沒有將它分成多行,因為引用非常重要。/proc基本上,它在執行 unshare 並/proc在子使用者命名空間中掛載之前解除安裝了一大堆東西。

Docker 掛載了一堆目錄和文件,/proc其中包含自己的目錄,這些目錄是空的 tmpfs 目錄和空文件。中的各種文件/proc表示適用於整個系統的值。事實上,/proc/kcore如果你是 root,就可以讀取容器內的核心記憶體,因為很多人想相信容器是某種輕量級 VM 之類的東西,這會讓很多人感到驚訝。

核心(從版本 4.14 開始)fs/namespace.c:mnt_already_visible檢查您是否正在掛載一個已經掛載的文件系統,如果該文件系統有作為子文件系統掛載的東西並且這些掛載具有 MNT_LOCKED 標誌,它會失敗。每當您創建使用者命名空間時,似乎都會將 MNT_LOCKED 標誌應用於所有掛載(我沒有追查核心中的位置),以防止您解除安裝該命名空間中的東西(因為您在“內部”獲得特權使用者命名空間)並使隱藏的東西再次可見。

我發布的命令使用 awk 腳本來提取Docker 已掛載/proc/1/mountinfo的所有子目錄和文件,然後將它們全部解除安裝。/proc這使得/proc文件系統可以再次安裝在嵌套的使用者命名空間中。

引用自:https://serverfault.com/questions/897299