Перейти до вмісту

Модуль 4.3: Втеча з контейнера

Складність: [СЕРЕДНЯ] — обізнаність про загрози

Час на проходження: 55-65 хвилин

Передумови: Модуль 4.2: Поширені вразливості

Результати навчання

Розділ «Результати навчання»

Після завершення цього модуля ви зможете переглядати специфікацію Pod’а як інженер з безпеки, пояснювати, яку межу хоста послаблено, і обирати засоби запобігання, що відповідають конкретному робочому навантаженню, а не покладатися на загальні поради щодо посилення безпеки:

  1. Діагностувати ризик втечі з контейнера у специфікаціях Pod’а, відстежуючи привілейований режим, простори імен хоста, томи hostPath, можливості (capabilities) Linux та вибір середовища виконання.
  2. Оцінювати радіус ураження (blast radius) доступу на рівні ноди, пов’язуючи файли хоста, простори імен процесів, мережеві простори імен та права ServiceAccount у Kubernetes.
  3. Впроваджувати запобігання за допомогою Pod Security Admission, обмежених контекстів безпеки (security contexts) та ізоляції середовища виконання (sandboxing) для кластерів Kubernetes 1.35.
  4. Порівнювати ізольовані (sandboxed) середовища виконання зі стандартним посиленням безпеки середовища виконання, щоб обирати засоби контролю для довірених, сторонніх і багатоорендних (multi-tenant) робочих навантажень.

Чому цей модуль важливий

Розділ «Чому цей модуль важливий»

У 2019 році клас уразливостей “втеча з runC” (CVE-2019-5736) показав, як контейнер за певних умов може перезаписати двійковий файл середовища виконання хоста та дістатися облікових даних рівня хоста. Публічні описи були обережними, технічні деталі контролювалися, а вразливі платформи відреагували швидко, але урок було важко не помітити: вплив втечі з контейнера на бізнес не обмежується одним скомпрометованим застосунком. Один збій межі ізоляції може перетворити вебоболонку (web shell) на доступ до ноди, доступ до ноди — на крадіжку облікових даних, а крадіжку облікових даних — на інцидент масштабу всього кластера, який залучає до одного аварійного дзвінка інженерів, юристів і клієнтів.

Той самий патерн з’являється у менш відомих інцидентах усередині звичайних інженерних команд. Агент від постачальника просить privileged: true, Pod для налагодження монтує /, або CI-раннер отримує доступ до сокета середовища виконання, бо так зручніше складати образи. Під час розгортання ніщо не виглядає зловмисним, проте кластер тихо змінився з “контейнери — це ізольовані робочі навантаження” на “будь-яка компрометація застосунку може стати доступом до хоста”. Саме тому KCSA очікує, що ви розпізнаватимете конфігурації, які уможливлюють втечу, перш ніж завчите команди експлойтів.

Цей модуль навчає втечі з контейнера як задачі моделювання загроз. Ви дізнаєтеся, як ізоляція Linux зазвичай захищає ноду, які налаштування Kubernetes навмисно послаблюють цю ізоляцію, як змінюється радіус ураження, коли контейнер дістається ресурсів хоста, і де має бути запобігання в середовищі Kubernetes 1.35. У прикладах і тексті ми вживатимемо псевдонім оболонки alias k=kubectl; після цього першого пояснення команди на кшталт k apply та k get означають kubectl.

Втеча з контейнера змінює межу довіри

Розділ «Втеча з контейнера змінює межу довіри»

Втеча з контейнера означає, що процес, який має бути замкнений усередині контейнера, отримує суттєвий доступ до ноди, на якій він виконується. Ця фраза може звучати драматично, але основна ідея проста: контейнер — це не крихітна віртуальна машина з власним ядром. Це набір процесів Linux, які використовують простори імен, cgroups, можливості (capabilities), монтування файлової системи, профілі безпеки та політику середовища виконання, щоб створити обмежений вигляд хоста.

Межа довіри має значення, тому що Kubernetes планує багато робочих навантажень на одну ноду. Коли ізоляція тримається, вразливий застосунок може втратити власні дані, свої змонтовані Secret’и та права свого ServiceAccount. Коли ізоляція дає збій, зловмисник може читати файли хоста, інспектувати інші контейнери, втручатися у служби ноди, отримувати доступ до API середовища виконання контейнерів або збирати облікові дані, що їх використовують компоненти інфраструктури. Інцидент перейшов із реагування на рівні застосунку до реагування на рівні ноди та кластера.

┌─────────────────────────────────────────────────────────────┐
│ CONTAINER ESCAPE DEFINED │
├─────────────────────────────────────────────────────────────┤
│ │
│ NORMAL CONTAINER ISOLATION: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ HOST │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ Container A │ │ Container B │ │ Container C │ │ │
│ │ │ (isolated) │ │ (isolated) │ │ (isolated) │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ └─────────────────────────────────────────────────────┘ │
│ Containers can't see or affect host or each other │
│ under normal isolation │
│ │
│ CONTAINER ESCAPE: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ HOST ← COMPROMISED │ │
│ │ ┌─────────────┐ │ │
│ │ │ Container A │──→ ESCAPE ──→ Full host access │ │
│ │ │ (attacker) │ │ │
│ │ └─────────────┘ │ │
│ └─────────────────────────────────────────────────────┘ │
│ Attacker breaks isolation, gains host access │
│ │
│ IMPACT: Node compromise, lateral movement, cluster │
│ compromise possible │
│ │
└─────────────────────────────────────────────────────────────┘

Зверніть увагу на важливе формулювання на діаграмі: “повний доступ до хоста” — це можливий результат, а не єдиний. Деякі шляхи втечі надають прямий контроль, еквівалентний root, тоді як інші надають вузький, але небезпечний шлях, наприклад доступ до сокета середовища виконання або видимість процесів хоста. У моделюванні загроз ваше завдання — визначити, який саме ресурс хоста перетнув межу і що цей ресурс може зробити далі.

Найлегша помилка — вважати, що “root у контейнері” — це те саме, що “root на хості”. Вони пов’язані, але не тотожні. Процес root усередині типового, добре замкненого контейнера все одно може бути заблокований просторами імен, відкинутими можливостями, фільтрацією seccomp, монтуваннями лише для читання та правами доступу до файлів. Процес без прав root, який має доступ до потужного сокета хоста, може бути небезпечнішим за процес root без цього сокета.

Зупиніться та зробіть припущення: якщо зловмисник компрометує вебзастосунок без прав root, який бачить лише власний простір імен процесів та файлову систему застосунку лише для читання, який ресурс хоста йому ще знадобиться, перш ніж це стане розслідуванням втечі з контейнера? Запишіть межу, яку йому довелося б перетнути, бо ця відповідь корисніша за заучування переліку лячних налаштувань.

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

Kubernetes додає до цієї моделі ще один рівень. Специфікація Pod’а — це не просто конфігурація застосунку; це запит на конкретні взаємодії з хостом. Налаштування на кшталт hostPID: true просить kubelet помістити контейнер у простір імен процесів хоста. Том hostPath просить kubelet зробити частину файлової системи ноди видимою всередині контейнера. Можливість (capability) просить ядро дозволити операції, яких звичайний код застосунку рідко потребує.

Знання рівня KCSA полягають у розпізнаванні того, коли ці запити легітимні, коли вони надмірні і як вони поєднуються. Окреме налаштування може бути прийнятним для вузькоспеціалізованого системного агента, але те саме налаштування у просторі імен бізнес-застосунку може порушувати модель загроз кластера. Кілька налаштувань разом часто важать більше, ніж будь-яке одне окремо, бо зловмисники поєднують у ланцюжок видимість, доступ на запис і контроль над виконанням.

Фактори ризику, що перетворюють Pod на двері до хоста

Розділ «Фактори ризику, що перетворюють Pod на двері до хоста»

Конфігурації з найвищим ризиком втечі з контейнера рідко бувають непомітними. Вони просять Kubernetes надати контейнеру повноваження рівня хоста, бо робоче навантаження, оператор чи інструмент постачальника стверджують, що потребують цих повноважень. Операційна складність полягає в тому, що деякі інфраструктурні робочі навантаження справді потребують незвичного доступу, тож безпечна відповідь — не “ніколи не запускати системні агенти”. Безпечна відповідь — точно розуміти, що було надано, та ізолювати це з наміром.

Привілейований режим — найочевидніший приклад. Привілейований контейнер отримує широкий доступ до можливостей Linux та пристроїв хоста, а багато обмежень безпеки середовища виконання послаблюється. Він існує для системних навантажень рівня ноди, апаратних агентів, низькорівневих мережевих компонентів та операцій “розбий скло” (break-glass). Він небезпечний, бо компрометації застосунку більше не потрібно долати багато окремих засобів ізоляції; Pod уже було запущено зі знятою значною частиною межі хоста.

┌─────────────────────────────────────────────────────────────┐
│ PRIVILEGED CONTAINER RISK │
├─────────────────────────────────────────────────────────────┤
│ │
│ CONFIGURATION: │
│ securityContext: │
│ privileged: true │
│ │
│ WHAT IT GRANTS: │
│ • All Linux capabilities │
│ • Access to all host devices (/dev/*) │
│ • No seccomp filtering │
│ • SELinux/AppArmor restrictions are typically │
│ relaxed or unconfined │
│ │
│ WHY IT'S DANGEROUS: │
│ An attacker inside a privileged container can mount the │
│ host filesystem, access sensitive host files, and modify │
│ host configurations—effectively gaining full host control │
│ with minimal effort. │
│ │
│ TRIVIAL ESCAPE - Never use in application namespaces │
│ │
└─────────────────────────────────────────────────────────────┘

Для іспитів і реальних оглядів читайте privileged: true як знахідку рівня ризику для кластера, якщо тільки Pod не є відомим інфраструктурним компонентом у жорстко контрольованому просторі імен. Це не нешкідливий зручний прапорець для налагодження. Якщо особа, що реагує на інцидент, залишає в репозиторії маніфест привілейованого Pod’а, будь-яка ідентичність, що зможе розгорнути його пізніше, отримує багаторазовий механізм доступу до хоста — навіть якщо ніхто не мав наміру створювати бекдор.

Спільне використання просторів імен хоста є тоншим питанням. Простори імен зазвичай роблять так, що контейнер бачить власні процеси, мережеві інтерфейси, об’єкти IPC та власний вигляд монтувань файлової системи. Налаштування hostPID, hostNetwork або hostIPC каже середовищу виконання поділитися частиною вигляду ноди. Це не завжди надає негайний доступ на запис, але дає зловмиснику інформацію та досяжність, яких звичайні Pod’и застосунків мати не повинні.

┌─────────────────────────────────────────────────────────────┐
│ HOST NAMESPACE RISKS │
├─────────────────────────────────────────────────────────────┤
│ │
│ hostPID: true │
│ ├── Container sees all host processes │
│ ├── Can send signals to host processes │
│ └── An attacker could inspect or interact with host │
│ processes, potentially gaining host-level access │
│ │
│ hostNetwork: true │
│ ├── Container uses host's network stack │
│ ├── Can bind to any host port │
│ └── Can sniff all host network traffic │
│ │
│ hostIPC: true │
│ ├── Access to host shared memory │
│ └── Can communicate with host processes via IPC │
│ │
└─────────────────────────────────────────────────────────────┘

З hostPID контейнер може спостерігати за процесами хоста та інколи надсилати їм сигнали — залежно від його користувача, можливостей та інших засобів захисту. У поєднанні з CAP_SYS_PTRACE ця видимість може перетворитися на інспектування процесів. У поєднанні з доступом на запис до файлової системи хоста вона може допомогти зловмиснику визначити, які файли служб, облікові дані чи артефакти середовища виконання варто атакувати. Це налаштування поширене в інструментах для усунення несправностей ноди, але це не робить його безпечним для звичайних робочих навантажень застосунків.

З hostNetwork контейнер використовує мережевий простір імен ноди. Це може бути легітимним для певних мережевих плагінів, DNS-агентів або компонентів моніторингу, але воно обходить припущення, побудовані навколо мережі Pod’ів. Робоче навантаження може прив’язуватися до портів хоста, звертатися до служб, що слухають на localhost, діставатися кінцевих точок метаданих link-local, де такі доступні, та уникати засобів контролю NetworkPolicy, написаних для мережі Pod’ів. Це розширює радіус ураження, навіть якщо саме по собі не є прямою втечею.

Томи hostPath часто є найконкретнішим ризиком, бо вони розміщують файли хоста всередині файлової системи контейнера. Монтування вузького каталогу логів лише для читання відрізняється від монтування / на запис, а шлях до сокета середовища виконання — це знову інша річ. Запитати слід не “чи дозволено hostPath десь?”, а “який саме об’єкт хоста перетнув межу контейнера, з яким режимом доступу, і чим цей об’єкт може керувати?”

┌─────────────────────────────────────────────────────────────┐
│ HOST PATH RISKS │
├─────────────────────────────────────────────────────────────┤
│ │
│ DANGEROUS MOUNTS: │
│ │
│ hostPath: { path: / } │
│ └── Full host filesystem access │
│ │
│ hostPath: { path: /etc } │
│ └── Can read/modify host credentials and configuration │
│ │
│ hostPath: { path: /var/run/docker.sock } │
│ └── Control Docker daemon → create privileged containers │
│ │
│ hostPath: { path: /var/log } │
│ └── Read logs, potential sensitive data │
│ │
│ hostPath: { path: /root/.ssh } │
│ └── Steal SSH keys │
│ │
│ WHY DOCKER SOCKET IS ESPECIALLY DANGEROUS: │
│ Access to the Docker socket gives full control over the │
│ container runtime. An attacker could use it to launch │
│ new privileged containers with host filesystem access, │
│ effectively escaping to the host. │
│ │
└─────────────────────────────────────────────────────────────┘

Приклад із сокетом Docker залишається важливим навіть у кластерах, що використовують containerd, бо урок узагальнюється на сокети середовища виконання та керування нодою. Сокет Unix — це не просто файл. Якщо він надає доступ до API, що може запускати контейнери, монтувати шляхи чи керувати робочими навантаженнями, то доступ до цього сокета може бути еквівалентним проханню до привілейованого помічника діяти за зловмисника. Права доступу до файлів і членство в групах стають частиною вашого аналізу втечі.

Зупиніться та зробіть припущення: якщо Pod монтує /var/run/docker.sock, але встановлює runAsNonRoot: true, allowPrivilegeEscalation: false та capabilities.drop: ["ALL"], який засіб контролю все одно важить більше за UID процесу? Суть у тому, чи може процес спілкуватися із сокетом і чи може цей сокет попросити ноду створити сильніший контейнер.

Можливості (capabilities) Linux — ще одне поширене джерело плутанини. Замість того щоб трактувати root як один гігантський дозвіл, Linux ділить багато привілейованих операцій на іменовані можливості. Kubernetes дозволяє контейнеру додавати або відкидати можливості у своєму контексті безпеки. Відкинути всі можливості й додати назад лише потрібні — це сильний патерн, але додавання неправильної можливості може бути майже настільки ж ризикованим, як привілейований режим, для конкретного шляху втечі.

┌─────────────────────────────────────────────────────────────┐
│ DANGEROUS CAPABILITIES │
├─────────────────────────────────────────────────────────────┤
│ │
│ CAP_SYS_ADMIN │
│ ├── Nearly equivalent to root │
│ ├── Allows mounting filesystems │
│ └── Can be used to break container isolation │
│ │
│ CAP_SYS_PTRACE │
│ ├── Allows debugging processes │
│ └── Combined with hostPID, can interact with host │
│ processes in dangerous ways │
│ │
│ CAP_NET_ADMIN │
│ ├── Configure network interfaces │
│ └── Capture traffic, modify routing │
│ │
│ CAP_DAC_READ_SEARCH │
│ ├── Bypass file read permission checks │
│ └── Read any file regardless of ownership │
│ │
│ CAP_DAC_OVERRIDE │
│ ├── Bypass all file permission checks │
│ └── Write to any file regardless of ownership │
│ │
│ BEST PRACTICE: Drop ALL capabilities, then add back only │
│ the specific ones your application needs. │
│ │
└─────────────────────────────────────────────────────────────┘

CAP_SYS_ADMIN заслуговує на особливу увагу, бо вона охоплює широкий набір операцій, зокрема пов’язану з монтуванням поведінку, і її давно описують як перевантажену. Якщо постачальник просить її, не приймайте “агенту потрібен admin” як пояснення. Запитайте, яка операція ядра її потребує, чи існує вужчий дизайн і чи належить це робоче навантаження до привілейованого системного простору імен, а не до сусідства з бізнес-застосунками.

CAP_SYS_PTRACE небезпечна, коли простір імен процесів також розширено. Налагодження одного процесу всередині того самого контейнера відрізняється від трасування процесів хоста. Та сама можливість, що допомагає розробникам інспектувати збійний двійковий файл, може допомогти зловмиснику інспектувати пам’ять процесів, токени, аргументи та змінні середовища, якщо межу простору імен розширено. Саме тому аналіз втечі є композиційним, а не побудованим за принципом галочок.

Уразливості ядра становлять останню категорію. Контейнери спільно використовують ядро хоста, якщо тільки ізольоване середовище виконання (sandboxed runtime) чи рівень віртуалізованої ізоляції не змінює цю модель. Якщо ядро містить досяжну ваду підвищення привілеїв, то контейнер з інакше розумними налаштуваннями все одно може стати точкою входу. Seccomp і найменші привілеї зменшують досяжну поверхню атаки, але вони не роблять оновлення ядра необов’язковим.

┌─────────────────────────────────────────────────────────────┐
│ KERNEL EXPLOIT ESCAPE │
├─────────────────────────────────────────────────────────────┤
│ │
│ CONCEPT: │
│ • Containers share the host kernel │
│ • Kernel vulnerability = escape opportunity │
│ • Works even with "secure" container settings │
│ │
│ EXAMPLES: │
│ ├── Dirty COW (CVE-2016-5195) │
│ ├── Dirty Pipe (CVE-2022-0847) │
│ └── Various privilege escalation CVEs │
│ │
│ MITIGATION: │
│ • Keep kernel updated │
│ • Use seccomp to limit syscalls │
│ • Consider sandboxed runtimes (gVisor, Kata) │
│ • Sandboxed runtimes use different kernel or intercept │
│ syscalls, reducing kernel attack surface │
│ │
└─────────────────────────────────────────────────────────────┘

Ризик втечі через ядро — одна з причин, чому оновлення керованого Kubernetes, обслуговування образів нод та профілі за замовчуванням середовища виконання належать до розмов про безпеку. Команда може писати чудові специфікації Pod’ів і все одно нести стару вразливість ядра, якщо ноди відстають. І навпаки, оновлені ноди не виправдовують небезпечні специфікації Pod’ів, бо неправильна конфігурація лишається поширенішим способом, у який організації віддають доступ до хоста робочим навантаженням.

Перш ніж проводити цей уявний огляд на реальному маніфесті, передбачте, яка знахідка важила б найбільше у вашому власному середовищі: привілейований Pod у заблокованому системному просторі імен, Pod без прав root із доступним на запис hostPath /, чи звичайний Pod, що працює на нодах зі старими ядрами. Універсальної відповіді без контексту немає, і в цьому й суть. Моделювання загроз ранжує ризик за шляхом, експозицією та засобами контролю, а не за самим лише ключовим словом.

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

Розділ «Запобігання починається з допуску та найменших привілеїв»

Найнадійніше запобігання втечі з контейнера відбувається до того, як Pod запуститься. Щойно небезпечний Pod допущено та заплановано, нода вже виконала запит. Ви все ще можете виявити, відреагувати та знищити робоче навантаження, але запобігання належить до політики, огляду та дизайну просторів імен. Kubernetes дає вам нативну відправну точку з Pod Security Standards та Pod Security Admission.

Pod Security Standards визначають три профілі політики: Privileged, Baseline та Restricted. Baseline блокує багато відомих шляхів підвищення привілеїв, водночас дозволяючи поширені патерни застосунків. Restricted є суворішим і підштовхує робочі навантаження до виконання без прав root, відкинутих можливостей, seccomp та зменшеної зміни файлової системи. У продакшн-просторах імен застосунків Restricted має бути відправною точкою за замовчуванням, якщо тільки конкретне робоче навантаження не доведе, що не може там працювати.

┌─────────────────────────────────────────────────────────────┐
│ PSS PREVENTS ESCAPE │
├─────────────────────────────────────────────────────────────┤
│ │
│ BASELINE STANDARD BLOCKS: │
│ ├── privileged: true │
│ ├── hostNetwork: true │
│ ├── hostPID: true │
│ ├── hostIPC: true │
│ └── All hostPath volumes │
│ │
│ RESTRICTED STANDARD ADDITIONALLY: │
│ ├── Requires non-root │
│ ├── Requires seccomp profile │
│ ├── Drops all capabilities │
│ └── Requires read-only root filesystem │
│ │
│ ENABLE IN NAMESPACE: │
│ kubectl label ns production \ │
│ pod-security.kubernetes.io/enforce=restricted │
│ │
└─────────────────────────────────────────────────────────────┘

У Kubernetes 1.35 операційний патерн полягає в маркуванні просторів імен режимами та версіями Pod Security Admission. Використовуйте enforce для стандарту, який має блокуватися, warn, щоб навчати розробників до розширення примусового виконання, та audit, щоб генерувати записи для огляду безпеки. Наприклад, команда може використати k label ns production pod-security.kubernetes.io/enforce=restricted pod-security.kubernetes.io/enforce-version=v1.35 після валідації робочих навантажень у тестовому (staging) просторі імен.

Допуск (admission) потужний, бо він прибирає суперечки з кожного розгортання. Розробнику не потрібно пам’ятати, що hostPID ризиковий, якщо політика простору імен відхиляє його. Рецензенту не потрібно ловити кожен привілейований sidecar, якщо CI та допуск ловлять його першими. Компроміс у тому, що легітимні системні компоненти потребують іншого шляху, і цей шлях має бути явним, а не випадковим.

Найменші привілеї починаються всередині специфікації Pod’а. Посилений контейнер застосунку працює як користувач без прав root, забороняє підвищення привілеїв, відкидає можливості Linux, використовує профіль seccomp за замовчуванням середовища виконання, уникає просторів імен хоста, уникає томів hostPath і використовує файлову систему лише для читання, де це можливо. Ці засоби контролю не роблять застосунок невразливим, але вони змушують зловмисника долати кілька окремих бар’єрів.

Порядок цих бар’єрів має значення. runAsNonRoot зменшує повноваження процесу. allowPrivilegeEscalation: false блокує поширені здобутки привілеїв у стилі setuid усередині контейнера. Відкидання можливостей прибирає привілейовані операції ядра. Seccomp обмежує досяжність системних викликів. Файлові системи лише для читання зменшують закріплення та втручання. Жоден із них не замінює політику допуску, але разом вони роблять “одна вебвада дорівнює компрометації ноди” набагато менш імовірним.

Багато команд натрапляють на труднощі, коли робоче навантаження падає під політикою Restricted. Корисна реакція — не перемикати простір імен на Privileged. Натомість визначте точний засіб контролю, що ламає робоче навантаження. Чи припускає образ права root, бо пише під /var? Змініть образ або змонтуйте emptyDir за шляхом запису. Чи потрібен йому низький порт? Використайте вищий порт контейнера й мапте його через Service. Чи потрібні йому метрики хоста? Розгляньте виділений агент з обмеженим доступом.

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

Реалістичний продакшн-кластер часто використовує щонайменше три класи просторів імен. Простори імен застосунків забезпечують Restricted. Системні платформні простори імен дозволяють ретельно переглянуті винятки для мережі, сховища, спостережуваності та керування нодами. Експериментальні простори імен чи простори “розбий скло” можуть дозволяти сильніший доступ на короткі вікна, але вони повинні мати окремий RBAC, видимість для аудиту та очищення. Мета — тримати незвичну потужність подалі від рутинних шляхів розгортання.

Розгорнутий приклад: сторонній агент моніторингу просить hostPID, hostNetwork та privileged: true. Замість того щоб надавати ці поля в кожному просторі імен застосунків, створіть виділений простір імен, наприклад monitoring-system, застосуйте найменш дозвільний режим Pod Security, що допускає агента, обмежте, хто може там розгортати, та переконайтеся, що ServiceAccount агента не може змінювати довільні робочі навантаження. Тоді запитайте постачальника, які поля справді потрібні, бо багато агентів просять більше, ніж використовують.

Який підхід ви обрали б тут і чому: послабити Restricted у просторі імен payments, щоб один DaemonSet постачальника міг розгорнутися, чи ізолювати DaemonSet у виділеному просторі імен із цілеспрямованим RBAC та мережевими засобами контролю? Другий шлях вимагає більше роботи під час налаштування, але він не дає винятку для постачальника перетворитися на дозвіл за замовчуванням для непов’язаних Pod’ів застосунків.

Запобігання також включає перегляд припущень про образи та середовище виконання. Pod, що працює як UID 1000, усе одно може писати в hostPath, якщо права доступу до шляху це дозволяють. Файлова система лише для читання не захищає доступний на запис змонтований каталог хоста. Набір відкинутих можливостей не захищає потужний сокет середовища виконання. Кожен засіб контролю має оцінюватися щодо ресурсу, який він має захищати, а не милуватися ним ізольовано.

Ізоляція середовища виконання та виявлення додають окремі рівні

Розділ «Ізоляція середовища виконання та виявлення додають окремі рівні»

Допуск і найменші привілеї зменшують імовірність того, що робоче навантаження стартує з небезпечним доступом до хоста. Ізоляція середовища виконання та виявлення розв’язують решту ризику: вади, уразливості ядра, недовірений код, розділення орендарів та помилки, що проскакують крізь огляд. Саме тут seccomp, AppArmor, SELinux, gVisor, Kata Containers та моніторинг середовища виконання стають частиною історії про втечу з контейнера.

Багаторівневий захист (defense in depth) тут не гасло. Він означає, що кожен рівень блокує інший режим збою. Pod Security Admission блокує ризиковані специфікації. Контексти безпеки зменшують повноваження процесу. Seccomp і модулі безпеки Linux зменшують поверхню атаки на ядро. Ізольовані середовища виконання змінюють те, наскільки безпосередньо робоче навантаження дістається ядра хоста. Моніторинг шукає поведінку, якої ніколи не повинно бути у звичайного контейнера застосунку.

┌─────────────────────────────────────────────────────────────┐
│ CONTAINER ESCAPE PREVENTION │
├─────────────────────────────────────────────────────────────┤
│ │
│ LAYER 1: POD SECURITY │
│ ├── Baseline: no privileged, host namespaces, or hostPath │
│ ├── Restricted: non-root, seccomp, read-only root FS │
│ └── Restricted only: drop all capabilities │
│ │
│ LAYER 2: RUNTIME SECURITY │
│ ├── Seccomp profiles (RuntimeDefault minimum) │
│ ├── AppArmor/SELinux profiles │
│ ├── Read-only root filesystem │
│ └── Run as non-root user │
│ │
│ LAYER 3: RUNTIME ISOLATION │
│ ├── Consider gVisor for untrusted workloads │
│ ├── Consider Kata Containers for strong isolation │
│ └── Runtime classes for different security levels │
│ │
│ LAYER 4: MONITORING │
│ ├── Runtime security (Falco) │
│ ├── File integrity monitoring │
│ └── Anomaly detection │
│ │
└─────────────────────────────────────────────────────────────┘

Seccomp часто є першим рівнем середовища виконання, який команди впроваджують, бо Kubernetes може запитувати профілі RuntimeDefault безпосередньо в контексті безпеки Pod’а. Профіль seccomp обмежує, які системні виклики може робити процес контейнера. Якщо експлойт залежить від заблокованого системного виклику, seccomp може зупинити цей шлях навіть після того, як код застосунку скомпрометовано. Компроміс — це сумісність, бо незвичні застосунки можуть потребувати системних викликів поза профілем за замовчуванням.

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

Ізольовані середовища виконання змінюють відношення між контейнером і ядром хоста. Стандартне середовище виконання все ще значною мірою залежить від спільного ядра хоста для ізоляції. gVisor перехоплює та реалізує багато системних викликів у просторі користувача, зменшуючи пряму експозицію до ядра. Kata Containers запускають робочі навантаження всередині легких віртуальних машин, даючи кожному ізольованому середовищу окреме гостьове ядро та межу апаратної віртуалізації.

┌─────────────────────────────────────────────────────────────┐
│ SANDBOXED RUNTIME OPTIONS │
├─────────────────────────────────────────────────────────────┤
│ │
│ gVisor (runsc) │
│ ├── User-space kernel │
│ ├── Intercepts and emulates syscalls │
│ ├── Container doesn't directly touch host kernel │
│ ├── Performance overhead │
│ └── Good for: Untrusted workloads, multi-tenant │
│ │
│ Kata Containers │
│ ├── Lightweight VM per container │
│ ├── Separate kernel from host │
│ ├── Hardware virtualization isolation │
│ ├── More overhead than gVisor │
│ └── Good for: Maximum isolation, compliance │
│ │
│ RuntimeClass object: │
│ apiVersion: node.k8s.io/v1 │
│ kind: RuntimeClass │
│ metadata: │
│ name: gvisor │
│ handler: runsc │
│ │
│ Pod spec fragment: │
│ spec: │
│ runtimeClassName: gvisor │
│ │
└─────────────────────────────────────────────────────────────┘

Kubernetes використовує RuntimeClass, щоб обрати альтернативний обробник середовища виконання, коли нода його підтримує. Це робить ізоляцію вибором планування та політики, а не переписуванням застосунку. Pod може встановити runtimeClassName: gvisor чи інший налаштований клас, і kubelet просить середовище виконання контейнерів використати відповідний обробник. Платформні команди все ще мають встановити, протестувати та спланувати потужність цих середовищ виконання на нодах.

Компроміс — це продуктивність, сумісність та операційна складність. gVisor може ламати робочі навантаження, що залежать від незвичної поведінки ядра. Kata може мати вищі накладні витрати на запуск і пам’ять, бо додає віртуалізацію. Жоден із варіантів не усуває потреби в Pod Security Admission, бо ізольоване привілейоване робоче навантаження все одно може створювати ризик усередині власного ізольованого середовища або через відкриті інтеграції з хостом. Ізоляція — це сильний додатковий рівень для вибраних робочих навантажень, а не дозвіл ігнорувати базове посилення безпеки.

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

Правила виявлення мають відповідати вашій моделі втечі. Якщо звичайні Pod’и застосунків ніколи не повинні відкривати /var/run/docker.sock, налаштуйте сповіщення про цей доступ. Якщо лише агенти ноди мають використовувати простори імен хоста, сповіщайте, коли їх використовує неочікуваний простір імен. Якщо бізнес-сервіс раптом виконує менеджери пакетів, оболонки чи утиліти монтування, трактуйте це як сигнал компрометації. Хороші сповіщення прив’язані до очікувань, які можна обґрунтувати.

Корисна бойова історія — це “тимчасовий Pod для налагодження”, що стає постійним. Під час збою команда розгортає привілейований Pod Ubuntu із монтуваннями хоста, бо це швидше за доступ через SSH. Збій закінчується, про Pod забувають, і за тижні окрема вада застосунку дає зловмиснику шлях до того самого простору імен. Привілейований маніфест для налагодження перетворив рутинну компрометацію застосунку на компрометацію ноди, бо операційне очищення провалилося.

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

Розгорнутий огляд: аналіз шляху втечі

Розділ «Розгорнутий огляд: аналіз шляху втечі»

Найшвидший спосіб діагностувати ризик втечі з контейнера — читати специфікацію Pod’а від ноди назовні. Спершу запитайте, чи бачить контейнер простори імен хоста. Далі запитайте, чи може він читати або писати шляхи файлової системи хоста. Потім перевірте, чи має він можливості, що роблять ці шляхи кориснішими. Нарешті, перевірте, чи має він доступ до API, доступ до сокета середовища виконання чи ізольоване середовище виконання, що змінює модель.

Ось навмисно ризикований Pod з оригінальної вправи. Не починайте з його виправлення. Почніть із називання ресурсів хоста, які зробили доступними для контейнера, бо це тримає ваш огляд закоріненим у причині й наслідку, а не в страху перед окремими ключовими словами.

apiVersion: v1
kind: Pod
metadata:
name: risky-pod
spec:
hostPID: true
containers:
- name: app
image: ubuntu:24.04
securityContext:
capabilities:
add:
- SYS_ADMIN
- SYS_PTRACE
volumeMounts:
- name: docker-sock
mountPath: /var/run/docker.sock
- name: host-root
mountPath: /host
volumes:
- name: docker-sock
hostPath:
path: /var/run/docker.sock
- name: host-root
hostPath:
path: /

Перша знахідка — hostPID: true, що поміщає контейнер у простір імен процесів хоста. Саме це вже розширює видимість, але вплив стає більшим, бо Pod також додає SYS_PTRACE. Разом ці налаштування свідчать, що контейнер може інспектувати чи взаємодіяти з процесами поза власною межею контейнера. У реальному огляді ця комбінація заслуговує на знахідку високої серйозності, якщо тільки робоче навантаження не є жорстко контрольованим діагностичним інструментом ноди.

Друга знахідка — монтування кореня хоста. Монтування / за шляхом /host дає контейнеру вигляд файлової системи ноди. Вплив залежить від доступу на запис, власника файлів, ідентичності користувача та параметрів монтування, але дизайн небезпечний ще до того, як ви інспектуєте ці деталі. Файли хоста часто містять стан kubelet, дані середовища виконання, логи, облікові дані служб, сертифікати та конфігурацію, що можуть допомогти зловмиснику перейти від однієї точки опори до ширшого контролю.

Третя знахідка — сокет середовища виконання. Маніфест використовує /var/run/docker.sock, що є класичним прикладом надання контейнеру здатності спілкуватися з демоном Docker. У сучасному кластері Kubernetes ви можете побачити сокети containerd чи CRI замість нього, але міркування лишається тим самим. Якщо сокет дозволяє процесу попросити привілейовану службу ноди створити робочі навантаження чи змонтувати шляхи хоста, то посилення безпеки файлової системи всередині оригінального контейнера може вас не врятувати.

Четверта знахідка — SYS_ADMIN, яка часто є надто широкою для робочих навантажень застосунків. За наявності монтування файлової системи хоста, видимості PID хоста чи привілейованих допоміжних API широкі можливості роблять подальші дії легшими. Правильне питання для огляду — не “чи можемо ми це залишити, бо застосунок стартує лише з цією можливістю?”. Воно звучить так: “яка саме операція потребує цієї можливості, і чи можна цю операцію прибрати, ізолювати чи замінити?”

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

Тепер порівняйте ризиковану специфікацію з Pod’ом застосунку у стилі Restricted. Виправлена версія не намагається зберегти кожну поведінку ризикованого Pod’а, бо звичайний застосунок не повинен потребувати цих ресурсів хоста. Вона прибирає спільне використання просторів імен хоста, прибирає томи hostPath, працює як користувач без прав root, відкидає можливості, вимикає підвищення привілеїв, використовує seccomp і робить кореневу файлову систему лише для читання.

apiVersion: v1
kind: Pod
metadata:
name: secure-pod
spec:
# No hostPID, hostNetwork, or hostIPC
containers:
- name: app
image: ubuntu:24.04
securityContext:
runAsNonRoot: true
runAsUser: 1000
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
seccompProfile:
type: RuntimeDefault
# No hostPath volumes — use PVCs if storage is needed

Ця виправлена специфікація не є універсальним шаблоном, бо застосунки відрізняються. Деякі потребують доступного на запис тимчасового сховища, тож ви можете додати emptyDir, змонтований за шляхом /tmp, замість того щоб робити всю кореневу файлову систему доступною на запис. Деякі потребують конкретної можливості Linux, тож ви можете додати одну назад після огляду, а не приймати набір за замовчуванням. Навчальна теза в тому, що кожен виняток має бути вузьким, названим і протестованим щодо моделі загроз.

Якби це робоче навантаження справді потребувало поведінки рівня ноди, кращим дизайном було б перемістити його з простору імен застосунку до контрольованого системного простору імен. ServiceAccount отримав би лише потрібні йому права. Мережевий доступ було б обмежено. Моніторинг середовища виконання було б налаштовано навколо його очікуваної поведінки. Виняток був би видимим для власників платформи, а не схованим усередині звичайного шляху розгортання.

Ви можете використати k get pod risky-pod -o yaml під час огляду, щоб підтвердити живу специфікацію, але не зупиняйтеся на поданому маніфесті. Мутаційні webhook’и допуску, значення за замовчуванням, шаблони Helm та контролери операторів можуть змінити те, що насправді працює. Порушена межа належить живому Pod’у на ноді, а не файлу, який хтось мав намір розгорнути.

Патерни та антипатерни

Розділ «Патерни та антипатерни»

Хороші патерни запобігання втечі з контейнера роблять небезпечні повноваження явними. Вони не покладаються на те, що кожен розробник пам’ятатиме кожне поле, і не вдають, що системні робочі навантаження — це те саме, що вебзастосунки. Найсильніші організації відокремлюють звичайне розгортання застосунків від інструментів рівня ноди, забезпечують політику за простором імен і тримають огляд винятків близько до людей, які експлуатують кластер.

Перший патерн — “Restricted за замовчуванням, винятки за простором імен”. Команди застосунків мають стартувати всередині просторів імен, що забезпечують стандарт Restricted Pod Security для поточної мінорної версії Kubernetes. Інфраструктурні компоненти, що потребують сильнішого доступу, мають жити у виділених просторах імен з іншими мітками, жорсткішим RBAC та явним володінням. Це масштабується, бо шлях за замовчуванням є безпечним, тоді як винятки лишаються придатними для інспектування.

Другий патерн — “спершу відкинь, додавай свідомо”. Pod має відкинути всі можливості й потім додати лише ту, що потрібна для документованої операції. Це працює, бо реверсує звичайний режим збою, де робочі навантаження успадковують повноваження, яких ніколи не використовують. Це також полегшує огляд, бо кожна додана можливість стає питанням із конкретною відповіддю замість непомітного значення за замовчуванням.

Третій патерн — “заміни hostPath сховищем Kubernetes чи спеціалізованими API”. Команди застосунків часто просять hostPath, бо це виглядає як найпростіший спосіб поділитися файлами з нодою. PersistentVolume’и, ConfigMap’и, Secret’и, проєктовані (projected) томи та агенти нод часто надають безпечніші альтернативи. Коли hostPath неминучий, він має бути лише для читання, де можливо, обмеженим вузьким шляхом та ізольованим від загальних просторів імен застосунків.

Четвертий патерн — “ізолюй (sandbox) робочі навантаження, яким не повністю довіряєш”. Багатоорендні системи складання, код, поданий користувачем, навчальні лабораторії, середовища попереднього перегляду та виконання сторонніх плагінів несуть інші припущення, ніж власні сервіси. Ізольоване середовище виконання дає цим робочим навантаженням сильнішу межу, але його слід поєднувати з квотами ресурсів, мережевими засобами контролю та політикою допуску. Ізоляція змінює рівняння ризику; вона не скасовує операційної роботи.

Антипатерни зазвичай походять із браку часу. Найпоширеніший — розгортання привілейованого Pod’а для налагодження під час інциденту й залишення маніфесту доступним опісля. Команди потрапляють у цю пастку, бо збої винагороджують швидкість, а налагодження на рівні ноди інколи здається єдиним способом побачити проблему. Краща альтернатива — наперед побудувати схвалені робочі процеси усунення несправностей з обмеженнями часу, аудиторськими записами та кроками очищення.

Інший антипатерн — використання вимог постачальника як політики. Чарт постачальника може просити привілейований режим, мережу хоста та широкий RBAC, бо це працює в багатьох клієнтських середовищах. Ваш кластер — не кожне клієнтське середовище. Попросіть постачальника про мінімальний режим, протестуйте, які права насправді використовуються, і розгорніть компонент у просторі імен, спроєктованому для цього ризику, якщо він справді потребує доступу до хоста.

Тонший антипатерн — трактування виконання без прав root як повної відповіді. Виконання без прав root важливе, але воно не нейтралізує доступний на запис hostPath, сокет середовища виконання чи ServiceAccount із широкими правами на API. Виконання без прав root — це один засіб контролю в багаторівневій моделі. Воно зменшує деякі дії та можливості після експлуатації, але не може захистити ресурс, до якого Pod’у було навмисно дозволено доступ.

ПатернКоли використовуватиЧому це працюєМіркування щодо масштабування
Простори імен Restricted за замовчуваннямЗастосунки та сервіси, що належать командамБлокує поширені поля, що уможливлюють втечу, до плануванняПотребує настанов для онбордингу образів, що припускають root чи доступний на запис корінь
Виділені системні простори іменАгенти нод, CNI, CSI, компоненти спостережуваностіТримає привілейовані винятки подалі від звичайних шляхів розгортанняПотребує суворого RBAC, аудиторського огляду та відповідальності власника
Спершу відкинути всі можливостіМайже всі контейнери застосунківПрибирає невикористовувані привілейовані операції ядраДодавайте винятки лише з документованою операцією ядра та доказами тестування
Класи ізольованих середовищ виконанняНедовірені, сторонні чи багатоорендні навантаженняЗменшує пряму експозицію до ядра хостаПотребує підтримки ноди, тестування продуктивності та перевірок сумісності навантаження
АнтипатернЩо йде не такКраща альтернатива
Привілейовані Pod’и для налагодження у просторах імен застосунківТимчасовий інструмент для інциденту стає багаторазовим шляхом доступу до хостаВикористовуйте контрольовані робочі процеси налагодження, ефемерні контейнери та короткочасне схвалення
Монтування сокетів середовища виконання для складанняСкомпрометоване завдання складання може попросити середовище виконання ноди створити сильніші контейнериВикористовуйте безкореневі (rootless) складальники, віддалені складальники чи виділені ізольовані ноди складання
Широкі монтування hostPathКомпрометація застосунку відкриває файли хоста та облікові дані нодиВикористовуйте PVC, проєктовані томи чи вузькі монтування лише для читання у контрольованих просторах імен
Послаблення Pod Security для одного навантаженняКожне навантаження у просторі імен успадковує слабшу межуПеремістіть виняток до виділеного простору імен із компенсаційними засобами контролю

Ці патерни слід переглядати під час проєктування, а не лише після того, як скан провалився. Якщо команда заздалегідь знає, що робоче навантаження потребує мережі хоста, платформна команда може спроєктувати безпечну стратегію розміщення. Якщо вимога з’являється лише як несподіване поле у pull request, огляд перетворюється на перемовини під тиском дедлайну, і ймовірність зрізаних кутів зростає.

Фреймворк прийняття рішень

Розділ «Фреймворк прийняття рішень»

Використовуйте огляд втечі з контейнера як структуроване рішення, а не як інтуїтивне відчуття. Почніть із призначення робочого навантаження, потім визначте ресурси хоста, потім оберіть засоби контролю, що відповідають експозиції. Застосунок для користувачів, експортер ноди, складальник CI та багатоорендний лабораторний раннер не повинні отримувати ту саму відповідь, бо вони не створюють той самий ризик.

Workload needs host access?
|
+-- No --> Enforce Restricted, drop capabilities, no hostPath, RuntimeDefault seccomp.
|
+-- Yes --> Is it a platform-owned node agent?
|
+-- No --> Redesign with Kubernetes APIs, PVCs, Services, or external builders.
|
+-- Yes --> Dedicated namespace, narrow host resources, strict RBAC, audit, monitoring.
|
+-- Runs untrusted code or tenants? --> Add sandboxed runtime or isolation nodes.
|
+-- Trusted system component? -------> Keep least privilege and review exceptions.

Перша гілка запитує, чи доступ до хоста справді потрібен. Багато запитів розпадаються під цим питанням. Застосунки просять hostPath, бо потребують сховища, але PVC цього достатньо. Сервіси просять мережу хоста, бо порт було жорстко закодовано, але Service може покрити звичайний Pod у мережі. Образи просять root, бо права доступу до файлів неправильні, але образ можна виправити. Прибрати потребу — сильніше, ніж контролювати виняток.

Друга гілка запитує, хто володіє робочим навантаженням. Агенти нод, що належать платформі, мають інше відношення довіри, ніж застосунки продуктових команд. Вони часто є частиною площини управління чи спостережуваності кластера й можуть потребувати досяжності до хоста. Це не означає, що вони автоматично безпечні. Це означає, що вони належать до простору імен, межі RBAC та профілю моніторингу, які відображають їхні повноваження.

Третя гілка запитує, чи довіряють самому коду. Власний агент ноди від вашої платформної команди — це не те саме, що сценарії складання, подані клієнтом, чи код виклику, виконуваний у браузері. Якщо робоче навантаження виконує недовірений чи сторонній код, розгляньте ізольовані середовища виконання, ізольовані пули нод, жорсткіший вихідний трафік (egress) та агресивне очищення. Вищі накладні витрати виправдані, коли альтернатива — компрометація “орендар-до-ноди”.

Питання для рішенняНизькоризикова відповідьВисокоризикова відповідьРекомендований засіб контролю
Чи потребує Pod просторів імен хоста?Без спільного використання просторів імен хостаЗапитано hostPID, hostNetwork чи hostIPCБлокуйте у просторах імен застосунків; ізолюйте системні агенти
Чи потребує він файлів хоста?Використовує PVC, Secret, ConfigMap чи проєктований томШирокий чи доступний на запис hostPathЗамініть дизайн сховища або звузьте й ізолюйте монтування
Чи потребує він привілейованих операцій?Відкидає всі можливостіДодає SYS_ADMIN, SYS_PTRACE чи привілейований режимДокументуйте точну операцію; уникайте повного привілейованого режиму
Чи виконує він недовірений код?Власний сервіс із контрольованими вхідними данимиСкладання, плагіни, лабораторії, код орендаряДодайте ізольоване середовище виконання та ізольовані ноди
Чи може компрометація дістатися API Kubernetes?Мінімальні права ServiceAccountШирокий RBAC чи змонтовані токени з доступом на записВикористовуйте RBAC з найменшими привілеями та контроль токенів

Коли ви оцінюєте радіус ураження, включайте і доступ до ноди, і доступ до API. Втеча з контейнера може відкрити дані kubelet, стан середовища виконання, облікові дані хоста та інші контейнери на ноді. Окремо ServiceAccount Pod’а може дозволяти дії з API Kubernetes. Слабкий ServiceAccount не робить доступ до хоста безпечним, а сильний ServiceAccount не потребує доступу до хоста, щоб завдати шкоди. Трактуйте обидва шляхи як частину однієї моделі інциденту.

Остаточне рішення має давати чіткий результат: відхилити Pod, прийняти його під Restricted, прийняти вузький виняток у виділеному просторі імен чи перемістити його до ізольованого пулу нод. Уникайте розпливчастих результатів на кшталт “ретельно моніторити” без зміни моделі дозволів. Моніторинг — це компенсаційний засіб контролю, а не заміна рішенню про те, чи має робоче навантаження мати повноваження хоста.

  • Більшість практичних втеч із контейнерів починається з конфігурації, а не з вразливостей нульового дня. Доступним на запис hostPath, привілейованим режимом чи монтуванням сокета середовища виконання легше зловживати, ніж експлойтом ядра, — саме тому політика допуску має таку високу захисну цінність.
  • Dirty COW отримала ідентифікатор CVE-2016-5195, а Dirty Pipe — CVE-2022-0847. Ці приклади запам’ятовуються, бо нагадують захисникам, що контейнери спільно несуть ризик ядра, якщо тільки додатковий рівень ізоляції не змінить це відношення.
  • Pod Security Admission у Kubernetes досягла стабільності (stable) у Kubernetes 1.25. До Kubernetes 1.35 команди мають трактувати мітки просторів імен для enforce, audit та warn як звичайну гігієну кластера, а не як просунуту функцію.
  • gVisor і Kata розв’язують різні задачі ізоляції. gVisor зменшує пряму експозицію системних викликів до ядра хоста за допомогою ядра в просторі користувача, тоді як Kata використовує легкі віртуальні машини, щоб надати окрему межу гостьового ядра.
ПомилкаЧому вона трапляєтьсяЯк її виправити
Використання privileged: true для зручностіНалагодження та чарти постачальників часто працюють швидше, коли всі обмеження знятоВимагайте названого винятку, перемістіть його до системного простору імен та замініть привілейований режим конкретними можливостями, де можливо
Монтування сокета середовища виконання в робоче навантаженняЗавдання складання та автоматизації хочуть локального контролю над середовищем виконанняВикористовуйте безкореневі чи віддалені складальники, ізольовані ноди складання та уникайте відкриття сокетів керування нодою для Pod’ів застосунків
Трактування виконання без прав root як повного захистуКоманди слушно цінують runAsNonRoot, але забувають, що змонтовані ресурси хоста зберігають власну потужністьПоєднуйте виконання без прав root із відсутністю небезпечного hostPath, відкинутими можливостями, seccomp та політикою допуску
Дозвіл широких доступних на запис томів hostPathЛокальні файли виглядають як найпростіший спосіб поділитися даними з нодоюВикористовуйте PVC чи проєктовані томи та обмежуйте будь-який неминучий hostPath вузьким шляхом лише для читання у контрольованому просторі імен
Послаблення міток Pod Security на спільному просторі іменОдне навантаження падає під Restricted, тож послаблюється весь простір іменПеремістіть виняток до виділеного простору імен і тримайте простори імен застосунків під Restricted
Ігнорування прав ServiceAccount під час аналізу втечіРецензенти зосереджуються лише на засобах контролю Linux і пропускають радіус ураження APIОцінюйте доступ до ноди та права на API Kubernetes разом під час моделювання загроз
Відкладання оновлення ноди, бо Pod’и посиленоКоманди переоцінюють те, що контексти безпеки можуть зробити проти вразливостей ядраТримайте образи нод актуальними та розгляньте ізольовані середовища виконання для навантажень із недовіреним кодом
Ваша команда знаходить продакшн-Pod із `privileged: true`, `hostPID: true` та монтуванням hostPath до `/`. Власник каже, що його використовують лише під час інцидентів. Як ви оцінюєте ризик і який безпечніший шлях пропонуєте?

Це шлях втечі з високим ризиком, бо він поєднує широкі можливості, видимість процесів хоста та прямий доступ до файлової системи хоста. Тимчасовий характер не усуває ризику, оскільки будь-яка ідентичність, що може розгорнути чи повторно використати маніфест, може відтворити шлях доступу до хоста. Безпечніший підхід — прибрати Pod із просторів імен застосунків, використовувати контрольовані робочі процеси налагодження, як-от схвалені ефемерні контейнери, де можливо, та вимагати короткочасного аудитованого доступу для справжнього налагодження на рівні ноди. Ключове міркування в тому, що швидкість реагування на інцидент не повинна лишати багаторазове привілейоване робоче навантаження у звичайних шляхах розгортання.

Контейнер без прав root відкидає всі можливості, але монтує `/var/run/docker.sock`. Чи може зловмисник усе одно втекти після компрометації застосунку, і чому?

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

Кластер забезпечує Restricted Pod Security, але оголошено про підвищення привілеїв через ядро для ОС ноди. Що ви перевіряєте першим і який додатковий захист може допомогти для недовірених навантажень?

Спершу ви перевіряєте версії образів нод, доступність патчів та те, які ноди запускають навантаження, що могли б дістатися вразливого шляху ядра. Restricted Pod Security зменшує багато шляхів неправильної конфігурації, але стандартні контейнери все одно спільно використовують ядро хоста. Seccomp може допомогти, якщо експлойт потребує заблокованих системних викликів, але це не заміна оновленню. Для недовірених навантажень ізольовані середовища виконання на кшталт gVisor чи Kata можуть зменшити пряму експозицію до ядра хоста.

Постачальник моніторингу просить `hostNetwork: true` для DaemonSet. Які близькі до втечі ризики це створює, навіть якщо контейнер не привілейований?

Мережа хоста поміщає робоче навантаження у мережевий простір імен ноди, що розширює те, що воно може бачити й діставати. Воно може прив’язуватися до портів хоста, діставатися служб ноди лише на localhost, обходити припущення мережі Pod’ів та уникати правил NetworkPolicy, написаних для звичайного трафіку Pod’ів. Це не надає автоматично доступу до файлової системи хоста, але збільшує ризик латерального руху та видавання себе за іншого після компрометації. Безпечніший дизайн — виділений простір імен, вузький RBAC, документована потреба та моніторинг навколо очікуваної мережевої поведінки.

Вам потрібно впровадити політику запобігання для простору імен payments у Kubernetes 1.35. Які засоби контролю слід забезпечити і як ви обробите одне навантаження, що падає?

Простір імен має забезпечувати стандарт Restricted Pod Security для поточної версії Kubernetes, а навантаження мають працювати без прав root, відкидати можливості, використовувати seccomp RuntimeDefault, уникати просторів імен хоста та уникати небезпечних томів hostPath. Якщо одне навантаження падає, не послаблюйте весь простір імен payments. Визначте точне поле, що падає, і перепроєктуйте навантаження, якщо можливо. Якщо справжній виняток лишається, перемістіть його до виділеного простору імен із явним володінням, жорсткішим RBAC, видимістю для аудиту та компенсаційними засобами контролю.

Раннер CI виконує сторонні сценарії складання. Зараз він використовує стандартне середовище виконання та кеш hostPath. Як ви порівняли б стандартне посилення безпеки з ізоляцією через sandboxed-середовище виконання?

Стандартне посилення безпеки все одно потрібне: відкиньте можливості, уникайте привілейованого режиму, обмежте права ServiceAccount та замініть широкі монтування hostPath. Однак сторонні сценарії складання — це недовірений код, тож сильніша межа зазвичай виправдана. Ізольоване середовище виконання чи ізольований пул нод зменшує імовірність того, що втеча зі складання дістанеться ядра хоста чи сусідніх навантажень. Компроміс — це продуктивність і тестування сумісності, що є розумним для цього класу ризику.

Рецензент бачить `SYS_PTRACE` у специфікації Pod'а, але без `hostPID`. Чи це автоматично втеча з ноди, і яке додаткове питання слід поставити?

Це не автоматично втеча з ноди, бо можливість може застосовуватися лише в межах простору імен процесів контейнера. Рецензент має запитати, чому навантаження потребує трасування і чи може воно інспектувати лише власні процеси. Він також має перевірити комбінації на кшталт hostPID, привілейованого режиму, широкого hostPath чи чутливих токенів, що збільшили б радіус ураження. Це міркування важливе, бо можливості стають набагато небезпечнішими в поєднанні з розширеними просторами імен чи ресурсами хоста.

Практична вправа: аналіз шляху втечі

Розділ «Практична вправа: аналіз шляху втечі»

У цій вправі ви переглянете ризикований Pod із розгорнутого прикладу так, ніби він надійшов у pull request для продакшн-кластера Kubernetes 1.35. Мета — не експлуатувати щось. Мета — діагностувати ризик втечі, оцінити радіус ураження, впровадити безпечнішу специфікацію та порівняти, чи належить навантаження до звичайного простору імен застосунків, чи до спеціального системного шляху.

Використовуйте тимчасовий (scratch) простір імен в одноразовому кластері, якщо вирішите застосовувати приклади. Якщо у вас немає доступного кластера, виконайте огляд на папері за маніфестом. Важлива навичка — пояснити, як кожне налаштування змінює межу довіри ноди і який засіб контролю заблокував би цей шлях до запуску Pod’а.

  • Визначте кожне поле в ризикованому Pod’і, що збільшує ризик втечі з контейнера, та згрупуйте знахідки за спільним використанням просторів імен, доступом до файлової системи хоста, контролем над середовищем виконання та можливостями.
  • Оцініть радіус ураження у разі компрометації процесу застосунку, включаючи файли ноди, процеси хоста, доступ до сокета середовища виконання та права на API Kubernetes.
  • Впровадьте заміну специфікації у стилі Restricted, що прибирає спільне використання просторів імен хоста, прибирає томи hostPath, відкидає можливості, використовує виконання без прав root, встановлює allowPrivilegeEscalation: false та використовує seccomp RuntimeDefault.
  • Порівняйте два дизайни винятку, якщо навантаження насправді є агентом ноди: послаблений простір імен застосунків проти виділеного системного простору імен із цілеспрямованим RBAC та моніторингом.
  • Визначте критерії успіху для політики допуску, написавши, які мітки Pod Security мають існувати на просторі імен застосунків та який простір імен, якщо такий є, може тримати виняток.
Розв'язок: фактори ризику

Ризикований Pod має кілька факторів ризику втечі. Монтування сокета середовища виконання за /var/run/docker.sock може делегувати операції контролю над хостом демону Docker, якщо процес може дістатися сокета. Монтування кореневої файлової системи хоста відкриває файлову систему ноди під /host, що може розкрити облікові дані, стан kubelet, конфігурацію служб та інші чутливі дані. hostPID: true розширює видимість процесів на ноду, а SYS_PTRACE робить цю видимість небезпечнішою, бо трасування більше не обмежене звичайними процесами застосунку. SYS_ADMIN є широкою і має трактуватися як серйозний виняток, бо вона уможливлює багато привілейованих операцій ядра.

Розв'язок: радіус ураження

Радіус ураження включає і шляхи рівня ноди, і рівня Kubernetes. На ноді зловмисник може інспектувати процеси хоста, читати чи змінювати файли хоста залежно від прав та режиму монтування, та використати сокет середовища виконання, щоб запросити нові контейнери із сильнішим доступом. У Kubernetes токен ServiceAccount Pod’а може дозволяти дії з API, тож RBAC слід переглянути, навіть якщо він не видимий у фрагменті. Сукупний ризик вищий за будь-яке окреме поле, бо видимість процесів, доступ до файлової системи, можливості та контроль над середовищем виконання можуть підсилювати одне одного.

Розв'язок: виправлена специфікація Pod'а

Використайте виправлену специфікацію, показану в розгорнутому прикладі, як базову. Вона прибирає спільне використання просторів імен хоста та томи hostPath, працює як UID 1000 з runAsNonRoot: true, встановлює readOnlyRootFilesystem: true, блокує підвищення привілеїв, відкидає всі можливості та запитує seccomp RuntimeDefault. Якщо застосунок потребує доступного на запис тимчасового сховища, додайте вузький emptyDir для цього шляху замість того, щоб робити кореневу файлову систему доступною на запис. Якщо йому потрібна можливість, документуйте точну операцію та додайте лише цю можливість після огляду.

Розв'язок: дизайн винятку

Не послаблюйте спільний простір імен застосунків заради агента ноди. Створіть виділений простір імен із мінімальним рівнем Pod Security, що допускає агента, обмежте, хто може там розгортати, прив’яжіть мінімальний ServiceAccount, обмежте мережевий доступ, де практично, та моніторте поведінку, що була б підозрілою для цього компонента. Якщо код недовірений чи сторонній, оцініть ізольоване середовище виконання чи ізольований пул нод. Виняток має бути видимим, мати власника та переглядатися, а не ховатися поряд зі звичайними застосунками.

  • Ви можете пояснити, чому privileged: true, простори імен хоста, широкий hostPath, сокети середовища виконання та небезпечні можливості є окремими факторами ризику втечі.
  • Ви можете ранжувати радіус ураження за відкритим ресурсом хоста та подальшою дією, яку він уможливлює.
  • Ваша виправлена специфікація відповідає очікуванням контексту безпеки у стилі Restricted для робочого навантаження застосунку.
  • Ваш дизайн винятку тримає повноваження рівня ноди подалі від звичайних просторів імен застосунків.
  • Ви можете обґрунтувати, чи стандартного посилення безпеки середовища виконання достатньо, чи виправдана ізоляція через sandboxed-середовище виконання.

Модуль 4.4: Загрози ланцюга постачання — Дізнайтеся, як скомпрометовані образи, залежності, системи складання та реєстри можуть стати наступним шляхом до кластера.