🐳 Переключение пользователя в образе или контейнере Docker

смена пользователя Docker

by itisgood

1. Обзор

В этом руководстве мы узнаем, как переключать пользователей в образе или контейнере Docker.

2. Почему мы переключаем пользователей?

Механизм пользователей и групп в Linux – это фундаментальный механизм контроля доступа и безопасности, который позволяет ассоциировать файлы с определенными пользователями и группами.

Это позволяет ограничить доступ к важным файлам только авторизованным пользователям и группам и предотвратить несанкционированный доступ.

Как следствие, это значительно уменьшает поверхность атаки в случае нарушения безопасности.

В контексте Docker лучшей практикой безопасности считается отказ от запуска контейнеров от имени пользователя root.

Поскольку контейнеры Docker используют одно и то же ядро с хост-системой, запуск от имени root-пользователя подвергает всю систему потенциальным атакам.

К сожалению, большинство базовых образов по умолчанию имеют права пользователя root.

Чтобы снизить этот риск, рекомендуется всегда переключаться на не root-пользователя в образах Docker.

Тем самым мы ограничиваем потенциальный ущерб от нарушения безопасности и обеспечиваем безопасность нашей системы.

3. Переключение пользователя при создании образа Docker

Чтобы собрать образ Docker, мы пишем ряд инструкций в Dockerfile.

Затем мы выполняем команду docker build, чтобы превратить Dockerfile в образ Docker.

На протяжении всех шагов мы иногда хотим перейти к другому пользователю, будь то временно или для установки пользователя по умолчанию для образа Docker.

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

3.1. Директива USER

Директива USER в Dockerfile задает идентификатор пользователя (UID) и, по желанию, идентификатор группы (GID) пользователя, который будет использоваться на последующих этапах сборки.

Количество смен пользователей с помощью директивы USER не ограничено.

Одним из распространенных вариантов является временное переключение пользователя на пользователя root для установки зависимостей, требующих эскалации, и последующее переключение на пользователя, не являющегося root.

Директива USER в Dockerfile принимает в качестве аргумента имя пользователя и необязательный аргумент группы, с которой должен ассоциироваться пользователь:

USER <user>[:<group>]

Кроме того, синтаксис также поддерживает UID и GID напрямую:

USER <UID>[:<GID>]

Если у пользователя нет основной группы и мы не указываем группу при использовании директивы USER, то по умолчанию будет использоваться группа root.

3.2. Использование директивы USER

Чтобы продемонстрировать работу этой директивы, давайте соберем простой образ на основе базового образа Alpine Linux с пользователем по умолчанию root:

$ cat Dockerfile
FROM alpine:3.18.0

WORKDIR /tmp

RUN touch file
CMD ls -lh .

Во-первых, в Dockerfile в качестве базового образа указывается alpine:3.18.0 – это Docker-образ Alpine Linux версии 3.18.0.

🐧 Как обновить Alpine Linux до последней версии

Затем с помощью директивы WORKDIR мы устанавливаем рабочий каталог по адресу /tmp.

Затем выполняем shell-команду touch file для создания пустого файла.

Наконец, с помощью директивы CMD мы запускаем команду ls -lh при каждом запуске образа Docker.

Затем мы можем собрать образ с помощью команды docker build:

$ docker build --tag simpleimage:latest .

Запустив образ Docker, мы увидим в выводе, что файлы принадлежат пользователю root и группе root:

$ docker run --rm simpleimage:latest
total 0
-rw-r--r--    1 root     root           0 May 14 01:30 file

Теперь перепишем наш Dockerfile, чтобы использовать директиву USER для смены пользователя на appuser:

$ cat Dockerfile
FROM alpine:3.18.0

WORKDIR /tmp
RUN adduser -D appuser
USER appuser

RUN touch file
CMD ls -lh .

Во-первых, мы создаем пользователя appuser в контейнере с помощью команды adduser.

Без предварительного создания пользователя директива USER не сработает, поскольку не сможет преобразовать appuser в действительный UID:

unable to find user appuser: no matching entries in passwd file

Запустив образ Docker, мы увидим, что теперь файл принадлежит appuser:

$ docker run --rm simpleimage:latest
total 0
-rw-r--r--    1 appuser       appuser           0 May 14 01:56 file

Другими словами, после того как директива USER изменит пользователя на appuser, движок Docker выполнит команду RUN touch file от имени appuser.

3.3. Почему директива RUN su не работает

Одна из распространенных ошибок – переключение пользователя с помощью команды su с помощью директивы RUN в Dockerfile.

В частности, мы можем ошибочно полагать, что вместо директивы USER можно заменить ее на RUN sh для достижения того же результата:

$ cat Dockerfile
FROM alpine:3.18.0

WORKDIR /tmp

RUN adduser -D appuser
RUN su appuser

RUN touch file
CMD ls -lh .

Смысл приведенного выше Dockerfile заключается в том, чтобы выполнить первую команду RUN su appuser для перехода в статус пользователя appuser.

После этого, как мы ожидаем, остальные директивы будут выполняться от имени пользователя appuser.

Однако мы увидим, что команда su appuser не сохраняется на уровне образов:

$ docker build . -q --tag simpleimage:switch-user-with-s
$ docker run --rm simpleimage:switch-user-with-su
total 0      
-rw-r--r--    1 root     root           0 May 14 04:41 file

Чтобы понять, почему изменить пользователя в образе Docker не так просто, как выполнить команду su, важно знать, как Docker создает образ.

Docker использует серию команд docker run и docker commit для выполнения каждого шага в Dockerfile, при этом каждый шаг запускается как новый контейнер, а изменения фиксируются как новый слой.

Более того, каждая директива RUN запускается в новой оболочке и окружении, поэтому запуск su в отдельной директиве RUN не окажет никакого влияния на последующие шаги, которые запускаются с настройками оболочки по умолчанию.

Это также объясняет, почему изменения, сделанные с помощью команд cd и export, не сохраняются на разных уровнях.

Однако такие директивы, как USER, WORKDIR и ENV, могут изменять настройки оболочки по умолчанию для последующих шагов, включая директивы RUN.

Это позволяет сохранить изменения, сделанные с помощью этих директив, на всех уровнях.

По этой причине для изменения пользователя или группы в образе Docker лучше использовать эти директивы, а не команду su.

Если мы все же хотим использовать команду su для временной смены пользователя для определенных команд, то один из способов обойти эту проблему – передать команду, которую мы хотим выполнить, в опцию -c команды su:

$ cat Dockerfile 
FROM alpine:3.18.0 

WORKDIR /tmp 

RUN adduser -D appuser 

RUN su appuser -c 'touch file' 
CMD ls -lh .

Это обеспечит запуск командного файла touch Docker от имени appuser при сборке образа.

4. Смена пользователя для контейнера Docker

Чтобы запустить контейнер Docker под другим пользователем, можно использовать опцию -user в команде docker run.

Например, запустив образ Alpine Linux командой whoami, мы получим имя пользователя root, которое является пользователем по умолчанию в соответствии с Dockerfile образа:

$ docker run --rm alpine:latest whoami
root

Мы можем указать опцию -user, чтобы запустить тот же контейнер с гостевым пользователем:

$ docker run --rm --user guest alpine:latest whoami
guest

Аналогичным образом мы можем запускать команды на работающем контейнере с помощью опции -user команды docker exec:

$ docker exec --user guest -it alpine whoami
guest

Обратите внимание, что пользователи, от имени которых мы работаем, должны существовать в файле /etc/passwd контейнера Docker.

В противном случае команда завершится неудачей, поскольку не удастся преобразовать имя пользователя в запись пользователя в файле /etc/passwd:

$ docker exec --user unknown -it alpine whoami
unable to find user unknown: no matching entries in passwd file

5. Заключение

В этом руководстве мы вкратце рассмотрели механизм управления доступом пользователей и групп в Linux.

Затем мы узнали, что можно менять пользователей на этапе сборки образа Docker и запуска контейнера.

Смена пользователя на этапе сборки осуществляется просто – с помощью директивы USER в Dockerfile.

Мы также увидели, что команда su неэффективна для смены пользователя при сборке образа Docker.

Наконец, мы узнали, что и команда docker run, и команда docker exec поддерживают опцию -user для смены пользователя.

см. также:

 

You may also like

Leave a Comment