Безпека контейнерів: Чи ізоляція є абсолютною? (Docker vs. Podman без root привілеїв) | INTROSERV

Безпека контейнерів: Чи ізоляція є абсолютною? (Docker vs. Podman без root привілеїв)

by Nataliya Oteir
Безпека контейнерів: Чи ізоляція є абсолютною? (Docker vs. Podman без root привілеїв)
star 5
0
Прочитати 11 хв.

Фундаментальні обмеження ізоляції контейнерів

Контейнеризація стала домінуючим способом упаковки та доставки додатків у хмарних та мікросервісних архітектурах. Контейнери дозволяють запакувати код, бібліотеки та залежності, забезпечуючи високу портативність та ефективність експлуатації.

Однак масове перенесення критичних робочих навантажень у контейнери робить питання стійкості механізмів ізоляції важливим. Дослідження та опитування DevOps- та security-команд показують, що безпека контейнерів залишається однією з головних зон занепокоєння: уразливості ядра, рантаймів та помилки конфігурації регулярно призводять до реальних проривів ізоляції. 

Ключове питання: чи є ізоляція контейнерів абсолютною?
Відповідь – ні, і причина у їхній архітектурі. У цій статті ми спробуємо детальніше розібратися в цьому питанні, а також розглянемо заходи щодо пом'якшення ризиків вразливостей.

Контейнери проти віртуальних машин: спільне ядро

Віртуальна машина:

  • Кожна VM запускає власне ядро ​​ОС, повністю відокремлене від хоста.

  • Ізоляція забезпечується гіпервізором (KVM, Xen, ESXi тощо).

  • Атака, як правило, має бути спрямована на гіпервізор, що значно звужує вектори.

Контейнери:

  • Контейнер – це процес, ізольований засобами ядра Linux (namespaces, cgroups тощо).

  • Контейнер містить лише user space (бібліотеки, рантайм, додаток), але поділяє одне ядро ​​з хостом та іншими контейнерами.

  • Будь-яка критична вразливість ядра автоматично стає потенційним вектором атаки на всі контейнери на вузлі.

Тобто сам архітектурний вибір у вигляді загального ядра робить ізоляцію контейнерів принципово не абсолютною: успішна експлуатація вразливості ядра дозволяє подолати межі будь-яких просторів імен.

Роль Namespaces та Cgroups у створенні ізоляції

Основу контейнерної ізоляції в Linux становлять Namespaces та Cgroups.

Namespaces – ізоляція подання системи:

  • PID, монтування, мережа, користувач, IPC, UTS тощо.

  • Процеси "бачать" тільки свій простір: свою файлову систему, свої PID, свій hostname і мережу.

Cgroups – контроль та лімітування ресурсів: CPU, пам'ять, I/O, кількість процесів тощо.

Namespaces створюють ілюзію окремої системи, а cgroups не дають одному контейнеру забити ресурси хоста. Але важливо, що Namespaces це механізм ізоляції, а не повноцінний механізм безпеки від цілеспрямованого обходу бар'єрів. Вони не заважають експлуатації вразливостей ядра, не вирішують проблему надмірних привілеїв root або привілейованого контейнера, не фільтрують системні виклики та не керують політиками доступу.

Тому namespaces і cgroups – це все ж таки базовий шар, на який обов'язково повинні накладатися:

фільтрація syscalls (Seccomp), політики MAC (AppArmor/SELinux), обмеження Capabilities та, в ідеалі, простори імен користувачів + rootless-режим.

Безпека контейнерних платформ: критичні загрози та вектори атак

Площа атаки контейнерної платформи багатошарова і можна виділити такі основні поверхні:

  1. Рантайм та ядро ​​(runc, containerd, CRI-O, ядро ​​Linux).

  2. Ланцюжок поставок образів.

  3. Конфігурація контейнерів та оркестратора.

  4. Хмара та інфраструктура (IAM, API, storage, network).

Огляд векторів атак та критичних уразливостей у контейнерному середовищі: Вихід з контейнеру

Типові вектори у контейнерному середовищі: експлуатація CVE у ядрі Linux або рантаймі контейнерів; використання небезпечних образів (старі пакети, exploit kits); помилки конфігурації в Kubernetes/Docker (надмірні привілеї, файлової системи хоста, мережевий стек хоста); компрометація реєстрів та CI/CD.

Важливо розуміти, що Container Escape або “вихід з контейнеру” часто – це комбінація: вразливість ядра/рантайму + погана конфігурація (root, --privileged, файлова система хоста, відсутність MAC/Seccomp).

Вразливість ланцюжка поставок

Ланцюжок поставок контейнерних образів – один із основних ризиків адже базові образи з громадських реєстрів найчастіше містять відомі CVE; залежності (pip/npm/gem/go modules) підтягуються транзитивно і які завжди контролюються. Але найнебезпечніше, що шкідливість може бути “сплячою” і виявлятися вже в рантаймі.

Тому в production обов'язковими будуть "правила гарного тону":

  • сканування образів на CVE, наприклад, Trivy, Clair, Grype та ін.

  • використання “знаючих-політики” реєстрів таких як Harbor, Quay, GHCR з policy.

  • підпис та верифікація образів перед розгортанням.

Помилки конфігурації контейнерних середовищ та привілейовані контейнери

Найбільш частою помилкою, яка широко відчиняє двері вразливостям можна вважати запуск процесів всередині контейнера від root! Якщо програма в контейнері запускається з правами суперкористувача, то при компрометації контейнера атакуючий отримує root всередині контейнера, а при успішному виході за межі контейнера це спрощує ескалацію до root-користувача хоста.

Заборона запуску додатків від root та використання непривілейованих UID/GID – базове правило “правильного” харднінгу.

Привілейовані контейнери з прапором --privileged практично відключають ключові механізми ізоляції, а саме частину обмежень Сgroups, AppArmor/SELinux та Seccomp. Адже це дає контейнеру прямий доступ до пристроїв і псевдофайлових систем хоста (/proc, /sys, /dev та ін.) З привілейованого контейнера легко змонтувати диски хоста, модифікувати файлову систему та конфігурації.

По суті, привілейований контейнер тотожний навмисній ескалації привілеїв. Пам'ятайте – це припустимо тільки в рідкісних, добре ізольованих сценаріях, і точно не в оточенні multi-tenant.

Є ще й так звані "Тихі" помилки конфігурації, які можуть зробити контейнерне середовище надзвичайно вразливим, навіть без використання прапора --privileged. Найбільш небезпечними є монтування hostPath у чутливі директорії хоста, наприклад, /etc або /var/run/docker.sock; надання зайвих Capabilities, наприклад, CAP_SYS_ADMIN, який фактично дає права root на хості, а також необґрунтоване використання режимів hostNetwork або hostPID.

Ці, здавалося б, незначні налаштування можуть дозволити зловмисникові втекти з контейнера та отримати контроль над ядром або всією системою хосту.

Порівняння архітектури: Docker vs. Podman

Архітектурні відмінності Docker та Podman безпосередньо впливають на модель загроз. Docker з демоном, що працює з найвищими привілеями, виявляє головний ризик і єдину точку відмови.

Docker та rootfull-режим

У класичній або, якщо хочете, стандартній архітектурі Docker CLI спілкується з демоном dockerd через сокет /var/run/docker.sock або TCP. Демон dockerd запускається від імені root користувача та виконує основні операції:

  • створення/видалення контейнерів

  • складання образів

  • керування мережею/томами

  • працює з реєстрами

Тому стає зрозуміло, що прямий доступ до Docker API дорівнює майже повному root-доступу до хоста – можна монтувати файлову систему, запускати привілейовані контейнери і т.д. У такому разі демон стає єдиною точкою відмови, і якщо він скомпрометований, то зловмисник отримує доступ до хоста.

Саме тому Docker необхідний жорсткий контроль доступу до сокету, обов'язкове включення MAC, Seccomp, обмеження Capabilities. Ну і звичайно важливо подбати про мінімізацію кількості користувачів і сервісів, які мають доступ до Docker API.

Бездемонний Podman: нативний Linux-підхід

Podman був розроблений Red Hat та спільнотою як більш безпечна, “нативна” для Linux альтернатива. Тут спочатку передбачалася daemonless-архитектура архітектура, в якій немає постійного централізованого демона, а контейнери – це дочірні процеси користувача, який запустив команду. Тобто в основі – глибока інтеграція з systemd, коли юніти та послуги створюються напряму.

Це прибирає єдину точку відмови у вигляді root-демона і краще узгоджується з традиційною Unix-моделлю: "хто запустив процес - той ним і володіє".

Rootless-режим: User Namespaces як головний захисний бар'єр

Взагалі rootless-режим - це логічна відповідь на фундаментальну небезпеку: "а що, якщо контейнер все-таки вирветься назовні?"

Роль User Namespaces та зниження збитків

Простори імен користувачів ізолюють UID/GID і дозволяють замінювати UID. Наприклад, якщо всередині контейнера процес має UID 0, то на хості цей же процес відображається в непривілейований UID з діапазону subuid/subgid.

Тому навіть якщо атакуючий усередині контейнера має root привілеї і навіть якщо йому вдається скористатися вразливістю рантайму/ядра для виходу на рівень хоста, він продовжує працювати як непривілейований користувач на хості.

Багато ланцюжків експлуатації включаючи runc-escape в такому випадку ламаються або дають значно менший ефект тому, що не можна переписати бінарники/конфігурації, що належать root, не можна монтувати файлові системи і керувати пристроями без Capabilities та й MAC-політики продовжують діяти на хості.

Podman Rootless: обмеження та мережевий стек

Podman з самого початку проектувався з прицілом на rootless-операції, коли контейнери створюються і управляються непривілейованим користувачем, користувацькі пространства імен включені за замовчуванням, а SELinux/AppArmor і cgroups використовуються в тій мірі, в якій це можливо без root доступу.

Однак є в цій схемі деякі компроміси. У випадку, коли rootless-контейнер працює в межах діапазону subuid/subgid, можливі помилки мапінгу якщо образ містить файли з UID/GID, що виходять за цей діапазон.

Інший опосередкований мінус такої архітектури в тому, що непривілейований юзер не може вільно налаштовувати мережеві пространства імен. З початку 2025 року Podman використовує user-space стек pasta як заміну slirp4netns. Цей плагін працює повністю в просторі користувача, але завдяки tap-інтерфейсу і zero-copy splice дає майже нативну продуктивність мережі, тобто просадки все-таки можливі. І вже точно забезпечені, якщо користувачі продовжують використовувати slirp4netns.

Docker Rootless: реалізація та вимоги

Докер,також підтримує повноцінний rootless-режим, в якому dockerd демон і контейнери запускаються всередині імен користувача без привілеїв root користувача хоста. І важливо – це відрізняється від старого userns-remap, де демон залишався привілейованим.

З точки зору безпеки, це гарантує, що при прориві з контейнера не відбудеться автоматичної ескалації до рівня root користувача хоста. І у разі успішної атаки на dockerd у rootless-режимі буде отримано доступ лише до ресурсів непривілейованого користувача, а не всієї системи.

Вибір між rootful та rootless-режимами – це насамперед балансування між максимальною продуктивністю та максимальним обмеженням потенційної шкоди у разі прориву.

Висновки та рекомендації щодо харднінгу

Аналіз підтверджує, що ізоляція контейнерів не є абсолютною внаслідок їхньої архітектури. Оскільки контейнери спільно використовують ядро ​​хостової системи, вразливості на рівні ядра або в рантаймі за визначенням дозволяють "бачити" крізь простори імен, порушуючи очікувані межі безпеки.

Насправді більшість успішних атак пов'язані з поєднанням якоїсь відомої вразливості (kernel/runc) і слабкої конфігурації (root, --privileged, hostPath).

Надійна модель безпеки контейнерів має будуватися як багатошарова система:

1-й шар - сегментація (namespaces, cgroups);
2-й шар – політики та фільтрація (Seccomp, MAC, Capabilities);
3-й шар – архітектурне обмеження привілеїв через rootless-режим та User Namespaces.

Чек-лист: харднінг хоста для контейнерів Docker та Podman

  • Rootless за замовчуванням

Розглядати Podman або Docker у rootless-режимі як дефолтну модель для внутрішніх та multi-tenant-навантажень.

  • Hardening ядра та патчі

Оперативно оновлювати ядро ​​(Dirty COW, Dirty Pipe та подібні CVE майже завжди вже закриті патчами). Використовувати дистрибутиви з гарною історією патчів безпеки RHEL, OpenSUSE Ubuntu LTS та ін.

Використання спеціальних незмінних дистрибутивів ОС

Для підвищення безпеки контейнерних середовищ використовуються незмінні (immutable) дистрибутиви ОС, наприклад, OpenSUSE MicroOS. Їхня коренева файлова система за замовчуванням доступна лише для читання, що суттєво знижує поверхню атаки. Ключовий механізм – атомарні оновлення: створюється новий образ ОС, і оновлення або застосовується повністю або повністю відкочується, виключаючи пошкодження системи та прискорюючи відновлення.

  • Принцип найменших привілеїв

Ніколи не використовуйте ключ --privileged у продакті, крім вузько спеціалізованих, ізольованих середовищ. Уникайте запуску програм всередині контейнерів від root користувача, а також використовуйте файлову систему лише для читання, мінімальний набір Capabilities та жорсткі Seccomp-профілі.

  • MAC-політики та Seccomp

Увімкніть і налаштуйте SELinux/AppArmor для контейнерів, використовуйте профілі Seccomp, власні, засновані на реальних системних викликах програми, а не тільки дефолтні від Docker.

  • Security в ланцюжку поставок

Використовуйте сканування образів контейнерів та обмежте кількість джерел базових образів у вигляді офіційних або внутрішніх реєстрів, а також увімкніть підпис та верифікацію образів перед розгортанням.

  • Runtime-моніторинг

Застосовуйте інструменти виявлення аномалій та container IDS/EDR (Falco, Sysdig Secure або Aqua Security), які можуть виявляти спроби виходу з контейнера, відстежувати виконання шкідливих команд. Відстежуйте нетиповий мережевий трафік, несподівані системні виклики та звернення до чутливих файлів.

Майбутнє ізоляції: Kata Containers, gVisor та мікро-VM

  • Rootless-режим істотно знижує ризик тотальної компрометації хоста, але не вирішує все, адже залишаються залежними від ядра хоста і деякі класи атак не усуваються.

Тому для критичних навантажень набирають популярності гібридні підходи.

  • Kata Containers – кожен pod або контейнер запускається всередині легкої віртуальної машини micro-VM з окремим ядром, комбінуючи переваги VM та контейнерів.
  • gVisor – ядро-пісочниця, написане на Go, що виступає прошарком між програмою та справжнім ядром Linux.

    Такі рішення зменшують довіру до спільного ядра і повертають нас ближче до моделі VM-ізоляції, зберігаючи при цьому декларативність та зручність контейнерних оркестраторів.

Застосуйте отримані знання та Hardening-чек-лист до вашого наступного проекту. Замовте VPS або Виділений сервер та почніть будувати ваше безпечне контейнерне середовище вже сьогодні!

Перейти до вибору конфігурації

Перетворіть рекомендації в цій статті в реальну безпеку під час наступного розгортання.

Отримайте VPS або виділений сервер і почніть створювати безпечну контейнерну платформу вже сьогодні.

Перейти до вибору конфігурації

Нові публікації:

Docker проти Podman: Повний посібник з бездемонової контейнеризації

    Нові публікації

    VAT

    • Other

      Other

      0%
    • austria

      Austria

      20%
    • Belgium

      Belgium

      21%
    • Bulgaria

      Bulgaria

      20%
    • Croatia

      Croatia

      25%
    • Cyprus

      Cyprus

      19%
    • Czech Republic

      Czech Republic

      21%
    • Denmark

      Denmark

      25%
    • Estonia

      Estonia

      22%
    • France

      France

      20%
    • Finland

      Finland

      24%
    • Germany

      Germany

      19%
    • Greece

      Greece

      24%
    • Hungary

      Hungary

      27%
    • Ireland

      Ireland

      23%
    • Italy

      Italy

      22%
    • Latvia

      Latvia

      21%
    • Lithuania

      Lithuania

      21%
    • Luxembourg

      Luxembourg

      17%
    • Malta

      Malta

      18%
    • Netherlands

      Netherlands

      21%
    • Poland

      Poland

      23%
    • Portugal

      Portugal

      23%
    • Romania

      Romania

      19%
    • Slovakia

      Slovakia

      20%
    • Slovenia

      Slovenia

      %
    • Spain

      Spain

      21%
    • Sweden

      Sweden

      25%
    • USA

      USA

      0%
    european
    states
    • Other
    • canada
    • poland
    • european-union
    • france
    • germany
    • austria
    • austria
    • austria
    • austria
    • austria
    • austria
    • austria
    • austria
    • austria
    • austria
    • austria
    • austria
    • austria
    • austria
    • austria
    • austria
    • austria
    • austria
    • austria
    • austria
    • austria
    • austria
    • austria
    • austria
    • austria
    • austria
    • austria
    • austria
    • austria
    • austria