Назад | Перейти на главную страницу

Как смонтировать частный / proc внутри пространства имен внутри контейнера докеров?

Мне нужно создать пространства имен внутри контейнера 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 глобально, это сработает. Но вы также можете отключить принудительное применение для конкретного контейнера с помощью --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 отлично работает даже с -U и -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 в пространстве имен дочернего пользователя.

Докер монтирует кучу каталогов и файлов в /proc со своими собственными каталогами, которые являются пустыми каталогами tmpfs и пустыми файлами. Различные файлы в /proc представляют значения, применимые ко всей системе. По факту, /proc/kcore позволил бы вам читать память ядра внутри контейнера, если бы вы были пользователем root, что, поскольку многие люди хотят верить, что контейнеры - это какая-то легкая виртуальная машина или что-то в этом роде, многих удивит.

Ядро в (по крайней мере, с версии 4.14) fs/namespace.c:mnt_already_visible проверяет, монтируете ли вы уже смонтированную файловую систему, и если в этой файловой системе есть объекты, смонтированные как дочерние файловые системы, и эти монтирования имеют флаг MNT_LOCKED, это не удается. Похоже, что флаг MNT_LOCKED применяется (я не выслеживал, где он находится в ядре) ко всем монтированиям всякий раз, когда вы создаете пространство имен пользователя, чтобы предотвратить размонтирование объектов в этом пространстве имен (потому что вы получаете привилегии «внутри» user namespace) и снова сделать скрытые объекты видимыми.

Опубликованная мною команда использует сценарий awk для содержимого /proc/1/mountinfo вытащить все подкаталоги и файлы в /proc что Docker смонтировал, и размонтирует их все. Это делает /proc файловая система снова монтируется во вложенных пользовательских пространствах имен.