Ответ
Директива USER в Dockerfile задаёт имя пользователя (или его UID) и опционально группу (или GID), от имени которого будут запускаться все последующие инструкции RUN, CMD и ENTRYPOINT в этом образе.
Форматы указания:
USER <user>(например,USER app)USER <uid>(например,USER 1000)USER <user>:<group>(например,USER app:app)USER <uid>:<gid>(например,USER 1000:1000)
Пример в Dockerfile:
FROM alpine:latest
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
# Копируем файлы от root
COPY --chown=appuser:appgroup app.jar /opt/app/
# Переключаем пользователя
USER appuser
WORKDIR /opt/app
CMD ["java", "-jar", "app.jar"]
Зачем это нужно с точки зрения DevOps и безопасности:
- Снижение привилегий (Principle of Least Privilege): Запуск контейнера от root (по умолчанию, если
USERне указан) даёт процессу внутри контейнера неограниченные права. Если злоумышленник скомпрометирует такое приложение, он получит root-доступ к хостовой системе (особенно при использовании--privilegedфлага или уязвимостей в ядре). Запуск от непривилегированного пользователя минимизирует этот риск. - Соответствие стандартам безопасности: Требования многих compliance-стандартов (например, PCI DSS, CIS Benchmarks) прямо запрещают запуск контейнеров от root.
- Изоляция от хоста: Использование несуществующего на хосте высокого UID (например,
USER 10000:10000) может добавить дополнительный уровень изоляции.
Важные замечания:
- Указанный пользователь или UID/GID должны существовать внутри образа. Их нужно создать с помощью
RUN(как в примере выше) или использовать базовый образ, где они уже есть. - Директива
USERвлияет только на инструкции, следующие за ней в Dockerfile. Инструкции доUSERвыполняются от root (или от пользователя, заданного предыдущей директивойUSER). - Пользователя можно переопределить при запуске контейнера флагом
docker run -u <user>.