Технологии

Архитектура Rootless Podman: Полное руководство по контейнерам

Представьте, что ваш контейнерный движок работает от 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 alpine nsenter для диагностики namespaces cat /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

Фильтры и сортировка