Короткий ответ
Если процесс внутри контейнера работает от root и злоумышленник найдёт способ выйти за пределы изоляции (уязвимость runtime, неверно настроенные mounts/capabilities), последствия для хоста будут значительно серьёзнее, чем при непривилегированном пользователе; инструкция USER в Dockerfile создаёт и переключает выполнение на обычного пользователя.
Как это работает подробнее
по умолчанию, если USER не указан, процессы контейнера выполняются от root внутри его user namespace; без дополнительной настройки user namespace remapping (userns-remap на демоне) root внутри контейнера по UID соответствует root на хосте (UID 0), хотя и ограничен изоляцией контейнера. Инструкция USER appuser переключает контекст выполнения последующих инструкций и финального процесса на указанного непривилегированного пользователя.
Пример кода
FROM python:3.12-slim
RUN addgroup --system app && adduser --system --ingroup app appuser
WORKDIR /app
COPY --chown=appuser:app . .
USER appuser
CMD ["python", "server.py"]Что использовать на практике
- Практика. для обслуживающих процессов (веб-сервер приложения, воркер) обычно создают выделенного системного пользователя в образе и переключаются на него перед
CMD/ENTRYPOINT; некоторые официальные базовые образы (например,node,postgres) уже содержат готового непривилегированного пользователя, которого достаточно указать вUSER.
Подводные камни
- Риск. добавляют
USER appuser, но забывают выдать этому пользователю права на директории, в которые приложение пишет файлы (логи, временные файлы, volume), из-за чего контейнер падает с ошибками доступа; путают изоляцию контейнера с полноценной изоляцией виртуальной машины — не-root пользователь внутри контейнера снижает, но не исключает риски при компрометации ядра или runtime.