Представьте, что ваш контейнерный движок работает от root. Теперь представьте, что злоумышленник нашел уязвимость в демоне. Поздравляю! У него теперь root на всей вашей системе.
Безопасность стала необходимостью, архитектура Docker с его привилегированным демоном похож на пережиток прошлого. Podman предлагает иной подход: контейнеры без root, где каждый процесс запускается от имени обычного пользователя.
Как это работает? Как обычный пользователь может изолировать процессы, создавать сетевые пространства и управлять хранилищем без единой привилегии? Давайте разберемся, что скрывается за rootless Podman :)
Зачем нужны rootless-контейнеры?
Проблема Docker: демон требует root → единая точка отказа
Принцип минимальных привилегий: зачем давать root для изоляции?
Реальные инциденты: кейсы побега из контейнеров через уязвимости в демоне
⠀⠀
1. User Namespace. Механизм трансляции UID/GID для изоляции контейнеров
# Демонстрация: что видит процесс внутри vs снаружи
# Внутри контейнера:
$ id
uid=0(root) gid=0(root)
# Снаружи на хосте:
$ ps aux | grep nginx
user123 12345 ... nginx
Технические детали:
Системный вызов
unshare(CLONE_NEWUSER)- создание пользовательского namespaceФайлы
/etc/subuidи/etc/subgid:
# Формат файла /etc/subuid:
# username:start_uid:uid_count
user123:100000:65536
# │ │ └─ количество UID (65536)
# │ └───────── начальный UID (100000)
# └─────────────────── имя пользователя (user123)
Маппинг в реальном времени: как uid 0 → 100000, uid 1 → 100001
⠀⠀
2. Глубокая настройка subuid/subgid
Проблемы и решения:
Автоматическая настройка через
podman system migrateРучная настройка для системных пользователей
Конфликты диапазонов между пользователями
Проверка конфигурации:
$ podman unshare cat /proc/self/uid_map
0 1000 1
1 100000 65536
⠀⠀⠀
3. Сетевые вызовы: slirp4netns vs pasta
Slirp4netns - TUN/TAP в userspace:
Архитектура: процесс-посредник, эмулирующий сетевой стек
Ограничения: производительность NAT, задержки
Диагностика:
podman run --network=slirp4netns
Pasta - прямое пробрасывание сокетов:
Принцип работы: проброс портов без NAT
Производительность: почти нативная скорость
Настройка:
podman run --network=pasta
Сравнительная таблица:
Аспект |
slirp4netns |
pasta |
|---|---|---|
Производительность |
~80% от нативной |
~95% от нативной |
Совместимость |
высокая |
требуется современное ядро |
Порты <1024 |
через sudo |
напрямую |

⠀⠀
4. Хранилище: OverlayFS без root
Проблемы файловой системы:
Права доступа: кто владеет файлами в образах?
Драйверы хранилища:
vfs,overlay,fuse-overlayfsНастройка в
/etc/containers/storage.conf:
[storage]
driver = "overlay"
graphroot = "/home/user/.local/share/containers/storage"
FUSE-overlayfs - решение для rootless:
Архитектура: FUSE-драйвер для OverlayFS
Производительность: сравнение с привилегированным режимом
Проблемы с hard links: ограничения и обходы
⠀⠀⠀
5. Ограничения и обходные пути
Что не работает в rootless:
Прямой доступ к сетевым устройствам
Изменение системных параметров через
/proc/sysМонтирование специфичных файловых систем (cgroup2, proc)
Работа с аппаратными устройствами
Обходные решения:
podman run --deviceс правильными правамиsysctl через
--security-opt systempaths=unconfinedПортирование приложений под rootless
⠀⠀⠀
6. Бенчмарки: Цена безопасности
Методология тестирования:
CPU:
sysbench cpu runПамять:
mbw,sysbench memoryСеть:
iperf3,netperfДиск:
fio,bonnie++
Результаты:
CPU: разница < 2%
Память: дополнительные ~15MB на процесс изоляции
Сеть: slirp4netns -20% throughput, pasta -3%
Диск: fuse-overlayfs -8% IOPS
⠀⠀⠀
7. Реальные кейсы миграции
Миграция с Docker:
# Экспорт из Docker
$ docker save app > app.tar
# Импорт в Podman
$ podman load < app.tar
$ podman run --user 1000:1000 app
Проблемы и решения:
Образы с fixed UID: пересборка или
podman unshare chownСетевые порты: перенос на порты >1024
Volumes с правами: настройка правильного владельца
⠀
⠀⠀
Техническая глубина: Анализ системных вызовов
// Пример последовательности вызовов
unshare(CLONE_NEWUSER); // Создание user namespace
unshare(CLONE_NEWNS); // Mount namespace
unshare(CLONE_NEWNET); // Network namespace
setgid_map(...); // Настройка маппинга GID
setuid_map(...); // Настройка маппинга UID
execve("/app"); // Запуск приложения
Отладка и мониторинг:
strace -f podman run alpinensenter для диагностики namespacescat /proc/self/status | grep Cap- проверка capabilities
⠀⠀⠀
⠀⠀
Что дальше? Практическое внедрение
Попробуйте прямо сейчас:
# Установите Podman
sudo apt install podman
# Настройте rootless
podman system migrate
# Запустите ваш первый безопасный контейнер
podman run --rm -it -p 8080:8080 \
--name my-app \
--user 1001:1001 \
docker.io/nginx

Комментарии (2)

GritsanY
14.11.2025 08:44Больше похоже на список буллетов для презентации и последующего разъяснения, чем на статью. Либо для тех, кто уже и так глубоко в теме, но зачем им статья, оправдывающая существование rootless-контейнеризации?
gotch
Rootless mode | Docker Docs