Модуль 5.1: Безпека образів
Складність:
[СЕРЕДНЯ]- Основні знанняЧас на виконання: 25-30 хвилин
Передумови: Модуль 4.4: Загрози ланцюга постачання
Що ви зможете робити
Розділ «Що ви зможете робити»Після завершення цього модуля ви зможете:
- Оцінити безпеку образів контейнерів протягом життєвого циклу збірка-зберігання-розгортання-виконання
- Оцінити практики зміцнення образів: мінімальні базові образи, користувач не-root, багатоетапні збірки
- Визначити шаблони вразливих образів: теги latest, несканований реєстр, вбудовані секрети
- Пояснити як сканування образів, підпис та admission control формують конвеєр захисту у глибину
Чому цей модуль важливий
Розділ «Чому цей модуль важливий»Образи контейнерів є форматом пакування для всіх навантажень Kubernetes. Кожна вразливість, неправильна конфігурація чи шкідливий код в образі стає частиною вашого середовища виконання. Захист образів протягом їхнього життєвого циклу — збірка, зберігання, розгортання, виконання — є фундаментом безпеки Kubernetes.
KCSA перевіряє ваші знання практик безпеки образів та управління вразливостями.
Життєвий цикл безпеки образів
Розділ «Життєвий цикл безпеки образів»┌─────────────────────────────────────────────────────────────┐│ ЖИТТЄВИЙ ЦИКЛ БЕЗПЕКИ ОБРАЗІВ │├─────────────────────────────────────────────────────────────┤│ ││ ЗБІРКА ││ ├── Обрати безпечний базовий образ ││ ├── Мінімізувати встановлені пакети ││ ├── Не включати секрети ││ ├── Використовувати багатоетапні збірки ││ └── Сканувати на вразливості ││ ││ ЗБЕРІГАННЯ ││ ├── Використовувати приватний реєстр ││ ├── Підписувати образи ││ ├── Увімкнути сканування вразливостей ││ ├── Використовувати незмінні теги ││ └── Впровадити контроль доступу ││ ││ РОЗГОРТАННЯ ││ ├── Перевіряти підписи ││ ├── Застосовувати дозволені реєстри ││ ├── Блокувати вразливі образи ││ ├── Завантажувати за дайджестом ││ └── Використовувати image pull secrets ││ ││ ВИКОНАННЯ ││ ├── Безперервний моніторинг вразливостей ││ ├── Виявлення загроз часу виконання ││ ├── Файлова система тільки для читання ││ └── Виконання без root-привілеїв ││ │└─────────────────────────────────────────────────────────────┘Побудова безпечних образів
Розділ «Побудова безпечних образів»Вибір базового образу
Розділ «Вибір базового образу»┌─────────────────────────────────────────────────────────────┐│ ПОРІВНЯННЯ БАЗОВИХ ОБРАЗІВ │├─────────────────────────────────────────────────────────────┤│ ││ ТИП ОБРАЗУ РОЗМІР CVE ВИКОРИСТАННЯ ││ ─────────────────────────────────────────────────────── ││ ubuntu:22.04 ~77MB 100+ Розробка ││ debian:bookworm ~50MB 50+ Загального призн. ││ alpine:3.19 ~7MB 10-20 Легкі застосунки ││ distroless/static ~2MB 0-5 Статичні бінарники ││ scratch 0MB 0 Бінарники Go/Rust ││ ││ РЕКОМЕНДАЦІЇ: ││ ├── Продакшн: Distroless або Alpine ││ ├── Статичні бінарники: Scratch або distroless/static ││ ├── Потрібна оболонка: Alpine (менший) або Debian ││ └── Уникати: Повні ОС-образи (Ubuntu, CentOS) у ││ продакшні ││ ││ ПЕРЕВАГИ DISTROLESS: ││ • Без оболонки (складніше для зловмисників) ││ • Без менеджера пакетів ││ • Мінімальна поверхня атаки ││ • Менший розмір = швидше завантаження ││ │└─────────────────────────────────────────────────────────────┘Багатоетапні збірки
Розділ «Багатоетапні збірки»# Етап збірки — має всі інструменти збіркиFROM golang:1.21 AS builderWORKDIR /appCOPY go.mod go.sum ./RUN go mod downloadCOPY . .RUN CGO_ENABLED=0 go build -o /app/myapp
# Етап виконання — мінімальний образFROM gcr.io/distroless/static:nonrootCOPY --from=builder /app/myapp /myappUSER nonroot:nonrootENTRYPOINT ["/myapp"]┌─────────────────────────────────────────────────────────────┐│ ПЕРЕВАГИ БАГАТОЕТАПНОЇ ЗБІРКИ │├─────────────────────────────────────────────────────────────┤│ ││ БЕЗ БАГАТОЕТАПНОЇ ЗБІРКИ: ││ Кінцевий образ включає: ││ • Інструменти збірки (gcc, make тощо) ││ • Вихідний код ││ • Проміжні артефакти ││ • Тестові залежності ││ Результат: Великий образ із зайвою поверхнею атаки ││ ││ З БАГАТОЕТАПНОЮ ЗБІРКОЮ: ││ Кінцевий образ включає: ││ • Лише скомпільований бінарник ││ • Мінімальні залежності часу виконання ││ Результат: Малий образ із мінімальною поверхнею атаки ││ ││ ПОРІВНЯННЯ РОЗМІРІВ: ││ Застосунок Go з інструментами збірки: ~800MB ││ Застосунок Go багатоетапний: ~20MB ││ Застосунок Go на scratch: ~10MB ││ │└─────────────────────────────────────────────────────────────┘Найкращі практики Dockerfile
Розділ «Найкращі практики Dockerfile»┌─────────────────────────────────────────────────────────────┐│ ПРАКТИКИ БЕЗПЕКИ DOCKERFILE │├─────────────────────────────────────────────────────────────┤│ ││ РОБІТЬ: ││ ✓ Прив'язуйте базовий образ до дайджесту ││ FROM alpine@sha256:abc123... ││ ││ ✓ Запускайте як non-root користувач ││ USER nonroot:nonroot ││ ││ ✓ Використовуйте COPY замість ADD ││ COPY --chown=nonroot:nonroot app /app ││ ││ ✓ Мінімізуйте шари та очищуйте ││ RUN apt-get update && apt-get install -y pkg \ ││ && rm -rf /var/lib/apt/lists/* ││ ││ НЕ РОБІТЬ: ││ ✗ Включати секрети в образ ││ ENV API_KEY=secret123 # ПОГАНО ││ ││ ✗ Використовувати тег latest ││ FROM nginx:latest # ПОГАНО ││ ││ ✗ Запускати від root ││ USER root # ПОГАНО для продакшну ││ ││ ✗ Встановлювати непотрібні пакети ││ RUN apt-get install vim curl wget # Уникати ││ │└─────────────────────────────────────────────────────────────┘Сканування образів
Розділ «Сканування образів»Сканування вразливостей
Розділ «Сканування вразливостей»┌─────────────────────────────────────────────────────────────┐│ ІНСТРУМЕНТИ СКАНУВАННЯ ОБРАЗІВ │├─────────────────────────────────────────────────────────────┤│ ││ TRIVY (Aqua Security) ││ ├── Пакети ОС та залежності мов програмування ││ ├── Неправильні конфігурації ││ ├── Виявлення секретів ││ └── Генерація SBOM ││ ││ GRYPE (Anchore) ││ ├── Швидке сканування вразливостей ││ ├── Кілька джерел баз даних ││ └── Інтеграція з CI/CD ││ ││ CLAIR (CoreOS/Red Hat) ││ ├── Сканування на основі API ││ ├── Інтеграція з реєстром ││ └── Безперервний моніторинг ││ ││ КОЛИ СКАНУВАТИ: ││ • Під час збірки: Зупиняти збірки з критичними CVE ││ • У реєстрі: Безперервне сканування збережених образів ││ • Під час виконання: Сповіщення про нові CVE ││ │└─────────────────────────────────────────────────────────────┘Приклад Trivy
Розділ «Приклад Trivy»# Сканування образу на вразливостіtrivy image nginx:1.25
# Сканування з фільтром серйозностіtrivy image --severity HIGH,CRITICAL nginx:1.25
# Зупинити, якщо знайдено критичні CVE (для CI)trivy image --exit-code 1 --severity CRITICAL nginx:1.25
# Генерація SBOMtrivy image --format spdx-json -o sbom.json nginx:1.25
# Сканування Dockerfile на неправильні конфігураціїtrivy config DockerfileБезпека реєстру
Розділ «Безпека реєстру»Конфігурація приватного реєстру
Розділ «Конфігурація приватного реєстру»┌─────────────────────────────────────────────────────────────┐│ БЕЗПЕКА РЕЄСТРУ │├─────────────────────────────────────────────────────────────┤│ ││ КОНТРОЛЬ ДОСТУПУ ││ ├── Автентифікація потрібна для всіх операцій ││ ├── Доступ на основі ролей (push проти pull) ││ ├── Дозволи на рівні репозиторіїв ││ └── Інтеграція з ServiceAccount ││ ││ ЦІЛІСНІСТЬ ОБРАЗІВ ││ ├── Довіра до контенту (підписування) ││ ├── Незмінні теги ││ ├── Інтеграція сканування вразливостей ││ └── Процеси просування образів ││ ││ МЕРЕЖЕВА БЕЗПЕКА ││ ├── Обов'язкове шифрування TLS ││ ├── Приватні точки доступу (без публічного доступу) ││ ├── Ізоляція VPC/мережі ││ └── Журналювання аудиту ││ ││ ХМАРНІ РЕЄСТРИ: ││ • AWS: ECR (Elastic Container Registry) ││ • GCP: Artifact Registry ││ • Azure: Container Registry ││ • Самохостовані: Harbor, Quay ││ │└─────────────────────────────────────────────────────────────┘Image Pull Secrets
Розділ «Image Pull Secrets»# Створення секрету реєструapiVersion: v1kind: Secretmetadata: name: registry-credentials namespace: productiontype: kubernetes.io/dockerconfigjsondata: .dockerconfigjson: <base64-encoded-docker-config>---# Використання у подіapiVersion: v1kind: Podmetadata: name: private-appspec: imagePullSecrets: - name: registry-credentials containers: - name: app image: myregistry.io/myapp:v1.0# Або прив'язка до ServiceAccountapiVersion: v1kind: ServiceAccountmetadata: name: app-saimagePullSecrets:- name: registry-credentialsAdmission Control для образів
Розділ «Admission Control для образів»Приклад політики Kyverno
Розділ «Приклад політики Kyverno»apiVersion: kyverno.io/v1kind: ClusterPolicymetadata: name: require-trusted-registryspec: validationFailureAction: Enforce rules: - name: validate-registry match: any: - resources: kinds: - Pod validate: message: "Образи мають бути з довірених реєстрів" pattern: spec: containers: - image: "gcr.io/my-project/* | myregistry.io/*"Чи знали ви?
Розділ «Чи знали ви?»-
Середній образ контейнера має 300+ пакетів та 100+ відомих вразливостей. Мінімальні базові образи можуть зменшити це на 90%.
-
Distroless образи не мають оболонки — якщо зловмисник отримає виконання коду, він не зможе легко запускати команди. Це захист у глибину.
-
Distroless образи Google збираються з нуля щодня і включають лише те, що потрібно для запуску конкретного середовища виконання мови.
-
Шари образів кешуються та спільно використовуються. Вразливість у базовому шарі впливає на всі образи, побудовані на ньому.
Поширені помилки
Розділ «Поширені помилки»| Помилка | Чому це шкодить | Рішення |
|---|---|---|
| Використання :latest | Непередбачуваний, змінний | Прив’язати до дайджесту |
| Великі базові образи | Велика поверхня атаки | Використовувати мінімальні/distroless |
| Запуск від root | Вищі привілеї при експлуатації | runAsNonRoot: true |
| Без сканування | Невідомі вразливості | Сканувати в CI та реєстрі |
| Файлова система для запису | Можливе закріплення | readOnlyRootFilesystem |
Перевірка знань
Розділ «Перевірка знань»-
Чому distroless образи безпечніші за Alpine?
Відповідь
Distroless образи містять лише застосунок та його залежності часу виконання — без оболонки, без менеджера пакетів, без утиліт. Це означає, що навіть якщо зловмисник отримає виконання коду, він не зможе легко запускати команди або встановлювати інструменти. Alpine включає оболонку та менеджер пакетів, які можуть бути використані зловмисниками. -
Яка перевага багатоетапних збірок Docker?
Відповідь
Багатоетапні збірки розділяють середовище збірки та середовище виконання. Кінцевий образ містить лише скомпільований застосунок та залежності часу виконання, а не інструменти збірки, вихідний код або тестові залежності. Це значно зменшує розмір образу та поверхню атаки. -
Чому слід завантажувати образи за дайджестом, а не за тегом?
Відповідь
Теги є змінними — їх можна перезаписати для вказівки на інші образи. Дайджести є адресованими за контентом та незмінними. Завантаження за дайджестом гарантує, що ви завжди отримуєте точно той самий образ, запобігаючи атакам, де теги замінюються шкідливими версіями. -
Коли повинно відбуватися сканування образів?
Відповідь
У кількох точках: під час збірки (зупиняти збірки з критичними CVE), у реєстрі (безперервне сканування збережених образів) та під час виконання (сповіщення про нові CVE, що впливають на запущені контейнери). Це забезпечує захист у глибину протягом життєвого циклу образу. -
Чому readOnlyRootFilesystem запобігає?
Відповідь
Він запобігає запису контейнера до його кореневої файлової системи. Це блокує зловмисників від зміни бінарників, додавання інструментів або створення механізмів закріплення всередині контейнера. Застосунки, яким потрібне записуване сховище, використовують окремі томи (emptyDir, PVC).
Підсумок
Розділ «Підсумок»Безпека образів охоплює весь життєвий цикл:
| Фаза | Ключові контролі |
|---|---|
| Збірка | Мінімальна база, багатоетапна, без секретів, сканування |
| Зберігання | Приватний реєстр, підписування, незмінні теги |
| Розгортання | Перевірка підписів, дозволені реєстри, дайджест |
| Виконання | FS тільки для читання, non-root, безперервне сканування |
Ключові принципи:
- Менші образи = менша поверхня атаки
- Прив’язуйте до дайджесту, а не до тегу
- Скануйте на кожній фазі
- Підписуйте та верифікуйте образи
- Запускайте з мінімальними привілеями
Наступний модуль
Розділ «Наступний модуль»Модуль 5.2: Спостережуваність безпеки — Моніторинг та виявлення загроз безпеки у Kubernetes.