Модуль 1.6: Практики безпеки (DevSecOps)
Складність:
[СЕРЕДНЯ]— Базове мислення щодо безпекиЧас на виконання: 35-40 хвилин
Попередні вимоги: Концепції CI/CD (Модуль 3)
Що ви зможете зробити
Розділ «Що ви зможете зробити»Після вивчення цього модуля ви зможете:
- Пояснити принцип безпеки «зсув вліво» (shift left) і чому виправляти проблеми на ранніх етапах дешевше
- Визначити основні ризики безпеки Kubernetes (неправильна конфігурація, відкриті дашборди, надмірні права RBAC)
- Описати безпечний CI/CD pipeline зі скануванням образів, керуванням секретами та застосуванням політик
- Порівняти інструменти DevSecOps (Trivy, OPA/Gatekeeper, Falco) та пояснити, від чого захищає кожен із них
- Налаштувати Стандарти безпеки Pod (PSS) для обмеження привілеїв контейнерів на рівні простору імен
- Встановити концепції сканування перед комітом (pre-commit) для запобігання витоку секретів у систему контролю версій
- Написати NetworkPolicy для явного контролю та обмеження трафіку між pod
Чому це важливо
Розділ «Чому це важливо»Раніше безпека була чимось другорядним — командою, яка казала «ні» наприкінці розробки. Це не працює у хмарних (cloud-native) середовищах, де ви деплоїте код багато разів на день. DevSecOps інтегрує безпеку в кожен етап життєвого циклу розробки. Для середовищ Kubernetes, де неправильна конфігурація є ризиком безпеки №1, це критично важливо.
Що таке DevSecOps?
Розділ «Що таке DevSecOps?»DevSecOps — це безпека, інтегрована в DevOps, а не додана поверх нього згодом.
┌─────────────────────────────────────────────────────────────┐│ ТРАДИЦІЙНА БЕЗПЕКА vs DEVSECOPS │├─────────────────────────────────────────────────────────────┤│ ││ Традиційна безпека: ││ ┌─────┐ ┌─────┐ ┌──────────┐ ┌─────────────┐ ││ │ Dev │───►│ QA │───►│ Огляд │───►│ Production │ ││ └─────┘ └─────┘ │ безпеки │ └─────────────┘ ││ └──────────┘ ││ │ ││ Вузьке місце! ││ "Поверніться та виправте" ││ ││ DevSecOps: ││ ┌─────────────────────────────────────────────────────┐ ││ │ Безпека на КОЖНОМУ етапі │ ││ │ │ ││ │ План → Код → Збірка → Тест → Деплой → Моніторинг │ ││ │ ↑ ↑ ↑ ↑ ↑ ↑ │ ││ │ Модель SAST SCA DAST Скан. Безпека │ ││ │ загроз (залежн) конфіг. Runtime │ ││ │ │ ││ └─────────────────────────────────────────────────────┘ ││ ││ Ключова зміна: безпека — це обов'язок кожного ││ │└─────────────────────────────────────────────────────────────┘Філософія «Зсув вліво» (Shift Left)
Розділ «Філософія «Зсув вліво» (Shift Left)»«Зсув вліво» означає виявлення проблем безпеки на ранніх етапах:
Зупиніться та подумайте: Якщо розробник жорстко закодує пароль у гілці з новою функцією, на якому етапі pipeline його ідеально було б виявити, щоб мінімізувати витрати та ризики?
┌─────────────────────────────────────────────────────────────┐│ ВАРТІСТЬ ВИПРАВЛЕННЯ ПРОБЛЕМ БЕЗПЕКИ │├─────────────────────────────────────────────────────────────┤│ ││ Вартість ││ │ ││ $$$│ ┌────┐ ││ │ ┌────┤ │ ││ │ ┌────┤ │ │ ││ $$│ ┌────┤ │ │ │ ││ │ ┌────┤ │ │ │ │ ││ $│ ┌────┤ │ │ │ │ │ ││ │ ┌────┤ │ │ │ │ │ │ ││ │ ┌────┤ │ │ │ │ │ │ │ ││ └──────┴────┴────┴────┴────┴────┴────┴────┴────┴──► ││ Код Збірка Тест Stage Prod Злам ││ ││ Знайдено рано = дешеве виправлення ││ Знайдено в production = дороге виправлення ││ Знайдено після зламу = катастрофа ││ │└─────────────────────────────────────────────────────────────┘Безпека в CI/CD Pipeline
Розділ «Безпека в CI/CD Pipeline»┌─────────────────────────────────────────────────────────────┐│ БЕЗПЕЧНИЙ CI/CD PIPELINE │├─────────────────────────────────────────────────────────────┤│ ││ 1. PRE-COMMIT ││ ├── Сканування секретів (запобігання коміту секретів) ││ └── git-secrets, detect-secrets ││ ││ 2. СТАТИЧНИЙ АНАЛІЗ (SAST) ││ ├── Сканування вихідного коду на вразливості ││ └── Semgrep, SonarQube, CodeQL ││ ││ 3. СКАНУВАННЯ ЗАЛЕЖНОСТЕЙ (SCA) ││ ├── Перевірка залежностей на відомі CVE ││ └── npm audit, Snyk, Dependabot ││ ││ 4. СКАНУВАННЯ КОНТЕЙНЕРІВ ││ ├── Сканування образів на вразливості ││ └── Trivy, Grype, Clair ││ ││ 5. СКАНУВАННЯ КОНФІГУРАЦІЙ ││ ├── Перевірка Kubernetes YAML на помилки ││ └── KubeLinter, Checkov, Kubescape ││ ││ 6. ДИНАМІЧНИЙ АНАЛІЗ (DAST) ││ ├── Тестування запущеного додатка ││ └── OWASP ZAP, Burp Suite ││ │└─────────────────────────────────────────────────────────────┘Безпека контейнерів
Розділ «Безпека контейнерів»1. Безпека образів
Розділ «1. Безпека образів»# ПОГАНО: велика поверхня атаки, запуск від імені rootFROM ubuntu:latestRUN apt-get update && apt-get install -y nginxCOPY app /appCMD ["nginx"]
# ДОБРЕ: мінімальний образ, не root користувачFROM nginx:1.25-alpineRUN adduser -D -u 1000 appuserCOPY --chown=appuser:appuser app /appUSER appuserEXPOSE 80802. Сканування образів
Розділ «2. Сканування образів»# Trivy - найпопулярніший сканер з відкритим кодомtrivy image nginx:1.25
# Приклад виводу:# nginx:1.25 (debian 12.0)# Total: 142 (UNKNOWN: 0, LOW: 89, MEDIUM: 45, HIGH: 7, CRITICAL: 1)3. Підписування образів
Розділ «3. Підписування образів»# Підписуйте образи, щоб переконатися, що вони не були змінені# Використання cosign (sigstore)cosign sign myregistry/myapp:v1.0
# Перевірка перед деплоємcosign verify myregistry/myapp:v1.0Безпека Kubernetes
Розділ «Безпека Kubernetes»Типові помилки конфігурації
Розділ «Типові помилки конфігурації»# ПОГАНО: Pod із надмірними дозволамиapiVersion: v1kind: Podmetadata: name: insecure-podspec: containers: - name: app image: myapp securityContext: privileged: true # Ніколи так не робіть! runAsUser: 0 # Не запускайте від імені root volumeMounts: - name: host mountPath: /host # Не монтуйте файлову систему хоста volumes: - name: host hostPath: path: /
# ДОБРЕ: безпечна конфігурація PodapiVersion: v1kind: Podmetadata: name: secure-podspec: securityContext: runAsNonRoot: true runAsUser: 1000 fsGroup: 1000 containers: - name: app image: myapp securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true capabilities: drop: - ALL resources: limits: memory: "128Mi" cpu: "500m"Стандарти безпеки Pod (Pod Security Standards)
Розділ «Стандарти безпеки Pod (Pod Security Standards)»Kubernetes 1.25+ використовує Стандарти безпеки Pod:
# Застосування стандартів безпеки на рівні простору іменapiVersion: v1kind: Namespacemetadata: name: production labels: pod-security.kubernetes.io/enforce: restricted pod-security.kubernetes.io/warn: restricted pod-security.kubernetes.io/audit: restricted| Рівень | Опис |
|---|---|
| privileged | Немає обмежень (небезпечно) |
| baseline | Мінімальні обмеження, запобігає відомим ескалаціям привілеїв |
| restricted | Суворі обмеження, відповідає найкращим практикам |
Керування секретами
Розділ «Керування секретами»Проблема
Розділ «Проблема»# НІКОЛИ ТАК НЕ РОБІТЬapiVersion: v1kind: ConfigMapmetadata: name: app-configdata: DATABASE_PASSWORD: "supersecret123" # Залишиться в історії Git назавжди!Рішення
Розділ «Рішення»┌─────────────────────────────────────────────────────────────┐│ ВАРІАНТИ КЕРУВАННЯ СЕКРЕТАМИ │├─────────────────────────────────────────────────────────────┤│ ││ 1. Зовнішні менеджери секретів ││ ├── HashiCorp Vault (найпопулярніший) ││ ├── AWS Secrets Manager ││ ├── Azure Key Vault ││ └── Google Secret Manager ││ ││ 2. Kubernetes-Native ││ ├── Sealed Secrets (шифрування для Git) ││ ├── External Secrets (синхронізація з менеджерів) ││ └── SOPS (шифрування YAML-файлів) ││ ││ 3. Ін'єкція під час виконання ││ ├── Vault Agent Sidecar ││ └── CSI Secret Store Driver ││ │└─────────────────────────────────────────────────────────────┘Приклад Sealed Secrets
Розділ «Приклад Sealed Secrets»# Встановіть контролер sealed-secrets# Потім створіть зашифровані секрети, які можна додавати до Git
kubeseal --format yaml < secret.yaml > sealed-secret.yaml
# sealed-secret.yaml можна додавати до репозиторію# Тільки кластер зможе його розшифруватиМережева безпека
Розділ «Мережева безпека»Зупиніться та подумайте: Якщо ви застосуєте NetworkPolicy типу default-deny до простору імен, що станеться з існуючими pod, які зараз спілкуються між собою?
# Мережева політика: дозволити лише певний трафікapiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: api-network-policy namespace: productionspec: podSelector: matchLabels: app: api policyTypes: - Ingress - Egress ingress: - from: - podSelector: matchLabels: app: frontend ports: - protocol: TCP port: 8080 egress: - to: - podSelector: matchLabels: app: database ports: - protocol: TCP port: 5432Інструменти сканування безпеки
Розділ «Інструменти сканування безпеки»KubeLinter (Конфігурація)
Розділ «KubeLinter (Конфігурація)»# Сканування Kubernetes YAML на наявність проблемkube-linter lint deployment.yaml
# Приклад виводу:# deployment.yaml: (object: myapp apps/v1, Kind=Deployment)# - container "app" does not have a read-only root file system# - container "app" is not set to runAsNonRootKubescape (Комплексний аналіз)
Розділ «Kubescape (Комплексний аналіз)»# Повне сканування безпеки згідно з фреймворками типу NSA-CISAkubescape scan framework nsa
# Перевіряє:# - Неправильні конфігурації# - Проблеми RBAC# - Мережеві політики# - Вразливості образівTrivy (Все в одному)
Розділ «Trivy (Все в одному)»# Сканування образу контейнераtrivy image myapp:v1
# Сканування маніфестів Kubernetestrivy config .
# Сканування запущеного кластераtrivy k8s --report summary clusterБезпека під час виконання (Runtime Security)
Розділ «Безпека під час виконання (Runtime Security)»┌─────────────────────────────────────────────────────────────┐│ БЕЗПЕКА RUNTIME │├─────────────────────────────────────────────────────────────┤│ ││ Виявлення: Що відбувається прямо зараз? ││ ┌─────────────────────────────────────────────────────┐ ││ │ Falco (CNCF) │ ││ │ - Моніторинг системних викликів │ ││ │ - Виявлення аномальної поведінки │ ││ │ - Сповіщення про події безпеки │ ││ └─────────────────────────────────────────────────────┘ ││ ││ Приклади правил Falco: ││ - Запуск оболонки (shell) в контейнері ││ - Читання чутливого файлу (/etc/shadow) ││ - Вихідне з'єднання на незвичний порт ││ - Процес запущено від імені root ││ ││ Запобігання: Зупинка небажаних дій ││ ┌─────────────────────────────────────────────────────┐ ││ │ OPA Gatekeeper / Kyverno │ ││ │ - Застосування політик │ ││ │ - Контроль доступу (Admission control) │ ││ │ - Блокування невідповідних ресурсів │ ││ └─────────────────────────────────────────────────────┘ ││ │└─────────────────────────────────────────────────────────────┘Найкращі практики RBAC
Розділ «Найкращі практики RBAC»# Принцип найменших привілеїв# Надавайте лише необхідні дозволи
# ПОГАНО: Права адміністратора кластера для всьогоapiVersion: rbac.authorization.k8s.io/v1kind: ClusterRoleBindingmetadata: name: developer-adminsubjects:- kind: User name: developer@company.comroleRef: kind: ClusterRole name: cluster-admin # Занадто багато повноважень!
# ДОБРЕ: Обмежені дозволи на рівні простору іменapiVersion: rbac.authorization.k8s.io/v1kind: Rolemetadata: namespace: development name: developerrules:- apiGroups: ["apps"] resources: ["deployments"] verbs: ["get", "list", "create", "update"]- apiGroups: [""] resources: ["pods"] verbs: ["get", "list"]---apiVersion: rbac.authorization.k8s.io/v1kind: RoleBindingmetadata: name: developer-binding namespace: developmentsubjects:- kind: User name: developer@company.comroleRef: kind: Role name: developerЧи знали ви?
Розділ «Чи знали ви?»- Понад 90% інцидентів безпеки Kubernetes спричинені неправильною конфігурацією, а не експлойтами нульового дня. Сумнозвісний злам Tesla у 2018 році стався просто тому, що адміністративний дашборд Kubernetes залишився відкритим в інтернеті без пароля.
- Злам Capital One (2019) призвів до викрадення 100 мільйонів заявок на кредитні картки через надмірно поблажливу роль IAM, що підкреслює, чому принцип найменших привілеїв (як-от суворий RBAC) є критично важливим.
- Атака на ланцюжок поставок Codecov (2021) сталася, коли зловмисники змінили bash-скрипт для викрадення змінних середовища CI/CD. Це підкреслює важливість керування секретами та сканування залежностей у пайплайнах.
- Falco обробляє мільярди подій у таких компаніях, як Shopify. У такому масштабі він може виявити шкідливу аномалію — наприклад, несподіваний запуск оболонки в робочому контейнері — протягом мілісекунд.
Типові помилки
Розділ «Типові помилки»| Помилка | Чому це небезпечно | Рішення |
|---|---|---|
| Секрети в Git | Постійна загроза витоку | Використовуйте менеджери секретів |
| Запуск від імені root | Ризик виходу за межі контейнера | Завжди використовуйте runAsNonRoot |
| Без мережевих політик | Горизонтальне переміщення | Політики «заборонити все за замовчуванням» |
| Тег latest | Неможливість відстежити вразливості | Фіксуйте конкретні версії |
| Без сканування образів | Невідомі вразливості | Скануйте в CI/CD |
| Cluster-admin усюди | Великий радіус ураження | RBAC з найменшими привілеями |
Контрольні запитання
Розділ «Контрольні запитання»-
Ваша команда планує новий мікросервіс. Провідний розробник пропонує запускати сканування безпеки лише на фінальному образі контейнера безпосередньо перед деплоєм у production, щоб зекономити час CI. Чому цей підхід є ризикованим у культурі DevSecOps?
Відповідь
Цей підхід порушує принцип «зсуву вліво» (Shift Left), який рекомендує виявляти проблеми безпеки якомога раніше в циклі розробки. Очікування створення фінального образу означає, що будь-які виявлені вразливості (як-от застарілі залежності або небезпечний код) вимагатимуть повернення всієї роботи на етап розробки. Виправлення проблем у production або staging коштує значно дорожче і забирає більше часу, ніж їх виявлення під час локальної розробки або на етапі pull request. Завдяки «зсуву вліво» команди можуть усувати недоліки, поки контекст ще свіжий у пам'яті розробника. -
Розробник створює маніфест Pod, у якому встановлює
runAsUser: 0, оскільки додатку потрібно встановити пакет під час запуску. Якщо цей контейнер буде зламано, у чому полягає основний ризик і як його мінімізувати?Відповідь
Встановлення `runAsUser: 0` означає, що контейнер працює від імені root, що створює серйозний ризик, якщо зловмисник отримає можливість виконувати команди всередині контейнера. У разі використання вразливості зловмисник матиме права рівня root, що значно полегшить вихід за межі контейнера та компрометацію вузла Kubernetes. Щоб мінімізувати це, образ контейнера має бути зібраний з усіма необхідними пакетами під час фази CI, а не під час виконання. Маніфест Pod має вимагати `runAsNonRoot: true` та вказувати ID непривілейованого користувача. -
Вам потрібно впровадити перевірки безпеки у ваш CI/CD pipeline. Менеджер просить вас обрати між SAST (статичне тестування) та DAST (динамічне тестування) через бюджетні обмеження. Як ви поясните різні загрози, на які спрямований кожен із цих методів?
Відповідь
SAST і DAST — це взаємодоповнювальні інструменти, які вирішують різні типи проблем, тому вибір лише одного з них залишає значну «сліпу пляму». SAST аналізує статичний вихідний код до того, як він буде скомпільований або запущений, що дозволяє виявляти захардкоджені секрети, небезпечні виклики функцій та логічні помилки на початку циклу розробки. DAST, навпаки, взаємодіє із запущеним додатком ззовні, імітуючи дії зловмисника для пошуку вразливостей runtime, таких як XSS, неправильно налаштовані HTTP-заголовки або обхід автентифікації. Для надійного пайплайну DevSecOps потрібні обидва інструменти. -
Молодший інженер пропонує додавати маніфест Kubernetes
Secretіз паролями до бази даних прямо в репозиторій Git, стверджуючи, що репозиторій приватний і безпечний. У чому основна помилка в цих міркуваннях і яка є краща альтернатива?Відповідь
Зберігання відкритих секретів у будь-якій системі контролю версій, навіть приватній, є помилковим, оскільки Git зберігає постійну історію всіх змін. Щойно секрет потрапляє в коміт, будь-хто з доступом до читання репозиторію — або той, хто отримає доступ у майбутньому — зможе дістати паролі з історії, навіть якщо файл згодом буде видалено. Кращою альтернативою є використання таких інструментів, як Sealed Secrets, які використовують асиметричне шифрування, щоб секрет можна було безпечно зберігати в Git. Тільки кластер Kubernetes має закритий ключ для розшифрування SealedSecret. -
Ваша організація хоче впровадити політику, згідно з якою жодні pod не можуть запускатися в просторі імен
productionіз привілейованим доступом або монтуванням файлів хоста. Як ви можете реалізувати це нативно в Kubernetes 1.25+ без встановлення сторонніх контролерів?Відповідь
Ви можете реалізувати це нативно, налаштувавши Стандарти безпеки Pod (PSS) на рівні простору імен за допомогою спеціальних міток (labels). Додавши мітку `pod-security.kubernetes.io/enforce: restricted` до простору імен `production`, вбудований контролер Kubernetes автоматично відхилятиме будь-які запити на створення Pod, що порушують суворий профіль безпеки. Цей профіль забороняє привілейовані контейнери, використання мережі хоста та томи hostpath. -
Розробник випадково комітить ключ доступу AWS у свій локальний репозиторій Git. Він усвідомлює помилку до того, як відправити зміни на сервер, але хоче гарантувати, що це ніколи не повториться. Яку практику DevSecOps слід впровадити для запобігання такому сценарію?
Відповідь
Команда має впровадити сканування перед комітом (pre-commit scanning) за допомогою таких інструментів, як `git-secrets` або `trufflehog`, налаштованих як pre-commit hook. Ця практика перехоплює процес коміту локально на машині розробника і сканує додані файли на наявність секретів. Якщо секрет знайдено, hook скасовує коміт, надаючи розробнику негайний зворотний зв'язок і запобігаючи потраплянню секрету в історію Git. Це класичний приклад «зсуву вліво». -
Зловмисник зламав frontend-pod і негайно намагається підключитися до pod бази даних через порт 5432. За замовчуванням Kubernetes дозволяє цей трафік. Який саме ресурс ви маєте написати, щоб заблокувати цей несанкціонований горизонтальний рух (lateral movement)?
Відповідь
Ви маєте написати ресурс Kubernetes `NetworkPolicy`, щоб явно контролювати та обмежувати зв'язок між pod. За замовчуванням усі pod у кластері Kubernetes можуть вільно спілкуватися між собою, що полегшує дії зловмисника після зламу одного з елементів системи. Визначивши NetworkPolicy типу default-deny, а потім явно дозволивши лише вхідний трафік від frontend-pod до бази даних на порт 5432, ви створюєте мережеву межу «нульової довіри» (zero-trust).
Практична вправа
Розділ «Практична вправа»Завдання: Потренуйтеся сканувати безпеку Kubernetes.
# 1. Створіть небезпечний деплойментcat << 'EOF' > insecure-deployment.yamlapiVersion: apps/v1kind: Deploymentmetadata: name: insecure-appspec: replicas: 1 selector: matchLabels: app: insecure template: metadata: labels: app: insecure spec: containers: - name: app image: nginx:latest securityContext: privileged: true runAsUser: 0 ports: - containerPort: 80EOF
# 2. Перевірте за допомогою kubectl (базова перевірка)kubectl apply -f insecure-deployment.yaml --dry-run=server# Примітка: Це не виявить проблем безпеки, лише помилки синтаксису
# 3. Якщо у вас встановлено trivy:# trivy config insecure-deployment.yaml
# 4. Ручний чеклист безпеки:echo "Security Review Checklist:"echo "[ ] Образ використовує конкретний тег (не :latest)"echo "[ ] Контейнер працює не від імені root"echo "[ ] privileged: false"echo "[ ] Встановлено ліміти ресурсів"echo "[ ] readOnlyRootFilesystem: true"echo "[ ] Capabilities відключено (drop ALL)"
# 5. Створіть безпечну версіюcat << 'EOF' > secure-deployment.yamlapiVersion: apps/v1kind: Deploymentmetadata: name: secure-appspec: replicas: 1 selector: matchLabels: app: secure template: metadata: labels: app: secure spec: securityContext: runAsNonRoot: true runAsUser: 1000 fsGroup: 1000 containers: - name: app image: nginx:1.25-alpine securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true capabilities: drop: - ALL ports: - containerPort: 8080 resources: limits: memory: "128Mi" cpu: "500m" requests: memory: "64Mi" cpu: "250m"EOF
# 6. Порівняйте обидва файлиecho "=== Небезпечний vs Безпечний ==="diff insecure-deployment.yaml secure-deployment.yaml || true
# 7. Очищенняrm insecure-deployment.yaml secure-deployment.yamlКритерії успіху: Розуміння різниці між небезпечними та безпечними конфігураціями.
Підсумок
Розділ «Підсумок»DevSecOps інтегрує безпеку в кожен етап:
Ключові концепції:
- Зсув вліво (Shift Left): Виявляйте проблеми на ранніх етапах
- Безпека як код
- Автоматизоване сканування
- Найменші привілеї
Безпека CI/CD:
- SAST: Сканування вихідного коду
- SCA: Сканування залежностей
- Сканування контейнерів: Перевірка образів
- Сканування конфігурацій: Перевірка Kubernetes YAML
Безпека Kubernetes:
- Стандарти безпеки Pod (PSS)
- Мережеві політики (Network Policies)
- RBAC (найменші привілеї)
- Керування секретами
Інструменти:
- Trivy: Образи та конфігурації
- KubeLinter/Kubescape: Конфігурації K8s
- Falco: Виявлення загроз у Runtime
- Vault/Sealed Secrets: Керування секретами
Мислення: Безпека — це обов’язок кожного, а не лише команди безпеки.
Трек завершено!
Розділ «Трек завершено!»Вітаємо! Ви завершили підготовчий трек Сучасні практики DevOps. Тепер ви розумієте:
- Інфраструктуру як код (IaC)
- Робочі процеси GitOps
- CI/CD пайплайни
- Основи Observability
- Концепції Platform Engineering
- Практики безпеки (DevSecOps)
Наступні кроки:
- Програма CKA — Сертифікація адміністратора
- Програма CKAD — Сертифікація розробника
- Філософія та дизайн — Чому Kubernetes переміг?