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

Модуль 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 — це безпека, інтегрована в DevOps, а не додана поверх нього згодом.

┌─────────────────────────────────────────────────────────────┐
│ ТРАДИЦІЙНА БЕЗПЕКА vs DEVSECOPS │
├─────────────────────────────────────────────────────────────┤
│ │
│ Традиційна безпека: │
│ ┌─────┐ ┌─────┐ ┌──────────┐ ┌─────────────┐ │
│ │ Dev │───►│ QA │───►│ Огляд │───►│ Production │ │
│ └─────┘ └─────┘ │ безпеки │ └─────────────┘ │
│ └──────────┘ │
│ │ │
│ Вузьке місце! │
│ "Поверніться та виправте" │
│ │
│ DevSecOps: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Безпека на КОЖНОМУ етапі │ │
│ │ │ │
│ │ План → Код → Збірка → Тест → Деплой → Моніторинг │ │
│ │ ↑ ↑ ↑ ↑ ↑ ↑ │ │
│ │ Модель SAST SCA DAST Скан. Безпека │ │
│ │ загроз (залежн) конфіг. Runtime │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ Ключова зміна: безпека — це обов'язок кожного │
│ │
└─────────────────────────────────────────────────────────────┘

Філософія «Зсув вліво» (Shift Left)

Розділ «Філософія «Зсув вліво» (Shift Left)»

«Зсув вліво» означає виявлення проблем безпеки на ранніх етапах:

Зупиніться та подумайте: Якщо розробник жорстко закодує пароль у гілці з новою функцією, на якому етапі pipeline його ідеально було б виявити, щоб мінімізувати витрати та ризики?

┌─────────────────────────────────────────────────────────────┐
│ ВАРТІСТЬ ВИПРАВЛЕННЯ ПРОБЛЕМ БЕЗПЕКИ │
├─────────────────────────────────────────────────────────────┤
│ │
│ Вартість │
│ │ │
│ $$$│ ┌────┐ │
│ │ ┌────┤ │ │
│ │ ┌────┤ │ │ │
│ $$│ ┌────┤ │ │ │ │
│ │ ┌────┤ │ │ │ │ │
│ $│ ┌────┤ │ │ │ │ │ │
│ │ ┌────┤ │ │ │ │ │ │ │
│ │ ┌────┤ │ │ │ │ │ │ │ │
│ └──────┴────┴────┴────┴────┴────┴────┴────┴────┴──► │
│ Код Збірка Тест Stage Prod Злам │
│ │
│ Знайдено рано = дешеве виправлення │
│ Знайдено в production = дороге виправлення │
│ Знайдено після зламу = катастрофа │
│ │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│ БЕЗПЕЧНИЙ 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 │
│ │
└─────────────────────────────────────────────────────────────┘

Безпека контейнерів

Розділ «Безпека контейнерів»
# ПОГАНО: велика поверхня атаки, запуск від імені root
FROM ubuntu:latest
RUN apt-get update && apt-get install -y nginx
COPY app /app
CMD ["nginx"]
# ДОБРЕ: мінімальний образ, не root користувач
FROM nginx:1.25-alpine
RUN adduser -D -u 1000 appuser
COPY --chown=appuser:appuser app /app
USER appuser
EXPOSE 8080

2. Сканування образів

Розділ «2. Сканування образів»
Terminal window
# 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. Підписування образів»
Terminal window
# Підписуйте образи, щоб переконатися, що вони не були змінені
# Використання cosign (sigstore)
cosign sign myregistry/myapp:v1.0
# Перевірка перед деплоєм
cosign verify myregistry/myapp:v1.0

Типові помилки конфігурації

Розділ «Типові помилки конфігурації»
# ПОГАНО: Pod із надмірними дозволами
apiVersion: v1
kind: Pod
metadata:
name: insecure-pod
spec:
containers:
- name: app
image: myapp
securityContext:
privileged: true # Ніколи так не робіть!
runAsUser: 0 # Не запускайте від імені root
volumeMounts:
- name: host
mountPath: /host # Не монтуйте файлову систему хоста
volumes:
- name: host
hostPath:
path: /
# ДОБРЕ: безпечна конфігурація Pod
apiVersion: v1
kind: Pod
metadata:
name: secure-pod
spec:
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: v1
kind: Namespace
metadata:
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: v1
kind: ConfigMap
metadata:
name: app-config
data:
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 │
│ │
└─────────────────────────────────────────────────────────────┘
Terminal window
# Встановіть контролер sealed-secrets
# Потім створіть зашифровані секрети, які можна додавати до Git
kubeseal --format yaml < secret.yaml > sealed-secret.yaml
# sealed-secret.yaml можна додавати до репозиторію
# Тільки кластер зможе його розшифрувати

Зупиніться та подумайте: Якщо ви застосуєте NetworkPolicy типу default-deny до простору імен, що станеться з існуючими pod, які зараз спілкуються між собою?

# Мережева політика: дозволити лише певний трафік
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-network-policy
namespace: production
spec:
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 (Конфігурація)»
Terminal window
# Сканування 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 runAsNonRoot

Kubescape (Комплексний аналіз)

Розділ «Kubescape (Комплексний аналіз)»
Terminal window
# Повне сканування безпеки згідно з фреймворками типу NSA-CISA
kubescape scan framework nsa
# Перевіряє:
# - Неправильні конфігурації
# - Проблеми RBAC
# - Мережеві політики
# - Вразливості образів
Terminal window
# Сканування образу контейнера
trivy image myapp:v1
# Сканування маніфестів Kubernetes
trivy 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/v1
kind: ClusterRoleBinding
metadata:
name: developer-admin
subjects:
- kind: User
name: developer@company.com
roleRef:
kind: ClusterRole
name: cluster-admin # Занадто багато повноважень!
# ДОБРЕ: Обмежені дозволи на рівні простору імен
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: development
name: developer
rules:
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "create", "update"]
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: developer-binding
namespace: development
subjects:
- kind: User
name: developer@company.com
roleRef:
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 з найменшими привілеями

Контрольні запитання

Розділ «Контрольні запитання»
  1. Ваша команда планує новий мікросервіс. Провідний розробник пропонує запускати сканування безпеки лише на фінальному образі контейнера безпосередньо перед деплоєм у production, щоб зекономити час CI. Чому цей підхід є ризикованим у культурі DevSecOps?

    Відповідь Цей підхід порушує принцип «зсуву вліво» (Shift Left), який рекомендує виявляти проблеми безпеки якомога раніше в циклі розробки. Очікування створення фінального образу означає, що будь-які виявлені вразливості (як-от застарілі залежності або небезпечний код) вимагатимуть повернення всієї роботи на етап розробки. Виправлення проблем у production або staging коштує значно дорожче і забирає більше часу, ніж їх виявлення під час локальної розробки або на етапі pull request. Завдяки «зсуву вліво» команди можуть усувати недоліки, поки контекст ще свіжий у пам'яті розробника.
  2. Розробник створює маніфест Pod, у якому встановлює runAsUser: 0, оскільки додатку потрібно встановити пакет під час запуску. Якщо цей контейнер буде зламано, у чому полягає основний ризик і як його мінімізувати?

    Відповідь Встановлення `runAsUser: 0` означає, що контейнер працює від імені root, що створює серйозний ризик, якщо зловмисник отримає можливість виконувати команди всередині контейнера. У разі використання вразливості зловмисник матиме права рівня root, що значно полегшить вихід за межі контейнера та компрометацію вузла Kubernetes. Щоб мінімізувати це, образ контейнера має бути зібраний з усіма необхідними пакетами під час фази CI, а не під час виконання. Маніфест Pod має вимагати `runAsNonRoot: true` та вказувати ID непривілейованого користувача.
  3. Вам потрібно впровадити перевірки безпеки у ваш CI/CD pipeline. Менеджер просить вас обрати між SAST (статичне тестування) та DAST (динамічне тестування) через бюджетні обмеження. Як ви поясните різні загрози, на які спрямований кожен із цих методів?

    Відповідь SAST і DAST — це взаємодоповнювальні інструменти, які вирішують різні типи проблем, тому вибір лише одного з них залишає значну «сліпу пляму». SAST аналізує статичний вихідний код до того, як він буде скомпільований або запущений, що дозволяє виявляти захардкоджені секрети, небезпечні виклики функцій та логічні помилки на початку циклу розробки. DAST, навпаки, взаємодіє із запущеним додатком ззовні, імітуючи дії зловмисника для пошуку вразливостей runtime, таких як XSS, неправильно налаштовані HTTP-заголовки або обхід автентифікації. Для надійного пайплайну DevSecOps потрібні обидва інструменти.
  4. Молодший інженер пропонує додавати маніфест Kubernetes Secret із паролями до бази даних прямо в репозиторій Git, стверджуючи, що репозиторій приватний і безпечний. У чому основна помилка в цих міркуваннях і яка є краща альтернатива?

    Відповідь Зберігання відкритих секретів у будь-якій системі контролю версій, навіть приватній, є помилковим, оскільки Git зберігає постійну історію всіх змін. Щойно секрет потрапляє в коміт, будь-хто з доступом до читання репозиторію — або той, хто отримає доступ у майбутньому — зможе дістати паролі з історії, навіть якщо файл згодом буде видалено. Кращою альтернативою є використання таких інструментів, як Sealed Secrets, які використовують асиметричне шифрування, щоб секрет можна було безпечно зберігати в Git. Тільки кластер Kubernetes має закритий ключ для розшифрування SealedSecret.
  5. Ваша організація хоче впровадити політику, згідно з якою жодні pod не можуть запускатися в просторі імен production із привілейованим доступом або монтуванням файлів хоста. Як ви можете реалізувати це нативно в Kubernetes 1.25+ без встановлення сторонніх контролерів?

    Відповідь Ви можете реалізувати це нативно, налаштувавши Стандарти безпеки Pod (PSS) на рівні простору імен за допомогою спеціальних міток (labels). Додавши мітку `pod-security.kubernetes.io/enforce: restricted` до простору імен `production`, вбудований контролер Kubernetes автоматично відхилятиме будь-які запити на створення Pod, що порушують суворий профіль безпеки. Цей профіль забороняє привілейовані контейнери, використання мережі хоста та томи hostpath.
  6. Розробник випадково комітить ключ доступу AWS у свій локальний репозиторій Git. Він усвідомлює помилку до того, як відправити зміни на сервер, але хоче гарантувати, що це ніколи не повториться. Яку практику DevSecOps слід впровадити для запобігання такому сценарію?

    Відповідь Команда має впровадити сканування перед комітом (pre-commit scanning) за допомогою таких інструментів, як `git-secrets` або `trufflehog`, налаштованих як pre-commit hook. Ця практика перехоплює процес коміту локально на машині розробника і сканує додані файли на наявність секретів. Якщо секрет знайдено, hook скасовує коміт, надаючи розробнику негайний зворотний зв'язок і запобігаючи потраплянню секрету в історію Git. Це класичний приклад «зсуву вліво».
  7. Зловмисник зламав frontend-pod і негайно намагається підключитися до pod бази даних через порт 5432. За замовчуванням Kubernetes дозволяє цей трафік. Який саме ресурс ви маєте написати, щоб заблокувати цей несанкціонований горизонтальний рух (lateral movement)?

    Відповідь Ви маєте написати ресурс Kubernetes `NetworkPolicy`, щоб явно контролювати та обмежувати зв'язок між pod. За замовчуванням усі pod у кластері Kubernetes можуть вільно спілкуватися між собою, що полегшує дії зловмисника після зламу одного з елементів системи. Визначивши NetworkPolicy типу default-deny, а потім явно дозволивши лише вхідний трафік від frontend-pod до бази даних на порт 5432, ви створюєте мережеву межу «нульової довіри» (zero-trust).

Завдання: Потренуйтеся сканувати безпеку Kubernetes.

Terminal window
# 1. Створіть небезпечний деплоймент
cat << 'EOF' > insecure-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: insecure-app
spec:
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: 80
EOF
# 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.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: secure-app
spec:
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. Тепер ви розумієте:

  1. Інфраструктуру як код (IaC)
  2. Робочі процеси GitOps
  3. CI/CD пайплайни
  4. Основи Observability
  5. Концепції Platform Engineering
  6. Практики безпеки (DevSecOps)

Наступні кроки: