png
к ленте

Пользователь в Docker

Апрель'19

Андрей Копылов, наш технический директор, любит, активно использует и пропагандирует Docker. В новой статье он рассказывает, как создать пользователей в Docker. Правильная работа с ними, почему пользователей нельзя оставлять с root правами и, как решить задачу несовпадения идентификаторов в Dockerfile.

Все процессы в контейнере будут работать из-под пользователя root, если специальным образом его не указать. Это кажется очень удобно, ведь у этого пользователя нет никаких ограничений. Именно поэтому работать под рутом неправильно с точки зрения безопасности. Если на локальном компьютере никто в здравом уме не работает с рутовыми правами, то многие запускают процессы под рутом в контейнерах.

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

Создание пользователя

Создание пользователя в контейнере не отличается от его создания в линуксовых дистрибутивах. Однако для разных базовых образов команды могут различаться.

Для дистрибутивов основанных на debian в Dockerfile необходимо добавить:

RUN groupadd --gid 2000 node \
&& useradd --uid 2000 --gid node --shell /bin/bash --create-home node

Для alpine:

RUN addgroup -g 2000 node \
&& adduser -u 2000 -G node -s /bin/sh -D node

Запуск процессов от пользователя

Для запуска всех последующих процессов от пользователя с UID 2000 выполните:

USER 2000

Для запуска всех последующих процессов от пользователя node выполните:

USER node

Подробнее в документации.

Монтирование томов

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

Часто на линуксовом компьютере у пользователя UID и GID равны 1000. Эти идентификаторы присваиваются первому пользователю компьютера.

Узнать свои идентификаторы просто:

id

Вы получите исчерпывающую информацию о своем пользователе. Замените 2000 из примеров на свой идентификатор и все будет в порядке.

Присвоение пользователю UID и GID

Если пользователь создан ранее, но необходимо изменить идентификаторы, то можно сделать это так:

RUN usermod -u 1000 node \
&& groupmod -g 1000 node

Если вы используете базовый образ alpine, то нужно установить пакет shadow:

RUN apk add —no-cache shadow

Передача идентификатора пользователя внутрь контейнера при построении образа

Если ваш идентификатор и идентификаторы всех людей, которые работают над проектом, совпадают, то достаточно указать этот идентификатор в Dockerfile. Однако часто идентификаторы пользователей не совпадают.

Как осуществить желаемое не сразу понятно. Для меня это было самым сложным в процессе освоения docker. Многие пользователи docker не задумываются о том, что есть разные этапы жизни образа. Сначала образ собирается для этого используют Dockerfile. При запуске контейнера из образа Dockerfile уже не используется.

Создание пользователей должно происходить при построении образа. Это же касается и определения пользователя, из-под которого запускаются процессы. Значит, что мы каким-то образом должны передать внутрь контейнера UID (GID).

Для использования внешних переменных в Dockerfile служат директивы ENV и ARG. Подробное сравнение директив тут.

Dockerfile

ARG UID=1000
ARG GID=1000
ENV UID=${UID}
ENV GID=${GID}
RUN usermod -u $UID node \
&& groupmod -g $GID node

Передать аргументы через docker-compose можно так:

docker-compose

build:
context: ./src/backend
args:
UID: 1000
GID: 1000

P.S. Для освоения всех премудростей docker недостаточно читать документацию или статьи. Нужно много практиковаться, нужно почувствовать docker.