Rootless-контейнери на Podman: що ламається у звичній схемі
Класична схема запуску контейнерів передбачає, що керівний демон працює від суперкористувача, а процес усередині за замовчуванням отримує root-права. Поки все стабільно, це непомітно: служба живе у своїй ізоляції, томи монтуються, порти публікуються.
Але варто знайтися вразливості або помилці в правах доступу — і атакувальник опиняється не в пісочниці, а на самому вузлі, з видом на сусідні контейнери, керівний сокет і файлову систему хоста.
Ціна такої архітектури — єдина точка відмови. Один скомпрометований контейнер рівнозначний компрометації всієї машини: з нього знімаються секрети сусідніх служб, читаються спільні томи, правляться конфігурації. Ізоляція служб перестає бути межею безпеки і залишається лише зручним пакуванням.
Podman прибирає з рівняння привілейований демон: у rootless-режимі контейнери запускаються в окремому просторі імен користувача, де root усередині відповідає непривілейованому ідентифікатору зовні.
Навіть за успішного прориву застосунок отримує права звичайного користувача — без запису в системні каталоги й без доступу до чужої контейнерної інфраструктури.
Перехід змінює звички: інакше налаштовуються томи й порти нижче 1024, частина образів вимагає явного зіставлення ідентифікаторів, а керування без системного демона спирається на інші механізми. Розбираємо, як це закривається і що саме потрібно перебудувати в наявному контурі.
Що дає переведення служб на контейнери без прав root
Переведення служб на контейнери, що запускаються від непривілейованого користувача, змінює не зручність, а клас відмов і радіус ураження. Процес без прав root не змонтує каталоги вузла й не запише в системні шляхи — компрометація контейнера залишається всередині його оточення.
Поверхня атаки скорочується не окремими налаштуваннями, а самою моделлю запуску: у служби немає прав на те, що зазвичай експлуатують.
Далі — ізоляція збою. Помилка в одному сервісі більше не означає падіння всього вузла: у кожного контейнера свої ліміти на пам'ять і процесор, і вичерпання ресурсів одним процесом не тягне за собою інші.
Клас відмов «впав вузол — лягли всі служби» йде з практики, а разом із ним і найдорожча частина простою сервісу — час на підйом усього хоста.
Автозапуск контейнерів описується заздалегідь: служби піднімаються після перезавантаження в заданому порядку, з політикою перезапуску й залежностями між собою.
Час відновлення служби вимірюється десятками секунд замість ручного розбору «що і в якому порядку запускати» — інженер не зайнятий рутиною, а лише перевіряє результат.
І єдине середовище розробки й продуктива: локально й на сервері використовується один образ і одна команда запуску, відрізняються лише параметри оточення й точки монтування.
Це прибирає розбіжності «у мене працює, на сервері ні», а Podman на робочій машині поводиться так само, як на бойовому вузлі, тому попередня перевірка перестає бути окремим етапом.
Podman і альтернативи: порівняння режимів запуску
Режим запуску визначає, що станеться за компрометації контейнера і наскільки передбачувано сервіс переживе перезавантаження вузла. Привілейований рушій зручний: контейнер бачить пристрої хоста, займає порт нижче 1024 і монтує будь-який каталог.
Плата — спільний демон і процес із правами root, де помилка в образі перетворюється на повний доступ до вузла.
Контейнер від імені сервісного користувача знімає це обмеження: ядро тримає процес у межах прав цього користувача, і вихід за них вимагає окремої помилки конфігурації.
Сумісність зі звичними командами зберігається — Podman повторює синтаксис запуску, тому скрипти розгортання переносяться заміною виклику, а не переписуванням.
Обмеження режиму видно на практиці: привілейовані порти вимагають пробросу, шари пишуться в просторі користувача, потрібен виділений діапазон subuid/subgid.
| Варіант | Коли підходить | Обмеження |
|---|---|---|
| Привілейований рушій на вузол | Доступ до пристроїв, томів хоста, портів нижче 1024; успадковані образи | Спільний демон — єдина точка відмови; контейнер із root усередині дорівнює root на вузлі |
| Контейнер від імені сервісного користувача | Веб-сервіси, черги, збирачі, фонові завдання без спецправ | Немає портів нижче 1024 без пробросу; повільніший запис у шари; частина можливостей ядра недоступна |
| Нативні служби поза контейнерами | Одиночний процес, оновлення пакетним менеджером, ізоляція не потрібна | Залежність від бібліотек хоста; немає переносимості; відкат версії складніший |
Змішана схема робоча: rootless за замовчуванням на всіх вузлах, окремі машини з привілейованим рушієм — під конкретне навантаження. Ключове — зафіксувати, які привілеї справді потрібні, і не видавати більше.
Порядок переведення служб: від аудиту вузла до передачі
Переводимо служби на rootless-контейнери (Podman) етапами: кожен наступний спирається на результат попереднього. Помилка видна на кроці, де вона з'явилася, а не в момент відмови продуктивної служби.
- Аудит вузла. Збираємо інвентаризацію: які служби запущені, від чийого імені, які порти й каталоги займають, що стартує із systemd і планувальника. Фіксуємо залежності між сервісами — без них схема розміщення вийде довільною.
- Схема розміщення служб. Розкладаємо сервіси за користувачами: що йде в rootless-контур, що залишається системним, де потрібні спільні томи й проброс портів. Схему узгоджуємо з вами до правок на вузлі.
- Підготовка оточення. Вмикаємо користувацькі простори імен, задаємо обмеження ресурсів і правила для тривалих сесій. Перевіряємо, що контейнери живуть після виходу адміністратора із системи — інакше падають разом із сесією.
- Налаштування ізоляції та автозапуску. Кожній службі — свій користувач, свої томи й порти, права на файли лише там, де потрібно. Автозапуск оформлюємо описами служб із явним порядком старту, що повторює реальні зв'язки сервісів.
- Перевірка відмовостійкості. Перезавантажуємо вузол, обриваємо мережу, гасимо служби по одній, заповнюємо диск. Бачимо, що піднімається саме, що втрачає дані, а що потребує ручного втручання.
- Передача в експлуатацію. Віддаємо конфігурацію, схему розміщення, інструкції з типових операцій і відкату. Прогоняємо супровід за сценаріями, щоб робота вузла не залежала від автора впровадження.
Пакет передачі: конфігурації, схеми, регламенти доступу
Передача влаштована так, що команда замовника залишається з робочим контуром, а не з усними домовленостями.
Rootless-режим Podman додає до цього свої нюанси: права користувача, мапінг ідентифікаторів, окремі простори імен — усе, що легко зламати за наступної зміни, якщо не зафіксовано документально.
Тому віддаємо комплект артефактів у репозиторії, який проходить рев'ю як код і оновлюється разом із сервісом.
- Файли конфігурації. Юніти для запуску контейнерів як користувацьких служб, налаштування реєстрів і сховища образів, ліміти ресурсів, параметри ротації журналів — з коментарями, що і навіщо змінюється за зростання навантаження.
- Схеми розгортання. Розміщення служб за вузлами й користувацькими обліковими записами, які томи й мережеві простори спільні, де проходить межа між середовищами розробки й експлуатації.
- Політики доступу. Хто зі співробітників і які групи керують службами, звідки дозволено збирання образів, правила перевірки підпису, заборона привілейованих контейнерів і монтування системних каталогів.
- Регламент оновлення. Порядок викочування нової збірки, перевірки перед перемиканням трафіку, поведінка за зайнятих томів, точки погодження й критерії, за якими реліз вважається успішним.
- Документація й відкат. Покрокові інструкції на типові операції, схема залежностей сервісів, порядок повернення до попередньої збірки з перевіркою, що служба піднялася й відповідає на запити.
- Діагностика й передача знань. Набір команд для розбору інцидентів, розбір конфігурацій на живому середовищі й відповіді на питання інженерів замовника — щоб супровід не залежав від нас.
Кейс: переведення служб на контейнери без привілеїв
Служби на 42 вузлах запускалися від суперкористувача й ділили доступ до сокета контейнерного рушія. Будь-який скомпрометований компонент отримував права на хост, а падіння однієї служби нерідко лікувалося перезапуском усієї машини.
Відновлення після такого збою займало 35–40 хвилин, оновлення виносили в нічне вікно на 3 години, частину викочувань відкочували вручну. Клас відмов «перезапуск усієї машини» спрацьовував у середньому 9 разів за квартал.
Що змінили
Служби перевели в rootless-режим Podman: кожна працює під окремим системним користувачем без доступу до привілейованого рушія. Автозапуск — користувацькі юніти systemd із lingering, тому служба піднімається після перезавантаження вузла без ручного входу.
Томи підключили як bind-mount із мітками SELinux, публікацію портів обмежили списком потрібних, образи — із внутрішнього реєстру з перевіркою підпису. Політику лімітів і журналювання прописали на рівні служби, а не вузла.
Що стало
| Показник | До | Після |
|---|---|---|
| Частка вузлів без прав суперкористувача | 0 із 42 | 38 із 42 |
| Відновлення служби після збою | 35–40 хв | 4–6 хв |
| Відмови класу «перезапуск усієї машини» | 9 за квартал | 0 |
| Вікно оновлення | 3 год уночі | 25 хв удень |
«Раніше одна служба, що впала, тягла за собою весь вузол, тепер перезапускається лише її дерево процесів», — інженер супроводу. Другий учасник коротше: «Вікно оновлення перестало бути нічним — викочуємо вдень і не будимо чергового».
Чотири вузли залишили з привілеями: службам там потрібен прямий доступ до обладнання, це зафіксовано окремою політикою. Решту закрито — компрометація процесу більше не дає прав на хост, а час відновлення скоротився майже на порядок.
Що робити, якщо Podman уже розгорнуто частково
Поки Podman закриває частину служб, а решта працюють за попередньою схемою, це робочий стан, а не аварійний. Небезпека не в співіснуванні двох моделей запуску, а в подвійній підтримці: два набори правил доступу, два способи дивитися журнали, два способи оновлювати образи. Завдання — не відкочувати зроблене, а задати порядок, у якому переїжджає залишок.
Перший крок — інвентаризація: що вже в rootless-режимі, що залишилося, і від чого кожна служба залежить — томи, порти, облікові записи, імена сусідів по мережі.
Більшість історій «зламалося після переїзду» пояснюються саме зв'язками: сусідня служба не розв'язується за іменем у новій схемі або каталог стає недоступним за правами. Це фіксується до будь-яких переміщень.
Далі — черга пріоритетів. Першими переїжджають служби без власного стану: зовнішній проксі, кеш, обробники черг — вони піднімаються за секунди, і помилка коштує хвилини. Служби з даними йдуть останніми: їм потрібні планове вікно, узгоджена копія й перевірка цілісності після.
Поки обидві схеми живі, вхід і мережу виносять на рівень, що не залежить від способу запуску. Імена й точки входу залишаються попередніми, і служби не знають, де живе сусід — перехід розтягується без зупинки роботи.
Завершено його не тоді, коли все запущено в rootless-режимі, а коли на кожну службу залишився один спосіб запуску, один спосіб доставки журналів і один спосіб оновлення. Подвійна підтримка закінчується разом з останнім дублювальним набором правил.
Ізоляція, автозапуск і сумісність: технічні сумніви
Усі заперечення щодо Podman зводяться до чотирьох-п'яти сценаріїв: як віддавати трафік на низькі порти, що з правами на дані, чи запустяться готові образи, чи переживуть контейнери перезавантаження вузла і чи можна переводити служби по одній. Розбираємо кожен по суті — із зазначенням, де потрібне налаштування, а де обмеження справді є.
Що робити з привілейованими мережевими портами?
Rootless-контейнер не може сам зайняти порт нижче 1024. Робочих схем дві: дозволити непривілейованим процесам низькі порти на вузлі або залишити зовні зворотний проксі чи балансувальник, який приймає трафік на 80/443 і передає всередину на високий порт.
Другий варіант кращий: контейнер не отримує зайвих прав, а точка входу трафіку залишається одна і нею керує окремий сервіс.
Як вирішується доступ до файлової системи й мережевих ресурсів?
Каталоги даних монтуються з явним власником — користувачем, від якого працює контейнер, інакше процес усередині не зможе писати. На вузлах із SELinux томи позначаються мітками контексту під час монтування, інакше доступ блокується на рівні мандатного контролю.
Внутрішні мережі створюються як користувацькі, сервіси бачать один одного за іменами, а назовні публікуються лише потрібні порти.
Чи сумісні наявні образи?
Podman працює з OCI-образами, тому зібрані раніше образи запускаються без перезбирання — змінюється команда запуску й спосіб опису сервісів. Основні правки стосуються описів: шляхів монтування, назв мереж, healthcheck і порядку старту залежностей. Ці розбіжності виявляються на етапі перенесення в тестовому середовищі, а не на бойовому вузлі.
Чи піднімуться контейнери після перезавантаження вузла?
Самі по собі — ні: rootless-процеси не піднімає системний менеджер ініціалізації. Вирішується користувацькими юнітами й увімкненим lingering, тоді сервіси стартують під час завантаження, перезапускаються після падіння й коректно зупиняються в заданому порядку. Це ж дає зрозумілу картину залежностей і логів.
Чи можна перевести частину сервісів, а частину залишити як є?
Так, і це найбезпечніший шлях. Вузли з різними середовищами співіснують, поки не конфліктують за порти й томи; зовнішній проксі маршрутизує трафік за сервісами. Переведення йде групами, з відкатом кожної групи окремо — збій на одному сервісі не зачіпає решту.
Обговоримо задачу: які дані потрібні для оцінки
Предметна оцінка збирається з фактів про інфраструктуру, а не із загальних побажань. Чим точніше ви опишете поточний стан і обмеження, тим менше припущень у плані робіт і тим реалістичніші строки. Нижче — мінімум, якого нам зазвичай достатньо, щоб повернутися з оцінкою та планом.
- Перелік вузлів і служб. Скільки хостів і які в них ролі, що вже в контейнерах, а що залишиться на хості: системні демони, планувальник завдань, локальні бази, файлові сервіси.
- Поточний спосіб запуску. Compose-файли, systemd-юніти, скрипти розгортання, свій реєстр образів — за ними видно, що переноситься як є, а що потребує перепакування.
- Вимоги до ізоляції. Чи потрібні роздільні користувачі й мережеві сегменти між службами, доступ до привілейованих портів, спільні томи — від цього залежить схема запуску без root у Podman і порядок роздачі прав.
- Вікна оновлення. Коли допустимо перезапускати служби, який простій вважаєте прийнятним, чи є жорсткі періоди недоступності і в якому порядку можна викочувати вузли.
- Доступ до даних. Де лежать томи й конфіги: локальні диски чи мережеве сховище, що монтується, як влаштовані резервні копії, чи є дані, які не можна виносити за межі вузла.
- Цільові показники. Що вважаємо результатом: час підйому вузла з нуля, час відновлення після збою, частка служб без root, частка автоматизованих перевірок.
Опишіть задачу у вільній формі — цього достатньо, щоб повернутися з оцінкою та планом робіт.







