Learning Platform
Глоссарий Troubleshooting
Урок 16.04 · 24 мин
Средний
dockersecuritycvetrivy

Trivy и Docker Scout: сканеры CVE

Hadolint ловит проблемы статикой Dockerfile до сборки. Следующий уровень аудита — уязвимости в собранном образе: какие версии пакетов установлены, какие из них имеют известные CVE (Common Vulnerabilities and Exposures), какие критичные, какие можно проигнорировать.

Стандартные инструменты — Trivy (open-source от Aqua Security) и Docker Scout (встроен в Docker Desktop, проприетарный, частично open).


apt: пакетный менеджер Debian/Ubuntu

Что такое CVE и почему это важно

CVE — это публичная база уязвимостей. У каждой есть ID типа CVE-2024-21626 и оценка severity по CVSS (Common Vulnerability Scoring System, 0-10 баллов). Привет от runc CVE-2024-21626 — позволял из контейнера записать файл на хост через символическую ссылку. CVSS score 8.6, severity HIGH.

Базы CVE ведут разные организации: NVD (NIST), GitHub Advisory, Aqua, RedHat Security Data. Сканеры тянут эти базы и проверяют твой образ.

Каждый пакет (Python lib, apt package, npm module) имеет версию. Сканер собирает inventory (что в образе есть), сверяет с базой CVE (для каждой версии — какие уязвимости известны), выдаёт отчёт.

Как работает сканер CVE
docker imageСобранный образ Postgres / Python ETL / nginx — слои с пакетами
trivy inventoryTrivy сканирует слои: читает /var/lib/dpkg/status (apt), /etc/alpine-release (apk), site-packages (pip), node_modules (npm)
CVE databaseЛокально кэшированная база NVD + GitHub Advisory + Aqua. Обновляется при каждом запуске trivy (или раз в N часов)
отчёт по severityСписок CVE с уровнем критичности LOW/MEDIUM/HIGH/CRITICAL, ссылками, fixed version (если есть)

Trivy: установка и базовый запуск

Trivy — самый популярный open-source сканер. Установка:

# macOS
brew install trivy

# Linux
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sudo sh -s -- -b /usr/local/bin

# Docker
docker run --rm aquasec/trivy image python:3.13-slim

Сканирование образа:

trivy image python:3.13-slim

Первый запуск долгий (минута на скачивание CVE базы ~300 МБ). Последующие — секунды.

Сокращённый вывод:

python:3.13-slim (debian 12.5)
Total: 47 (LOW: 30, MEDIUM: 12, HIGH: 5, CRITICAL: 0)

┌────────────────┬────────────────┬──────────┬─────────────────────┬───────────────┬──────────────┐
│    Library     │ Vulnerability  │ Severity │  Installed Version  │ Fixed Version │     Title    │
├────────────────┼────────────────┼──────────┼─────────────────────┼───────────────┼──────────────┤
│ libssl3        │ CVE-2024-5535  │ HIGH     │ 3.0.13-1~deb12u1    │ 3.0.13-1~deb… │ openssl: ... │
│ libsystemd0    │ CVE-2023-7008  │ MEDIUM   │ 252.22-1~deb12u1    │ (no fix)      │ systemd: ... │
│ python3.13     │ CVE-2024-8088  │ MEDIUM   │ 3.13.0-1            │ 3.13.1        │ python: ...  │
└────────────────┴────────────────┴──────────┴─────────────────────┴───────────────┴──────────────┘

Что смотрим:

  • Total — сколько CVE найдено по уровням.
  • Library / Vulnerability / Severity — что и насколько критично.
  • Installed Version — какая версия у тебя в образе.
  • Fixed Version — какая версия пакета пофикшена. Если пусто (no fix) — патча нет.

Severity: LOW / MEDIUM / HIGH / CRITICAL

Эта градация — по CVSS score:

  • LOW (CVSS 0.1-3.9). Минорные проблемы, обычно требуют сложных условий для эксплуатации.
  • MEDIUM (4.0-6.9). Заметные. Можно копить, патчить плановыми обновлениями.
  • HIGH (7.0-8.9). Серьёзные. Должны патчиться в течение спринта.
  • CRITICAL (9.0-10.0). RCE, privilege escalation, data leak. Патчатся сегодня.

Для production-образа в DE-команде обычно политика:

  • CRITICAL — fail сборки, не деплоим.
  • HIGH — fail сборки, но с возможностью override (если нет fix или нет реальной exposure).
  • MEDIUM / LOW — отчёт, не блокирует.

В Trivy это настраивается через --severity:

trivy image --severity CRITICAL,HIGH python:3.13-slim

Покажет только HIGH+. В CI:

trivy image --severity CRITICAL --exit-code 1 my-image:latest
# Exit 1 если есть CRITICAL — CI упадёт

Что Trivy ещё сканирует

Помимо образов, Trivy сканирует:

  • Файловые системы. trivy fs . — сканирует текущую директорию (находит уязвимые зависимости в requirements.txt, package.json, Cargo.toml, и т.д.).
  • Git-репозитории. trivy repo https://github.com/user/repo.
  • IaC (Infrastructure as Code). trivy config terraform/ — находит небезопасные настройки в Terraform, Kubernetes manifest’ах, Dockerfile’ах.
  • Kubernetes-кластеры. trivy k8s cluster.
  • Секреты. Опционально: ищет утечки API-ключей в файлах.
trivy fs --scanners vuln,secret,misconfig .

Это полное сканирование: уязвимости + секреты + misconfig.


Игнорирование CVE

Иногда CVE есть, но не критична для твоего use case. Например, CVE-2024-X в libfoo, но libfoo используется только в Build-стадии multi-stage, в финальный образ не попадает.

Игнорирование через .trivyignore:

CVE-2024-X
CVE-2024-Y
trivy image --ignorefile .trivyignore my-image

Эти CVE не показываются и не фейлят CI.

Важно: каждый ignore должен быть задокументирован. Обычно в .trivyignore пишут с комментарием:

# CVE-2024-X is only in build stage, not in runtime image
# CVE-2024-Y has no fix, mitigated by removing affected feature
CVE-2024-X
CVE-2024-Y

Docker Scout

Docker Desktop с 2023 года имеет встроенный сканер — docker scout. Аналог trivy, но проприетарный и интегрирован в Docker.

docker scout cves python:3.13-slim

Вывод похож на trivy. Преимущества: интеграция с Docker Hub (можно посмотреть scout-отчёт прямо на странице образа), recommendations (предлагает base image с меньшим числом CVE).

docker scout recommendations python:3.13-slim:

Recommended base images:
  python:3.13-slim -> 47 CVEs
  python:3.13-alpine -> 12 CVEs   ← меньше CVE, но musl ломает pandas
  cgr.dev/chainguard/python:latest -> 0 CVEs   ← distroless с обновлёнными пакетами

Минус Docker Scout: проприетарный, требует логин в Docker Hub для полных функций, в open-source CI неудобен. На дев-машине удобен, в production-pipeline — Trivy чаще.


SBOM (Software Bill of Materials)

SBOM — это «список ингредиентов» образа: все пакеты, их версии, лицензии, происхождение. Это становится требованием регуляторов (EU Cyber Resilience Act, US Executive Order 14028).

Trivy умеет генерировать SBOM:

trivy image --format spdx-json --output sbom.json python:3.13-slim

SBOM в формате SPDX (Linux Foundation standard) или CycloneDX. Содержит:

  • Список пакетов с версиями.
  • Лицензии (BSD, GPL, MIT, …).
  • Зависимости между пакетами.
  • Хеши слоёв.

Это полезно для аудита (что у нас в production?) и для compliance (доказать customer’у, что мы знаем, что внутри).

docker buildx тоже умеет генерировать SBOM в момент сборки:

docker buildx build --sbom=true -t my-image .

Как фиксить CVE

Допустим, trivy показал HIGH CVE в libssl3, fixed version 3.0.13-1~deb12u2. Что делать.

Шаг 1: Пересобрать с обновлённой базой. В Dockerfile:

FROM python:3.13-slim

RUN apt-get update && apt-get upgrade -y && rm -rf /var/lib/apt/lists/*

apt-get upgrade -y подтянет последние security-патчи. Пересобрали — trivy image — HIGH’ов меньше.

Шаг 2: Обновить base image. Если в базе python:3.13-slim 2 месяца назад зашитые пакеты — docker pull python:3.13-slim подтянет свежий образ с патчами.

docker pull python:3.13-slim   # обновить base
docker build --no-cache -t my-image .  # пересобрать с нуля
trivy image my-image           # перепроверить

Шаг 3: Сменить base. Если debian-base тянет много CVE — попробовать distroless или chainguard:

FROM cgr.dev/chainguard/python:latest-dev as builder
# ...

FROM cgr.dev/chainguard/python:latest
COPY --from=builder /app /app
ENTRYPOINT ["python", "/app/main.py"]

Chainguard publishes images с минимумом CVE — они сами поддерживают forks основных пакетов с актуальными патчами.

Шаг 4: Если нет fix — mitigation. Когда CVE без fixed version, выбор:

  • Признать риск, задокументировать в .trivyignore.
  • Удалить уязвимый пакет (если не используется).
  • Использовать config-level mitigation (отключить уязвимую фичу).
Цикл «scan -> fix -> re-scan»
docker buildСобрали образ из текущего Dockerfile
trivy imageСканируем — получаем список CVE
есть HIGH/CRITICAL?Проверяем severity. Если есть критичное — нельзя деплоить
да
docker pull base + apt upgradeПодтягиваем последний base image и применяем security-патчи в Dockerfile
re-build + re-scanЦикл повторяется до тех пор пока нет HIGH/CRITICAL
чисто
deployТолько когда сканер чистый — деплоим в production

Интеграция в CI

GitHub Actions для PR:

- name: Build image
  run: docker build -t my-image:${{ github.sha }} .

- name: Scan with Trivy
  uses: aquasecurity/[email protected]
  with:
    image-ref: my-image:${{ github.sha }}
    severity: CRITICAL,HIGH
    exit-code: 1
    format: sarif
    output: trivy-results.sarif

- name: Upload to GitHub Security tab
  uses: github/codeql-action/upload-sarif@v3
  with:
    sarif_file: trivy-results.sarif

PR с CRITICAL CVE не пройдёт. SARIF-отчёт публикуется в Security tab репозитория — все CVE видны в UI.


Pattern: nightly re-scan

CVE появляются постоянно. Образ, который сегодня чистый, через неделю может быть с CVE — потому что вышла новая CVE на уже установленный пакет.

Pattern: nightly job в CI пересканирует прод-образы:

on:
  schedule:
    - cron: '0 4 * * *'  # каждый день в 4:00 UTC

jobs:
  rescan:
    steps:
      - run: trivy image --severity CRITICAL prod-image:latest
      # Если есть CRITICAL — slack alert + автоматический PR на обновление base

Это закрывает «дрейф безопасности» — между релизами образ ухудшается, и nightly scan ловит это.


Попробуй сам

  1. Поставь trivy локально (brew install trivy или docker).
  2. Сканируй типичные базовые образы:
    trivy image python:3.13-slim
    trivy image python:3.13-alpine
    trivy image postgres:16
    Сравни количество CVE по severity.
  3. Сканируй с фильтром: trivy image --severity CRITICAL,HIGH postgres:16. Сколько HIGH?
  4. Собери Dockerfile с apt install curl без apt upgrade. Сканируй — посмотри CVE в libcurl. Добавь apt upgrade -y, пересобери, сканируй ещё раз. Должно стать меньше.
  5. Сгенерируй SBOM: trivy image --format spdx-json --output sbom.json python:3.13-slim. Открой файл — увидишь список всех пакетов.
  6. На macOS: попробуй docker scout cves python:3.13-slim и docker scout recommendations python:3.13-slim.

Проверка знанийKnowledge check
Образ python:3.13-slim показал 5 HIGH CVE в trivy: libssl3 (есть fix), libpython3.13 (есть fix), libsystemd (no fix). Какой будет твой план действий?
ОтветAnswer
Для CVE с fixed version (libssl3, libpython3.13): 1) Обновить base image: docker pull python:3.13-slim. Возможно, последняя версия python:3.13-slim уже содержит фиксы. 2) Добавить в Dockerfile RUN apt-get update && apt-get upgrade -y && rm -rf /var/lib/apt/lists/* — это применит security-патчи поверх base image. 3) Пересобрать: docker build --no-cache -t my-image . и снова trivy image my-image — проверить, что HIGH'и закрылись. Для CVE без fixed version (libsystemd "no fix"): 1) Оценить exposure: используется ли libsystemd в нашем приложении? Для Python ETL чаще всего нет. Если нет — это transitive dependency, не эксплуатируема. 2) Mitigation: можно ли удалить пакет? Если нет — задокументировать осознанный риск в .trivyignore с комментарием почему игнорируем. 3) Мониторить: подписаться на CVE-tracker, как только появится фикс — патчить. Если HIGH без фикса остаётся — нужен management decision. Production-критичные системы могут требовать смены base (например, с debian-slim на chainguard, где этот пакет уже не используется или фикснут). И главное правило: одиноразовый scan недостаточен. Nightly re-scan production-образов ловит CVE, которые появились после релиза, на уже установленных пакетах.

Проверьте понимание

Результат: 0 из 0
Концептуальный
Вопрос 1 из 4. Какую градацию severity использует Trivy и что значит CRITICAL по CVSS score?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 5