Продовження масштабного гайду із захисту інфраструктури. Фундамент закладено, архітектуру та вектори атак за методологією STRIDE розібрано, а тестовий полігон готовий до роботи. Тепер час переходити до безпосереднього харднінгу (hardening) серцевини системи. Робота починається із захисту головних вузлів управління, адже саме тут приймаються всі критичні рішення. У другій частині ми розбираємося, як виставити анонімів за двері, чому стандартні секрети в Kubernetes – це ілюзія безпеки, і як правильно налаштувати шифрування даних.
Центральним нервовим вузлом усієї системи є API-сервер. Через нього проходять абсолютно всі маніпуляції. Оставляти його налаштування у стані за замовчуванням – це величезний і невиправданий ризик.
Найперший, найпростіший і водночас критично важливий крок – повне відключення анонимного доступу. За замовчуванням API-сервер часто налаштований так, що може приймати певні запити від неаутентифікованих користувачів для специфічних ендпоінтів (наприклад, для перевірки стану health check). Зловмисники використовують цю особливість для безперешкодної розвідки та збору інформації про версії компонентів. Ця проблема вирішується додаванням одного простого прапорця до конфігураційного маніфесту API-сервера:
# Фрагмент конфігурації /etc/kubernetes/manifests/kube-apiserver.yaml
spec:
containers:
- command:
- kube-apiserver
- --anonymous-auth=false
Після збереження файлу kubelet автоматично перезапустить компонент із новими, жорсткішими правилами. Важливо також переконатися, що всі ключові компоненти (API-сервер, etcd, kubelet) регулярно оновлюються, оскільки розробники постійно закривають нововиявлені вразливості нульового дня.
Після того як анонімні гості опинилися за бортом, на перший план виходить система рольового контролю доступу (RBAC). Тут діє єдине залізне правило – принцип найменших привілеїв. Кожному сервісному акаунту та кожному інженеру видається рівно той мінімум прав, який необхідний для виконання поточного завдання. Якщо CI/CD пайплайну потрібно лише оновлювати образи для деплойменту статей на порталі HackYourMom, йому категорично не можна видавати права на читання секретів або, тим більше, роль cluster-admin.
Аудит виділених дозволів часто перетворюється на хаос при масштабуванні проєкту. Для швидкої перевірки прав доступу ідеально підходять консольні плагини, такі як kubectl-who-can. Вони дозволяють миттєво побачити, хто саме має право виконати конкретну дію:
# Приклад перевірки того, хто може читати секрети у просторі імен production kubectl who-can get secrets -n production
Детальніше про правильну побудову ролей та прив’язок (RoleBindings) завжди корисно читати в офіційній документації з RBAC.
Окремої уваги заслуговує концепція аварийного доступу, або стратегія «розбитого скла» (Break-Glass). Практично всі сучасні ентерпрайз-кластери інтегруються з розширеними зовнішніми провайдерами ідентифікації (IdP) через протоколи OIDC. Але існує сувора реальність: зовнішні сервіси іноді «падають». Якщо провайдер авторизації стане недоступним під час критичної аварії, доступ до інфраструктури буде повністю втрачено саме тоді, коли він потрібен найбільше. Для таких позаштатних ситуацій завжди генерується зарезервований статичний сертифікат адміністратора з максимальними привілеями. Цей файл має зберігатися у надзвичайно надійному місці (наприклад, у фізичному сейфі на зашифрованій флешці) і використовуватися виключно у випадку відмови основних систем.
База даних etcd – це серце інфраструктури, де зберігається абсолютно вся конфігурація, стани і критично важливі секрети. Розуміння того, як система працює із секретами за замовчуванням, часто викликає холодний піт. Стандартний ресурс Secret не забезпечує жодного криптографічного шифрування. Дані просто і банально кодуються у формат base64. Будь-хто, хто отримає прямий доступ до файлів etcd на фізичному сервері або випадково знайде бекап бази на відкритому S3-бакеті, зможе прочитати паролі до продуктових баз даних за допомогою звичайного текстового редактора.
Для усунення цієї архітектурної прірви застосовується обов’язкове шифрування даних у стані спокою (Data-at-rest encryption). Це гарантує, що навіть при фізичній крадіжці диска із серверної стійки або повній компрометації дампів etcd, чутливі дані залишаться набором нечитабельних символів.
Найбільш просунутий, надійний та сучасний підхід – це використання механізму KMS v2 (Key Management Service) із зовнішнім хардверним або софтверним провайдером шифрування. Найкращим стандартом індустрії для цієї ролі є HashiCorp Vault. При такій топології головні ключі шифрування (KEK) взагалі не зберігаються в самому кластері, а знаходяться у зовнішньому, максимально захищеному сховищі. Система звертається до Vault виключно для того, щоб безпечно зашифрувати або розшифрувати ключі даних (DEK).
Приклад базової локальної конфігурації шифрування (EncryptionConfiguration), яка наказує API-серверу шифрувати секрети з використанням алгоритму AES-CBC (для випадків, коли повноцінний Vault ще перебуває на стадії впровадження):
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
providers:
- aescbc:
keys:
- name: primary-key
secret: <сгенерований-надійний-ключ-у-форматі-base64>
- identity: {}
Кластер проєктувався для максимальної зручності розробників: за замовчуванням абсолютно всі поди можуть вільно та безперешкодно спілкуватися один з одним без жодних обмежень чи фаєрволів. Якщо зловмиснику вдасться зламати один маленький, забутий розробниками тестовий контейнер із вразливістю, він зможе спокійно сканувати всю внутрішню мережу і атакувати критичні платіжні шлюзи, які знаходяться зовсім в іншому кінці системи.
Цей архітектурний недолік кардинально усувається за допомогою мережевих політик (Network Policies). Вони працюють як розумний внутрішній фаєрвол на рівні кожного окремого мікросервісу. Впровадження мережевих політик вимагає суворого переходу до концепції Zero Trust (нулевої довіри).
Першим і безальтернативним кроком у будь-якому захищеному середовищі має бути створення політики Default Deny. Ця політика жорстко і безкомпромісно блокує абсолютно весь вхідний та вихідний трафік. Після її активації інженерам доведеться свідомо та точково прописувати правила для кожного дозволеного з’єднання.
Приклад маніфесту, який повністю блокує будь-яку мережеву активність в обраному просторі імен:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: secure-production
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
Після застосування такого жорсткого маніфесту зв’язок між компонентами відновлюється ювелірно. Наприклад, дозволяється вхідний трафік виключно від Ingress-контроллера до подів із веб-сервером, а вихідний трафік від веб-сервера – виключно до конкретного пода з базою даних і суворо на визначений порт. Це вимагає ретельного планування, але гарантує, що компрометація одного мікросервісу не призведе до ефекту доміно. Більше практичних прикладів точкових дозволів зібрано в офіційних гайдах з Network Policies.
Підбиваючи підсумки цього етапу: головні двері інфраструктури надійно замкнено. Анонімний доступ до API-сервера повністю відключено, права розмежовано за суворим принципом найменших привілеїв, а для критичних аварій підготовлено план аварійного доступу. Секрети більше не лежать у відкритому вигляді завдяки криптографічному шифруванню бази etcd, а внутрішня мережа сегментована жорсткими політиками нульової довіри, які блокують будь-який нелегітимний рух трафіку.
Проте захист платформи управління (Control Plane) – це лише половина справи. Кластер існує для того, щоб запускати додатки, і саме вони найчастіше стають точкою входу для атак. У третій, фінальній частині матеріалу фокус зміститься безпосередньо на робочі навантаження. Розглядатиметься безпека самих контейнерів: використання мінімалістичних образів без зайвих залежностей, налаштування Security Context для жорсткого обмеження системних викликів, робота з Admission Controllers (наприклад, OPA Gatekeeper) для автоматичного блокування небезпечних розгортань, а також налаштування безперервного аудиту та виявлення загроз у реальному часі за допомогою Falco. Далі буде ще більше технічного хардкору.