Мне нужно создать пространства имен внутри контейнера 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
файловая система снова монтируется во вложенных пользовательских пространствах имен.