Kubernetes-кластер, що виконує оборонні мікросервіси, не є inherently zero-trust. Стандартна модель мережевої взаємодії pod дозволяє будь-якому pod ініціювати TCP-з'єднання з будь-яким іншим pod у тій самій мережі кластера — а це означає, що один скомпрометований контейнер може досягти сервісів автентифікації, сховищ даних та командних інтерфейсів, до яких він не має жодних законних підстав для доступу. Service mesh вирішує цю проблему не шляхом переналаштування мережевих ACL — які є нестабільними у динамічних контейнерних середовищах — а шляхом впровадження криптографічної ідентичності та забезпечення виконання політик безпосередньо в шлях даних кожного міжсервісного виклику. Ця стаття розглядає, що це означає на практиці для оборонних кластерів: як SPIFFE/SPIRE інтегрується з архітектурою zero-trust для військових мереж, як трафічна політика на основі намірів замінює периметральне мислення всередині кластера та як підтримувати повну спостережуваність без жодної телеметрії, що перетинає межу класифікації.
Чому периметральна безпека не спрацьовує всередині оборонних кластерів мікросервісів
Модель периметральної безпеки передбачає, що трафік всередині довіреної мережевої межі є безпечним. У монолітному застосунку це припущення має певну обґрунтованість: існує один процес, одна межа довіри та відносно небагато внутрішніх комунікаційних шляхів для захисту. В архітектурі мікросервісів, розгорнутій на Kubernetes, це припущення повністю руйнується. Кластер, що виконує 20 сервісів, має порядку 400 можливих пар сервісів. Не всі вони повинні спілкуватися, але без явного забезпечення на рівні сервісу всі вони можуть. Вразливість в одному сервісі — залежність із уразливістю виконання віддаленого коду, неправильно налаштована змінна середовища, що розкриває облікові дані, незаплатена базова операційна система — надає противнику можливість бічного переміщення по всій мережі кластера.
Режим відмови не є теоретичним. Компромети ланцюжка поставок, спрямовані на контейнерні навантаження, продемонстрували, що після того, як противник отримує виконання коду всередині pod, він агресивно зондує мережу кластера. Без взаємної автентифікації ніщо не заважає скомпрометованому pod викликати внутрішні API безпосередньо: він вже має дійсну IP-адресу кластера, його запити надходять із довіреного діапазону CIDR, а цільовий сервіс не може перевірити ідентичність абонента. Традиційна мережева сегментація через Kubernetes NetworkPolicy допомагає на рівні IP/порт, але нічого не робить для запобігання імітації ідентичності легітимного pod у дозволеному діапазоні адрес, а також не забезпечує жодних обмежень прикладного рівня щодо дозволених операцій.
Service mesh вирішує це, роблячи криптографічну ідентичність навантаження обов'язковою для кожного з'єднання. Кожен sidecar-проксі пред'являє SPIFFE Verifiable Identity Document (SVID) — короткостроковий X.509-сертифікат, що кодує ідентичність облікового запису сервісу pod — і вимагає від віддаленого sidecar пред'явити дійсний SVID у відповідь, перш ніж будь-які дані застосунку передаються. Перевірка ідентичності відбувається на транспортному рівні, прозоро для застосунку, і не може бути обійдена зловмисником, який контролює лише процес застосунку всередині контейнера. Бічне переміщення зменшується з «дістатися до будь-якого pod у мережі кластера» до «дістатися лише до pod, чия політика явно дозволяє ваш SVID як джерело».
Вибір service mesh: Istio проти Linkerd проти Cilium у ізольованих від мережі середовищах
Три реалізації service mesh є виробничо придатними для оборонних Kubernetes-розгортань, кожна з різним профілем компромісів. Istio є найбільш функціонально повним: його рівень даних на основі Envoy підтримує розширене управління трафіком L7, включаючи впровадження збоїв, повторні спроби, переривачі мікросхем, дзеркалювання запитів та детальну AuthorizationPolicy. Площина управління — istiod — нативно інтегрується з SPIFFE/SPIRE для зовнішньої видачі сертифікатів, а його телеметричний конвеєр емітує сумісні з OpenTelemetry метрики та трасування з кожного sidecar. Ціною є операційна складність: Istio має крутішу криву навчання, більший розмір площини управління та sidecar Envoy, що споживають більше пам'яті на pod, ніж альтернативи. Для кластерів із 16+ ГБ оперативної пам'яті на вузол та команд із досвідом конфігурації Envoy виразність політик Istio важко перевершити.
Linkerd застосовує протилежний підхід. Його проксі рівня даних написаний на Rust та спроектований як надлегкий: кожен sidecar linkerd-proxy використовує 10–20 МБ оперативної пам'яті та додає менше 1 мс затримки на кожен перехід порівняно з 50–100 МБ та 0,5–3 мс для Envoy. mTLS з нульовою конфігурацією Linkerd увімкнений за замовчуванням для всього mesh-трафіку без необхідності будь-якого маніфесту PeerAuthentication, що знижує ризик неправильно налаштованого винятку для незашифрованого трафіку. Компромісом є те, що модель політики Linkerd менш виразна на рівні HTTP-методу та шляху, а його площина управління менш безпосередньо інтегрується з зовнішніми SPIRE-видавцями, ніж Istio. Для resource-constrained периферійних кластерів з обмеженою оперативною пам'яттю на вузол ефективність проксі Linkerd є значною операційною перевагою.
Cilium працює на рівні eBPF, а не як sidecar. Вбудовуючи забезпечення виконання політик у програми eBPF ядра Linux, прикріплені до мережевого інтерфейсу кожного pod, Cilium досягає майже нульових накладних витрат на навантаження для забезпечення мережевих політик та базового mTLS. Його ресурс CiliumNetworkPolicy підтримує SPIFFE-ідентично-усвідомлені правила через інтеграцію з SPIRE API, а компонент спостережуваності Hubble забезпечує видимість потоку L4/L7 всередині кластера. Сила Cilium — це продуктивність та безшовна заміна kube-proxy; його обмеженням є те, що забезпечення політик HTTP/gRPC L7 через eBPF є менш зрілим, ніж еквівалент на основі Envoy від Istio для складних сценаріїв авторизації. На практиці багато оборонних кластерів використовують Cilium як CNI для мережевих політик та шифрування, із нашарованими Istio або Linkerd для спостережуваності L7 та детальної AuthorizationPolicy на рівні сервісу.
Взаємний TLS: видача сертифікатів, ротація та інтеграція SPIFFE/SPIRE
Взаємний TLS у service mesh означає, що обидві сторони кожного з'єднання автентифікують одна одну за допомогою X.509-сертифікатів перед обміном будь-якими даними застосунку. Критичним питанням для оборонного розгортання є те, як видаються ці сертифікати, як часто вони ротуються та хто контролює кореневий центр довіри. Нативний Istio використовує власний вбудований центр сертифікації (CA istiod), який видає сертифікати навантаження, дійсні 24 години за замовчуванням. Для оборонного розгортання це є недостатнім з двох причин: кореневий ключ знаходиться всередині кластера (скомпрометований процес istiod розкриває всі ідентичності навантажень), а TTL 24 години є занадто тривалим для середовищ, де може знадобитися швидке відкликання облікових даних.
SPIRE забезпечує правильну архітектуру для оборонних контекстів. SPIRE-сервер виконується як StatefulSet із його пакетом довіри та записами реєстрації, що зберігаються у сховищі даних, яке може знаходитися поза кластером. Агент SPIRE виконується як DaemonSet на кожному вузлі та обробляє атестацію навантаження шляхом перевірки токена облікового запису сервісу Kubernetes кожного pod через API-сервер перед видачею SVID. Видані SVID мають конфігуровані TTL — виробничі оборонні розгортання використовують 1-годинні TTL для стандартних навантажень та 15-хвилинні TTL для навантажень, що обробляють засекречені дані — а агент SPIRE обробляє ротацію автоматично, надсилаючи новий SVID до сокету навантаження до того, як поточний закінчиться. Sidecar mesh зчитує SVID через сокет SPIFFE Workload API та пред'являє його у всіх вихідних TLS-з'єднаннях без жодних змін коду застосунку.
Інтеграція SPIRE з Istio вимагає налаштування istiod для використання SPIRE як постачальника сертифікатів через інтерфейс плагіна upstream CA. Конфігурація CustomCA Istio вказує istiod на GRPC-порт SPIRE-сервера, делегуючи всю видачу та ротацію SVID до SPIRE, тоді як Istio обробляє забезпечення PeerAuthentication та AuthorizationPolicy. Цей поділ відповідальності є важливим: SPIRE відповідає за життєвий цикл ідентичності (атестація, видача, ротація), тоді як Istio відповідає за життєвий цикл політики (які ідентичності можуть спілкуватися за якими шляхами). Оператор, що відкликає доступ навантаження, видаляє його запис реєстрації SPIRE, що призводить до відмови наступної ротації SVID, відключаючи навантаження від mesh при наступному оновленні сертифіката без необхідності будь-яких змін маніфесту політики.
Трафічна політика на основі намірів: allow-listing east-west комунікації
Принцип default-deny вимагає, щоб жоден міжсервісний трафік не був дозволений, якщо це явно не дозволено політикою. В Istio це реалізується за допомогою загальнокластерного маніфесту AuthorizationPolicy з порожнім блоком правил та action: DENY — який блокує весь трафік — після чого йдуть вузькі дозвільні політики для кожної легітимної пари сервісів. Кожна дозвільна політика називає принципал-джерело (SPIFFE URI облікового запису сервісу абонента), цільовий сервіс та точний набір HTTP-методів або імен gRPC-сервісів, для яких виклик авторизовано. Наприклад, політика, що авторизує сервіс прийому даних сенсорів виконувати POST до API злиття даних, не дозволяє також виконувати GET історичних записів або викликати адміністративну точку, навіть якщо обидва виконуються на тому самому порту цільового сервісу. Гранулярність — на рівні операції, а не лише TCP-з'єднання.
Написання та підтримка цього набору політик вимагає дисципліни. Кластер, що зростає з 10 до 30 сервісів протягом 18 місяців, накопичує сотні дозвільних записів, а застарілі записи для виведених із експлуатації сервісів стають латентною поверхнею атаки. Дві практики запобігають цьому накопиченню. По-перше, ставтеся до маніфестів AuthorizationPolicy як до коду: зберігайте їх у тому самому репозиторії з контролем версій, що й маніфести застосунків, вимагайте рецензування кожного нового дозвільного запису та щоквартально проводьте аудит набору політик відповідно до переліку поточних сервісів. По-друге, використовуйте журналювання доступу mesh — кожен відхилений запит генерує запис у журналі sidecar, що включає SVID-джерело, призначення та операцію — для виявлення легітимних шляхів трафіку, яким бракує політики, а не обходу mesh мовчки. Це журналювання також забезпечує криміналістичний слід, необхідний багатьом рамкам безпеки оборони для демонстрації того, що рішення про контроль доступу піддаються аудиту.
Ключова думка: Найпоширенішою хибною конфігурацією у zero-trust розгортаннях service mesh є застосування PeerAuthentication у режимі PERMISSIVE під час міграційного періоду з подальшим ненастанням переходу до STRICT. У режимі PERMISSIVE приймаються як TLS, так і незашифровані з'єднання, що означає, що mesh забезпечує атестацію ідентичності лише для з'єднань, які добровільно пред'являють сертифікат. Противник, що діє з pod без mesh — скомпрометований init-контейнер, залишений запущеним відлагоджувальний pod, навантаження DaemonSet, яке ніколи не отримало sidecar-інжекцію — може спілкуватися з будь-яким сервісом у незашифрованому вигляді, повністю обходячи перевірку ідентичності. Встановіть чітку дату переходу до режиму STRICT та використовуйте istioctl analyze для перерахування будь-яких залишкових незашифрованих шляхів до цієї дати.
Спостережуваність без витоку даних: внутрішньокластерні метрики та трасування
Service mesh автоматично генерує розширену телеметрію зі своїх sidecar-проксі: частоти запитів на сервіс, частоти помилок із розбивкою за HTTP-кодом статусу та статусом gRPC, перцентилі затримки (p50, p95, p99), кількість активних з'єднань та метрики TLS-рукостискань. У комерційному хмарному розгортанні ця телеметрія зазвичай пересилається до SaaS-платформи спостережуваності. У засекреченому військовому кластері будь-який телеметричний конвеєр, що надсилає дані за межу класифікації, є потенційним вектором витоку і архітектурно заборонений. Весь стек спостережуваності повинен бути розгорнутий всередині межі кластера та сам повинен контролюватися тими самими mesh-політиками, що регулюють трафік застосунків.
Стандартний внутрішньокластерний стек спостережуваності для service mesh складається з Prometheus для збору метрик, Grafana для візуалізації та Jaeger або Tempo для розподіленого трасування. Prometheus збирає дані з точки статистики Envoy (порт 15090) або точки метрик linkerd-proxy на кожному mesh-pod із конфігурованим інтервалом. Grafana підключається виключно до внутрішньокластерних екземплярів Prometheus та Loki — жодних зовнішніх підключень до джерел даних не налаштовано. Jaeger отримує span-трасування, переслані sidecar Envoy через протокол Zipkin або OpenTelemetry до локального для кластера кінцевого пункту збирача. Усе постійне сховище для метрик, трасувань та журналів використовує PersistentVolume, локальні для кластера та підкріплені зашифрованим блочним сховищем. Простір імен моніторингу сам несе NetworkPolicy, що блокує весь egress до зовнішніх діапазонів IP, роблячи архітектурно неможливим витік телеметрії з кластера навіть у разі введення неправильно налаштованого конвеєра.
Для Kubernetes-кластерів, загартованих для оборонних навантажень, варто зазначити, що стек спостережуваності також повинен бути взятий з ізольованих реєстрів. Образи Prometheus, Grafana, Jaeger та Loki повинні бути дзеркальні у внутрішній реєстр із верифікованими хешами до того, як кластер буде поміщений за межу класифікації. Політики витягування образів повинні бути встановлені на Never або IfNotPresent із розумінням того, що образи ніколи не оновлюватимуться з зовнішнього джерела. Будь-яке оновлення стека спостережуваності вимагає формального процесу управління змінами, що доставляє оновлені образи через процедуру ізоляції, а не простого оновлення Helm-чарту з публічного репозиторію чартів.
Накладні витрати sidecar у resource-constrained оборонних периферійних кластерах
Периферійні кластери, розгорнуті поблизу операцій — що виконуються на малогабаритних серверах або захищених обчислювальних платформах із 32–64 ГБ оперативної пам'яті та 4–8 вузлами — стикаються з ресурсним бюджетом, який робить накладні витрати sidecar реальним інженерним обмеженням, а не теоретичним питанням. Sidecar Envoy від Istio у стаціонарному стані споживає 50–100 МБ резидентної пам'яті та до 0,5 vCPU під час високопропускних навантажень. Кластер із 40 pod споживає 2–4 ГБ сукупної пам'яті sidecar, приблизно 6–12% загальної оперативної пам'яті кластера на 32 ГБ. Сама площина управління — istiod, Prometheus, Grafana, Jaeger — додає ще 2–4 ГБ, доводячи загальні накладні витрати інфраструктури mesh до 15–25% пам'яті кластера до врахування будь-яких навантажень застосунків.
Три варіанти зменшують ці накладні витрати у обмежених розгортаннях. По-перше, Rust-based проксі Linkerd є найефективнішим доступним sidecar: 10–20 МБ на pod замість 50–100 МБ для Envoy, та накладні витрати затримки менше 1 мс на перехід. Для кластерів, де вимоги до гранулярності політики L7 можуть бути задоволені моделлю політики Linkerd, економія пам'яті є суттєвою. По-друге, режим ambient mesh Istio (доступний починаючи з Istio 1.22) повністю усуває per-pod sidecar, замінюючи їх на per-node ztunnel-проксі, що обробляє mTLS для всіх pod на вузлі. Режим ambient знижує накладні витрати на pod майже до нуля ціною переміщення забезпечення політик з per-workload sidecar до per-node проксі, що забезпечує дещо більш грубу гранулярність політики для навантажень, яким потрібні рішення авторизації на рівні запиту. По-третє, вибіркова інжекція — інжектування sidecar лише у pod, яким потрібне забезпечення політики L7, та використання eBPF-шифрування L4 Cilium для решти — балансує гранулярність забезпечення проти споживання ресурсів для різнорідних навантажень кластера.
Взаємодія між споживанням ресурсів sidecar та управлінням секретами в оборонних CI/CD-конвеєрах заслуговує на явну згадку. Sidecar-и інжекції секретів (Vault Agent Injector, Secrets Store CSI Driver) додають ще один контейнер на pod. Периферійний кластер, що виконує як sidecar mesh, так і sidecar інжекції секретів на pod застосунку, має два інфраструктурних контейнери на кожен контейнер застосунку, подвоюючи кількість контейнерів та додаючи 60–120 МБ інфраструктурних накладних витрат на пару pod. Консолідація є можливою: агент SPIRE може слугувати як видавцем ідентичності для mesh, так і механізмом доставки секретів навантаження для секретів, що можуть бути виражені як SVID-авторизовані ролі Vault, усуваючи окремий sidecar інжекції секретів для таких навантажень.
Інтеграція політики service mesh із RBAC та управлінням секретами
Kubernetes RBAC регулює, хто може читати та змінювати об'єкти API Kubernetes — включаючи ресурси AuthorizationPolicy, PeerAuthentication та конфігурації mesh, що визначають стан безпеки service mesh. Якщо конфігурація RBAC дозволяє широкому набору принципалів змінювати об'єкти AuthorizationPolicy, рівень контролю доступу mesh може бути ослаблений будь-яким із цих принципалів. Правильне оборонне розгортання ставиться до маніфестів mesh-політики як до цінних об'єктів безпеки: лише обліковий запис сервісу CI/CD, що застосовує маніфести з репозиторію політик із контролем версій, повинен мати доступ на запис до ресурсів AuthorizationPolicy та PeerAuthentication, і лише адміністратори кластера повинні мати можливість змінювати записи реєстрації SPIRE. Всі інші принципали — включаючи окремі облікові записи сервісів застосунків — повинні мати доступ лише для читання або не мати доступу до цих об'єктів.
Зв'язок між рівнем ідентичності mesh та рівнем управління секретами є двонаправленим. Mesh використовує SPIFFE SVID для автентифікації міжсервісних викликів на транспортному рівні. Управління секретами (Vault, Kubernetes Secrets Store CSI Driver) використовує ті самі ідентичності на основі SVID для визначення того, яким навантаженням які секрети можуть надходити на рівні застосунку. Навантаження зі SPIFFE ID spiffe://cluster.local/ns/fusion/sa/data-processor може бути зіставлено з роллю Vault, що надає доступ для читання саме до облікових даних бази даних, які потрібні цьому сервісу — і нічого більше. Це означає, що система ідентичності mesh та система доставки секретів мають єдине авторитетне джерело ідентичності навантаження, усуваючи ризик невідповідності, коли навантаженню дозволено мережевий доступ, але не секрети, необхідні для його використання, або навпаки. Підтримка цього узгодження вимагає, щоб записи реєстрації SPIRE, визначення ролей Vault та маніфести AuthorizationPolicy mesh оновлювалися разом при додаванні, зміні або виведенні з експлуатації сервісу.
Журналювання аудиту пов'язує три системи для забезпечення відповідності вимогам та реагування на інциденти. Sidecar mesh реєструє кожне рішення доступу — дозвіл або відмову — із верифікованим SVID джерела, призначенням, операцією та міткою часу. Vault реєструє кожен доступ до секрету з ідентичністю, що робить запит, та доступним шляхом секрету. Журнали аудиту API-сервера Kubernetes фіксують кожен RBAC-регульований виклик API. Разом ці три потоки журналів забезпечують повний аудиторський слід від «який мережевий виклик було здійснено» через «які секрети були отримані в результаті» до «хто змінив політику, що регулювала обидва». Для оборонних середовищ, що діють відповідно до формальних вимог акредитації, ця простежуваність по рівнях ідентичності, контролю доступу та секретів часто є обов'язковою вимогою відповідності, а не операційним зручністю.
Безпека міжсервісної взаємодії типу zero-trust для засекречених середовищ
Corvus QUANTUM побудований на принципах zero-trust із взаємним TLS у всіх міжсервісних комунікаціях, забезпеченням виконання трафічних політик та внутрішньокластерною спостережуваністю, що відповідає вимогам засекречених військових середовищ.
Цей аналіз підготовлений інженерами Corvus Intelligence, які розробляють критично важливі для місії застосунки ISR та польові застосунки для оборонних і урядових організацій. Дізнатися про нашу команду →