Поиск по сайту:

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


Процессы в контейнере Docker не должны запускаться с правами root. Безопаснее запускать приложения от имени пользователя без полномочий root, указанного вами в файле Dockerfile, или при использовании docker run. Это минимизирует риск, предоставляя уменьшенную поверхность атаки для любых угроз в вашем контейнере.

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

Почему запуск с правами root опасен?

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

Хотя может показаться, что root внутри контейнера является независимым пользователем, на самом деле это то же самое, что и учетная запись root на вашем хосте. Разделение обеспечивается только механизмами изоляции контейнеров Docker. Нет четкой физической границы; другой процесс вашего контейнера, запущенный пользователем root в ядре вашего хоста. Это означает, что уязвимость в вашем приложении, среде выполнения Docker или ядре Linux может позволить злоумышленникам выйти из контейнера и выполнить операции с привилегиями root на вашем компьютере.

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

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

Запуск контейнерных приложений от имени пользователя без полномочий root

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

Вы должны создать новую учетную запись пользователя на одном из последних этапов в вашем Dockerfile. Этого можно добиться с помощью инструкции USER:

FROM base-image:latest
RUN apt install demo-package
USER demo-user:demo-group
ENTRYPOINT ["demo-binary"]

Контейнеры, запущенные из этого образа, будут работать как demo-user. Пользователь будет членом группы demo-group. Вы можете опустить имя группы, если вам не нужно, чтобы пользователь был в группе:

USER demo-user

Вы можете указать идентификатор пользователя (UID) и идентификатор группы (GID) вместо имен:

USER 950:950

Выделение известных UID и GID обычно является самым безопасным способом продолжения. Это предотвращает сопоставление пользователя в контейнере с учетной записью хоста с чрезмерными привилегиями.

USER часто указывается как предпоследний этап в Dockerfile. Это означает, что вы по-прежнему можете запускать операции, требующие root, на более ранних этапах сборки образа. Инструкция apt install в приведенном выше примере имеет законную потребность в root. Если бы над ней была размещена инструкция USER, apt запускался бы как demo-user, у которого не было бы необходимых разрешений. Поскольку инструкции Dockerfile применимы только к сборкам образов, а не к запуску контейнеров, безопасно отложить изменение пользователя до более позднего времени в вашем Dockerfile.

Изменение пользователя, под которым работает ваш контейнер, может потребовать обновления разрешений для файлов и папок, к которым он обращается. Установите права собственности на любые пути, которые будут использоваться вашим приложением:

COPY initial-config.yaml /data/config.yaml

USER demo-user:demo-group
RUN chown demo-user:demo-group /data

В этом примере каталог /data должен принадлежать demo-user, чтобы приложение могло вносить изменения в свой файл конфигурации. Предыдущий оператор COPY скопировал файл как root. Сокращение доступно при использовании флага --chown с copy:

COPY --chown=demo-user:demo-group initial-config.yaml /data/config.yaml

Смена пользователя при запуске контейнера

Хотя вы можете легко изменить пользователя в своих собственных файлах Dockerfile, многие сторонние приложения продолжают работать с правами root. Вы можете уменьшить риск, связанный с их использованием, устанавливая флаг --user каждый раз, когда вы вызываете docker run. Это переопределяет пользовательский набор в Dockerfile образа.

$ docker run -d --user demo-user:demo-group demo-image:latest
$ docker run -d --user demo-user demo-image:latest
$ docker run -d --user 950:950 demo-image:latest

Флаг --user запускает процесс контейнера от имени указанного пользователя. Это менее безопасно, чем инструкция Dockerfile USER, потому что вам нужно применять ее отдельно к каждой команде docker run. Лучшим вариантом для регулярно используемых изображений является создание собственного производного изображения, которое может установить новую учетную запись пользователя:

FROM image-that-runs-as-root:latest
USER demo-user
$ docker build . -t image-that-now-runs-as-non-root:latest

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

Работа с приложениями, которые должны запускаться от имени root

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

Переназначение пространства имен активируется добавлением поля userns-remap в файл /etc/docker/daemon.json:

{
    "userns-remap": "default"
}

Использование default в качестве значения для userns-remap указывает Docker автоматически создать нового пользователя на вашем хосте с именем dockremap. Корень в контейнерах будет отображаться обратно в dockremap на вашем хосте. Вместо этого вы можете дополнительно указать существующего пользователя и группу, используя комбинацию UID/GID или имя пользователя/имя группы:

{
    "userns-remap": "demo-user"
}

Перезапустите демон Docker после применения изменений:

$ sudo service docker restart

Если вы используете nsuser-remap: default, пользователь dockremap теперь должен существовать на вашем хосте:

$ id dockremap

uid=140(dockremap) gid=119(dockremap) groups=119(dockremap)

Пользователь также должен появиться в подчиненных ID-файлах /etc/subuid и /etc/subgid:

$ dockremap:231500:65535

Пользователю был выделен диапазон из 65 535 подчиненных идентификаторов, начиная с 231500. В пространстве имен пользователя идентификатор 231500 сопоставляется с 0, что делает его пользователем root в ваших контейнерах. Будучи UID с большим номером, 231500 не имеет привилегий на хосте, поэтому атаки с выходом из контейнера не смогут нанести такой большой ущерб.

Все контейнеры, которые вы запускаете, будут запускаться с использованием переназначенного пользовательского пространства имен, если вы не откажетесь с помощью docker run --userns=host. Механизм работает путем создания каталогов с пространством имен внутри /var/lib/docker, которые принадлежат подчиненному UID и GID пользователя с пространством имен:

$ sudo ls -l /var/lib/docker/231500.231500

total 14
drwx------ 5 231500 231500 13 Jul 22 19:00 aufs
drwx------ 3 231500 231500 13 Jul 22 19:00 containers
...

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

Краткое содержание

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

Как автор изображения, вы должны включить инструкцию USER в свой Dockerfile, чтобы ваше приложение работало без root. Пользователи образа могут переопределить это с помощью docker run --user, чтобы назначить определенный UID и GID. Это помогает смягчить случаи, когда образ обычно использует root.

Вы можете усилить безопасность, удалив все возможности из контейнера с помощью --cap-drop=ALL, а затем добавив необходимые в белый список с помощью флагов --cap-add. Комбинация этих методов запустит ваше приложение от имени пользователя без полномочий root с минимальным набором необходимых ему привилегий, что улучшит вашу безопасность.




Все права защищены. © Linux-Console.net • 2019-2024