Подтвердить что ты не робот

Понимание владения файлом пользователя в докере: как избежать изменения разрешений связанных томов

Рассмотрим следующий тривиальный файл Docker:

FROM debian:testing
RUN  adduser --disabled-password --gecos '' docker
RUN  adduser --disabled-password --gecos '' bob 

в рабочем каталоге ни с чем другим. Создайте изображение докера:

docker build -t test .

а затем запустите в контейнере bash script, связав рабочий каталог с новым поддиректором в домашнем каталоге bob:

docker run --rm -it -v $(pwd):/home/bob/subdir test 

Кому принадлежит содержимое subdir на контейнере? На контейнере запустите:

cd /home/bob/subdir
ls -l

ad мы видим:

-rw-rw-r-- 1 docker docker 120 Oct 22 03:47 Dockerfile

Святые курят! docker владеет содержимым! Вернемся на главную машину за пределами контейнера, мы видим, что наш оригинальный пользователь все еще владеет Dockerfile. Попробуйте исправить право собственности на домашний каталог bob. На контейнере запустите:

chown -R bob:bob /home/bob
ls -l 

и мы видим:

-rw-rw-r-- 1 bob bob 120 Oct 22 03:47 Dockerfile

Но подождите! вне контейнера, теперь мы запускаем ls -l

-rw-rw-r-- 1 1001 1001 120 Oct 21 20:47 Dockerfile

у нас больше нет собственного файла. Ужасные новости!


Если бы в приведенном выше примере был добавлен только один пользователь, все было бы более гладко. По какой-то причине Docker, похоже, создает любой домашний каталог, принадлежащий первому пользователю без полномочий root, который он встречает (даже если этот пользователь объявлен на более раннем изображении). Аналогично, этот первый пользователь является тем, который соответствует тем же правам на доступ, что и мой домашний пользователь.

Вопрос 1 Это правильно? Может кто-то указать мне на документацию, я просто предполагаю, основываясь на вышеупомянутом эксперименте.

Вопрос 2. Возможно, это связано только с тем, что оба они имеют одинаковое числовое значение в ядре, и если я тестировал систему, где мой домашний пользователь не был id 1000, то разрешения могли бы получить изменено в каждом случае?

Вопрос 3. Реальный вопрос, конечно, "что мне делать с этим?" Если bob зарегистрирован как bob на данном хост-компьютере, он должен иметь возможность запускать контейнер как bob и не изменять файлы в своей учетной записи хоста. Как бы то ни было, ему действительно нужно запустить контейнер как пользователь docker, чтобы избежать изменения его учетной записи.

Я слышал, вы спрашиваете, почему у меня такой странный Dockerfile? Иногда я удивляюсь. Я пишу контейнер для webapp (RStudio-server), который позволяет другим пользователям регистрироваться, что просто использует имена пользователей и учетные данные с Linux-машины в качестве допустимых имен пользователей. Это приносит мне, возможно, необычную мотивацию желать создать несколько пользователей. Я могу обойти это, создав пользователя только во время выполнения, и все в порядке. Тем не менее, я использую базовое изображение, которое добавило единственного пользователя docker, чтобы его можно было использовать в интерактивном режиме, но не выполнялось как root (согласно наилучшей практике). Это разрушает все, поскольку этот пользователь становится первым пользователем и заканчивает тем, что владеет всем, поэтому попытки входа в систему по мере того, как другие пользователи терпят неудачу (приложение не может запускаться из-за отсутствия разрешений на запись). При запуске script run chown сначала решается эта проблема, но ценой связанных томов, изменяющих разрешения (очевидно, только проблема, если мы связываем тома).

4b9b3361

Ответ 1

Это правильно? Может кто-то указать мне на документацию по этому поводу, я просто предполагаю, основываясь на вышеупомянутом эксперименте.

Возможно, это связано только с тем, что оба они имеют одинаковое числовое значение для ядра, и если я тестировал систему, в которой мой домашний пользователь не был идентификатором 1000, тогда разрешения будут изменены в каждом случае?

Прочитайте info coreutils 'chown invocation', что может дать вам лучшее представление о том, как работают права доступа/прав доступа к файлам.

В принципе, каждый файл на вашем компьютере имеет набор бит, привязанных к нему, который определяет его разрешения и права собственности. Когда вы chown файл, вы просто устанавливаете эти биты.

Когда вы chown файл для конкретного пользователя/группы, используя имя пользователя или группы, chown будет выглядеть в /etc/passwd для имени пользователя и /etc/group, чтобы группа попыталась сопоставить имя с именем Я БЫ. Если имя пользователя/группы не существует в этих файлах, chown завершится с ошибкой.

[email protected]:/test# touch test
[email protected]:/test# ll
total 8
drwxr-xr-x  2 root root 4096 Oct 22 18:15 ./
drwxr-xr-x 22 root root 4096 Oct 22 18:15 ../
-rw-r--r--  1 root root    0 Oct 22 18:15 test
[email protected]:/test# chown test:test test
chown: invalid user: 'test:test'

Однако вы можете chown использовать файл с идентификаторами независимо от того, что вы хотите (в пределах некоторых верхних положительных целых границ, конечно), существует ли пользователь/группа, которая существует с этими идентификаторами на вашем компьютере или нет.

[email protected]:/test# chown 5000:5000 test
[email protected]:/test# ll
total 8
drwxr-xr-x  2 root root 4096 Oct 22 18:15 ./
drwxr-xr-x 22 root root 4096 Oct 22 18:15 ../
-rw-r--r--  1 5000 5000    0 Oct 22 18:15 test

Биты UID и GID устанавливаются в самом файле, поэтому, когда вы монтируете эти файлы внутри контейнера докеров, файл имеет тот же идентификатор владельца/группы, что и на хосте, но теперь отображается на /etc/passwd в контейнере, который, вероятно, будет другим пользователем, если он не принадлежит root (UID 0).

Реальный вопрос, конечно, "что мне делать с этим?" Если bob зарегистрирован как bob на данном хост-компьютере, он должен иметь возможность запускать контейнер в виде bob и не изменять файлы в соответствии с его учетной записью хоста. В его нынешнем виде он фактически должен запускать контейнер в качестве пользовательского докера, чтобы избежать изменения его учетной записи.

Похоже, что с вашей текущей настройкой вам нужно убедиться, что ваши UID > имена пользователей в /etc/passwd на вашем хосте совпадают с вашими UID > именами пользователей в ваших контейнерах /etc/passwd, если вы хотите взаимодействовать с вашим установленным каталогом пользователя как тем же пользователем, который вошел в систему на хосте.

Вы можете создать пользователя с определенным идентификатором пользователя с помощью useradd -u xxxx. Buuuut, это похоже на беспорядочное решение...

Возможно, вам придется придумать решение, не устанавливающее домашний каталог хост-пользователей.

Ответ 2

Два варианта, которые я нашел:

ПОЧЕМУ все вещи (после выполнения вашей работы)

Я сделал docker run -v `pwd`/shared:/shared image, и контейнер создал файлы в pwd/shared, которые принадлежат процессу докеров. Однако /shared все еще принадлежит мне. Итак, в процессе докера, я делаю

chown -R `stat -c "%u:%g" /shared` /shared

stat -c "%u:%g" /shared возвращает 1000:1000 в моем случае, будучи uid:gid моего пользователя. Несмотря на то, что в docker conatainer нет пользователя 1000, идентификатор есть (и stat /shared просто говорит "unknown", если вы запрашиваете имя пользователя).

В любом случае chown подчиняется передаче содержимого /shared в 1000:1000 (что, насколько это касается, не существует, но вне контейнера, это я). Итак, теперь у меня есть все файлы. Контейнер все еще может изменять вещи, если захочет, потому что с его точки зрения он root.

И все хорошо с миром.

docker run -u, поэтому все созданные файлы автоматически будут иметь правообладателя

Другой способ сделать это - флаг -u при запуске докеров.

docker run -v `pwd`/shared:/shared -u `stat -c "%u:%g" /shared` ubuntu bash

Таким образом, пользователь-докер в контейнере youruid:yourgid.

Однако: это означает отказ от корневого права в контейнере (apt-get install и т.д.). Если вы не создадите пользователя с этим новым uid и не добавите его в группу root.

Ответ 3

Итак, я закончил в этом посте поиском того, как вернуть право владения всеми файлами (принадлежащими root), которые вышли из Docker-контейнера, работающего от имени root, моему непривилегированному пользователю на хосте.

Мне нужно, чтобы процесс внутри контейнера выполнялся от имени пользователя root, поэтому я не могу использовать -u при запуске докера.

Я не горжусь тем, что я сделал, но в конце своего сценария bash я добавил это:

docker run --rm -it \
    --entrypoint /bin/sh \
    -e HOST_UID='id -u' \
    -v ${HOST_FOLDER_OWNED_BY_ROOT}:/tmp \
    alpine:latest \
    -c 'chown -R ${HOST_UID}:${HOST_UID} /tmp/'

Давайте разберем некоторые строки:

  • Запустите /bin/sh внутри контейнера:

--entrypoint/bin/sh

  • Передайте текущий пользовательский uid как переменную среды в контейнер:

-e HOST_UID = id -u

  • Смонтируйте любую папку, которую вы хотите вернуть обратно своему пользователю (заполненную файлами, принадлежащими пользователю root, выведите -e d предыдущим контейнером, который выполнялся как root), в этом новом контейнере /tmp:

-v $ {HOST_FOLDER_OWNED_BY_ROOT}: /tmp

  • Рекурсивно запустите chown с uid пользователя хоста над целевым каталогом (смонтированным внутри контейнера в /tmp):

-c 'chown -R $ {HOST_UID}: $ {HOST_UID}/tmp/'

Итак, с этим я вернул файлы, принадлежащие моему текущему пользователю, без необходимости "повышать" привилегии до root или до sudo.

Это грязно, но это сработало. Надеюсь, я помог.