Инструкция USER без прав root

Тема дорожной карты · Docker & Containers

В контейнерной среде Docker важно обеспечить безопасность приложения, особенно когда речь идет о запуске процессов от имени пользователя без прав root. Это позволяет минимизировать риски, связанные с эксплуатацией уязвимостей и снижает угрозу для всей системы. Создание отдельного пользователя в Dockerfile (RUN adduser -D -u 10001 app) и последующее переключение на него инструкцией USER app (или USER 10001) перед CMD является стандартной практикой для повышения безопасности.

Дополнительно, использование опций --read-only, --cap-drop=ALL и rootless Docker обеспечивает защиту на нескольких уровнях (defense-in-depth). Однако, при работе с инструкцией USER необходимо учитывать ряд особенностей и возможных ошибок. Например, при копировании файлов с помощью COPY, владельцем по умолчанию становится пользователь root, что может быть потенциально опасным. В таких случаях следует использовать опцию COPY --chown=app:app, чтобы установить владельца как app.

Кроме того, важно помнить, что слушать порты, номера которых меньше 1024, можно только с правами root. Если ваше приложение требует использования таких портов, необходимо использовать команду setcap cap_net_bind_service=+ep. Также стоит отметить, что некоторые официальные образы Docker уже содержат непривилегированных пользователей, таких как node, nginx-unprivileged.

Как это работает

Инструкция USER без прав root применяется в различных сценариях, таких как BuildKit (современный builder, который стал дефолтным с версии 23.0), multi-stage сборки, использование build-secrets и cache mounts. Примеры использования включают хранение npm/pnpm кэша между сборками с помощью RUN --mount=type=cache,target=/root/.npm и инжектирование секретов, которые не попадают в слой, с помощью RUN --mount=type=secret,id=mytoken.

Также важно различать переменные окружения, которые задаются на этапе сборки (ARG), и те, которые используются во время выполнения (ENV). Инструкция HEALTHCHECK определяет, как Docker проверяет состояние контейнера, что особенно важно для долгоживущих сервисов.

Когда применять

Инструкция USER без прав root особенно полезна при использовании BuildKit с опцией --mount=type=cache, что значительно ускоряет время сборки и уменьшает время CI. Эта комбинация особенно эффективна, когда сборка скачивает пакеты, что характерно для большинства современных приложений.

Мульти-платформенные сборки с помощью buildx также являются важным применением инструкции USER. Они особенно полезны, когда таргет может быть как x86_64, так и arm64 (например, Raspberry Pi, M-series Mac, Graviton).

Инструкция HEALTHCHECK особенно полезна для долгоживущих сервисов, таких как веб-серверы или базы данных. Она делает ожидания compose up и пробы оркестратора корректными, обеспечивая стабильную работу системы.

Типичные ошибки

Когда вы работаете с инструкцией USER, важно избегать типичных ошибок. Например, использование секретов через ARG может привести к утечке информации в истории сборок и docker inspect. Также важно избегать сбоя кэша после каждого apt update, объединяя apt-команды в один RUN, чтобы избежать изменения следующей инструкции.

Кроме того, забытый флаг DOCKER_BUILDKIT=1 на старом Docker может привести к ошибке "unknown flag" на --mount. Использование инструкции HEALTHCHECK с интервалом проверки каждые 30 секунд и стартом 90 секунд может привести к тому, что контейнер будет помечен как unhealthy еще до того, как он будет готов к использованию.

Связанные понятия

Полезные ресурсы