Запуск Docker с правами root создаёт риски для безопасности всей системы и размещённых на VPS сервисов. Rootless-режим позволяет запускать весь стек Docker от имени непривилегированного пользователя, сохраняя функциональность и повышая безопасность. В статье — установка и принципы работы Docker в режиме Rootless.
Введение
Запуск демона Docker с привилегиями root представляет собой риск безопасности для всей системы. Традиционная архитектура Docker предполагает, что он работает от имени суперпользователя, что даёт контейнерам практически неограниченный доступ к ресурсам хостовой операционной системы. Любая уязвимость в коде Docker, ошибка в конфигурации или компрометация одного контейнера может привести к полному захвату контроля над хост-машиной. Злоумышленник, получивший доступ к сокету Docker (/var/run/docker.sock), автоматически получает возможность выполнять произвольные команды на уровне всей системы, создавать новые контейнеры с привилегированным доступом и манипулировать сетевыми настройками.
Rootless-режим переносит весь рабочий процесс из привилегированного пространства в пользовательское. Речь идет не просто о запуске отдельных контейнеров с опцией --user для ограничения прав процессов внутри них, а о полном отказе от привилегий на уровне всего Docker-демона. В Rootless-режиме весь стек Docker — включая демон, рантаймы и управляющие утилиты — работает от имени пользователя без прав root.
Как работает Rootless-режим
Механизмы пространств имён
В основе Rootless-режима лежат два механизма пространств имён Linux. Пользовательские пространства имён (User namespaces) обеспечивают маппинг идентификаторов пользователей и групп между хост-системой и контейнером. Это позволяет непривилегированному пользователю на хосте (например, с UID 1000) внутри контейнера иметь права root (UID 0) — без реальных привилегий на основной системе. Маппинг осуществляется через файлы /etc/subuid и /etc/subgid, где для каждого пользователя выделяется диапазон доступных ID, например:
user1:100000:65536
user2:165536:65536
Network namespace предоставляет изоляцию сетевого стека, но в Rootless-режиме реализация отличается от традиционной. Поскольку непривилегированный пользователь не может создавать стандартные сетевые интерфейсы (veth, bridge), используется пользовательский сетевой стек.
Ключевые компоненты Rootless
Для работы Rootless-режима нужно несколько специализированных утилит. newuidmap и newgidmap обеспечивают маппинг идентификаторов между пространствами имён, используя заранее выделенные диапазоны из /etc/subuid и /etc/subgid. Эти утилиты имеют setcap-биты, позволяющие непривилегированным пользователям работать с UID/GID маппингом.
slirp4netns, ещё одна обязательная утилита, создаёт пользовательский сетевой стек, эмулирующий TCP/IP функциональность без требований к привилегиям.
fuse-overlayfs предоставляет альтернативу нативному драйверу overlay2, работая полностью в пользовательском пространстве через FUSE (Filesystem in Userspace). Это устраняет необходимость в привилегиях для монтажа файловых систем.
Архитектура традиционного и rootless-демона
Традиционная архитектура Docker использует демон dockerd, работающий с привилегиями root и имеющий прямой доступ к системным ресурсам. Все операции управления контейнерами, сетью и хранилищем выполняются с максимальными правами.
В Rootless-архитектуре демон работает как пользовательский процесс без привилегий. Сетевые операции перенаправляются через slirp4netns, работа с файловыми системами — через fuse-overlayfs, а управление именами пространств — через newuidmap/newgidmap.
Различия в архитектуре объясняют некоторые ограничения Rootless-режима, включая особенности работы с сетью, производительность и совместимость с определенными функциями Docker
Установка компонентов Rootless на Ubuntu 24.04
Предварительные требования
Перед установкой выполните обновление:
sudo apt update
sudo apt upgrade -y
Установите необходимые зависимости:
sudo apt install uidmap dbus-user-session fuse-overlayfs slirp4netns
Убедитесь, что для вашего пользователя выделены диапазоны UID и GID:
grep ^$(whoami): /etc/subuid
grep ^$(whoami): /etc/subgid
Если записи отсутствуют, добавьте их, указав начальный ID и количество (например, 100000 и 65536):
sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 $(whoami)
Убедитесь, что в системе включена поддержка user namespaces (в Ubuntu 24.04 она активирована по умолчанию):
sysctl kernel.unprivileged_userns_clone
Установка Rootless Docker
Установите пакет docker-ce-rootless-extras, который включает в себя скрипт настройки и зависимости:
sudo apt install docker-ce-rootless-extras
После установки пакета, запустите скрипт:
dockerd-rootless-setuptool.sh install
Скрипт выполнит следующие действия:
- проверит наличие настроенных подчинённых UID/GID в /etc/subuid и /etc/subgid,
- создаст необходимые директории конфигурации в ~/.local/share/docker,
- настроит и запустит пользовательский сервис systemd для управления демоном.
Настройка переменных окружения
Для корректной работы в Rootless-режиме нужно настроить переменные окружения. Добавьте следующие строки в ~/.bashrc или ~/.profile:
export DOCKER_HOST=unix:///run/user/$(id -u)/docker.sock
export PATH=/home/$(whoami)/bin:$PATH
Это настроит DOCKER_HOST для подключения к пользовательскому демону и добавит пути к бинарным файлам Rootless Docker в PATH.
Примените изменения:
source ~/.bashrc
Проверка установки
Убедитесь, что установка прошла успешно, проверив статус демона и конфигурацию:
systemctl --user status docker.service
docker info | grep Rootless
docker version
Вывод команды docker info | grep Rootless должен содержать Rootless: true.
Дополнительная настройка
Для автоматического запуска демона при входе в систему выполните:
systemctl --user enable docker
Убедитесь, что задержка (linger) включена для вашего пользователя:
sudo loginctl enable-linger $(whoami)
После этого Docker будет работать в полностью изолированном Rootless-режиме, обеспечивая повышенную безопасность без потери функциональности.
Ограничения Rootless-режима и их обход
Сетевые ограничения
Одно из основных ограничений Rootless-режима касается работы с сетевыми портами. Процесс в Rootless-режиме не имеет прав для прямого захвата привилегированных портов (ниже 1024). Если контейнеру нужно прослушивать низкие порты, используйте механизм проброса портов — настройте перенаправление с помощью iptables. Например, следующее правило перенаправляет внешний трафик с порта 80 хоста на порт 8080, который уже может прослушивать контейнер:
sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080
Для перенаправления локального трафика добавьте правило в цепочку OUTPUT:
sudo iptables -t nat -A OUTPUT -o lo -p tcp --dport 80 -j REDIRECT --to-port 8080
Правила iptables сбрасываются после перезагрузки, чтобы сохранить их, используйте пакет netfilter-persistent.
Альтернативным решением является использование утилиты authbind, которая делегирует право на bind к конкретному порту для непривилегированного пользователя. Установите authbind и настройте доступ к нужному порту (например, 80) для вашего пользователя:
sudo apt install authbind
sudo touch /etc/authbind/byport/80
sudo chmod 500 /etc/authbind/byport/80
sudo chown $USER /etc/authbind/byport/80
После этого запуская контейнер, используйте authbind в команде запуска (способ зависит от вашего метода запуска Docker).
Rootless Docker не поддерживает некоторые сетевые драйверы, такие как macvlan и overlay. Вместо них используйте стандартный bridge-драйвер или пользовательские решения на основе технологий туннелирования.
Чтобы ping работал внутри контейнеров также нужна дополнительная настройка:
docker run --cap-add=NET_RAW --rm alpine ping -c 4 example.com
Производительность
Использование slirp4netns может снизить сетевую производительность. Для оптимизации можно использовать следующие параметры:
slirp4netns --enable-seccomp --enable-sandbox --mtu=1500
fuse-overlayfs может быть медленнее нативного overlay2 драйвера. Для критичных к производительности приложений рекомендуется использовать VFS драйвер (как временное решение):
dockerd --storage-driver vfs
Регулярно проверяйте производительность файловой системы:
docker run --rm -it alpine dd if=/dev/zero of=test.bin bs=1M count=100
И сетевую производительность:
docker run --rm --network host nicolaka/netshoot netstat -i
Для продакшен-сред стоит оценить производительность и при необходимости рассмотреть традиционный Docker с дополнительными мерами безопасности (AppArmor, SELinux).
Совместимость
Некоторые флаги docker run несовместимы с Rootless-режимом. Неработающие флаги:
- --privileged
- --device /dev/sda
- --network host
Альтернатива --device /dev/sda для FUSE устройств:
docker run --device /dev/fuse
Доступ к устройствам ограничен. Для работы с USB и другими устройствами создайте группу для устройства, добавьте пользователя:
sudo groupadd usbusers
sudo usermod -aG usbusers $USER
Настройте права доступа:
sudo chgrp usbusers /dev/bus/usb/*/*
sudo chmod g+rw /dev/bus/usb/*/*
Заключение
Rootless-режим в Docker — это шаг вперёд в сторону безопасного контейнерного окружения. Он устраняет главный риск классической модели — работу демона с правами суперпользователя, что позволяет запускать контейнеры без угрозы для всей системы. Да, Rootless имеет ограничения по производительности, сетевым настройкам и совместимости, однако для большинства сценариев разработки и тестирования он остаётся практичным и надёжным решением. В продакшене такой режим может стать дополнительным уровнем защиты, а при необходимости — сочетаться с традиционным Docker и механизмами усиленной безопасности (AppArmor, SELinux). В итоге Rootless-режим — это баланс между удобством, функциональностью и безопасностью, который стоит рассмотреть каждой команде, работающей с контейнерами.
Читайте в блоге:
- Защита Docker-контейнеров с AppArmor
- Docker Compose на Ubuntu 24.04: управление многоконтейнерными приложениями
- CI/CD на базе Ubuntu 24.04 LTS: GitHub Actions, Docker, NGINX