Trivy: проверка образов Docker на уязвимости, секреты и ошибки Dockerfile

0
7
Обложка статьи: Trivy: проверка образов Docker на уязвимости, секреты и ошибки Dockerfile

Образ контейнера состоит из системных пакетов и библиотек, и в старом образе уязвимостей обычно сотни. Проверять каждый образ вручную невозможно, поэтому нужен сканер в конвейере. Trivy проверяет образы на известные уязвимости, ищет секреты и разбирает Dockerfile на типовые ошибки. Ниже порядок работы и результаты проверки на тестовом образе.

Статья опирается на логику направления «Управление уязвимостями» из методики зрелости Группы Сбер (источник); это методика для крупных компаний, мы используем её как ориентир и пересказываем своими словами. Проверка выполнена с Trivy 0.75.0, запущенным в контейнере; тестовые образы и кэш после неё удалены.

Что должно получиться

Уровень Что это значит на практике
2. Гигиенический Образы проверяются при каждой сборке и по расписанию, уязвимости с доступным исправлением закрываются в согласованные сроки

Критерии сформулированы нами по мотивам методики, это ориентир, а не оценка соответствия.

Тестовый образ

Возьмём старый образ с двумя намеренными ошибками: запуск от root и секрет в переменной окружения (значение из документации AWS, не настоящее):

FROM python:3.9-slim
COPY app.py /app/app.py
ENV AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
CMD ["python", "/app/app.py"]

Запуск Trivy в контейнере с доступом к локальным образам:

docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
  -v trivy-cache:/root/.cache/ aquasec/trivy:0.75.0 image --scanners vuln ИМЯ_ОБРАЗА

Ключ -v trivy-cache:/root/.cache/ сохраняет базу уязвимостей между запусками: без него она скачивается заново каждый раз. Версию Trivy фиксируйте тегом, а не latest.

Результат проверки

Проверка Результат на тестовом образе
Уязвимости, все уровни 466 находок: 6 критических, 113 высоких, 188 средних, 156 низких, 3 без оценки. Основная часть в системных пакетах (Debian) и в pip и setuptools
Из них с готовым исправлением 6 критических и 69 высоких; остальные исправления пока нет
Порог CI: HIGH и CRITICAL с исправлением 72 в системных пакетах (66 высоких и 6 критических) и ещё 3 высоких в пакетах Python
Секреты в слоях образа Ничего не найдено: этот ключ из документации сканер секретов в слоях не отметил, а запись в ENV выявила проверка Dockerfile
Ошибки Dockerfile 3 находки: DS-0031 (критическая) секрет в ENV, DS-0002 (высокая) нет пользователя без прав root, DS-0026 (низкая) нет HEALTHCHECK
Секрет в файле (fs) Случайный токен формата GitHub PAT в файле leak.env найден как критический: файл и строка указаны
Новый образ (python:3.13-slim, пользователь без прав root) Только 4 высоких уязвимости с исправлением (вместо 75)

Вывод: самая эффективная мера — обновление базового образа. Сканер без обновления даёт длинный список, который никто не разберёт.

Пороги и скрипт для конвейера

Проверка по всем находкам останавливает сборки бесконечно. Практичный порог: HIGH и CRITICAL, для которых уже есть исправленная версия (--ignore-unfixed). Скрипт:

#!/usr/bin/env bash
# Проверка образа на известные уязвимости: падает при находках HIGH и CRITICAL, у которых уже есть исправление.
set -u
IMAGE="${1:?укажите образ, например myapp:1.0}"
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock -v trivy-cache:/root/.cache/ \
  aquasec/trivy:0.75.0 image --scanners vuln --severity HIGH,CRITICAL --ignore-unfixed --exit-code 1 "$IMAGE"
rc=$?
case $rc in
  0) echo "trivy: HIGH/CRITICAL с доступным исправлением не найдено" ;;
  1) echo "trivy: есть уязвимости с исправлением, сборку нужно остановить" ;;
  *) echo "trivy: ошибка запуска (код $rc)" ;;
esac
exit $rc

Коды возврата: 0 — порог не превышен, 1 — есть находки (задаётся ключом --exit-code 1), другие значения — ошибка запуска. Без --exit-code Trivy всегда возвращает 0, и сборка не остановится, даже если находки есть. В тесте скрипт вернул 1.

Секреты и ошибки Dockerfile

Для файлов проекта и Dockerfile используются другие режимы:

trivy fs --scanners secret ПУТЬ        # секреты в файлах
trivy config ПУТЬ                       # ошибки Dockerfile и конфигураций

Важная ловушка: trivy config . внутри контейнера без подключённого каталога ничего не проверяет (в отчёте прочерки), поэтому каталог проекта нужно смонтировать (-v $PWD:/src) и проверять /src. Секрет, найденный в репозитории, считайте скомпрометированным: смените его, а не просто удалите файл (секреты в git).

Порядок внедрения

  1. Составьте список образов, которые реально запущены, и их владельцев.
  2. Просканируйте все без порога и сохраните результат как исходное состояние.
  3. Обновите базовые образы до поддерживаемых версий: это убирает основную часть находок.
  4. Включите порог в CI: HIGH и CRITICAL с доступным исправлением.
  5. Запускайте проверку по расписанию и для уже развёрнутых образов: новые уязвимости появляются без изменения вашего кода.
  6. Исправьте Dockerfile: пользователь без прав root, без секретов в ENV, безопасный запуск контейнеров.
  7. Оформите исключения (файл .trivyignore с кодом уязвимости, причиной и сроком пересмотра) и сроки закрытия по общему процессу.

Диагностика

Симптом Причина и что делать
Сканирование долго качает базу Нет постоянного кэша. Подключите том для /root/.cache/
Сборка не останавливается при находках Не задан --exit-code 1. Добавьте ключ
Тысячи находок в старом образе Устаревший базовый образ. Обновите его, затем включайте порог
Находка есть, исправления нет Используйте --ignore-unfixed для порога, но следите за такими записями в отчёте и закрывайте после выхода обновления
trivy config показывает прочерки Проверяемый каталог не смонтирован в контейнер. Смонтируйте и укажите путь внутри контейнера
Секрет в ENV не найден сканером секретов В тесте запись ENV выявила проверка config (правило DS-0031), а не поиск секретов по слоям; запускайте обе проверки
Ложные срабатывания Добавьте запись в .trivyignore с причиной и сроком пересмотра

Ограничения

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

Где это в модели зрелости

Материал относится к направлению «Управление уязвимостями» (материалы направления, карта зрелости). Уровень 2 требует процесса с приоритетами и сроками: автоматическая проверка образов добавляет к сканированию серверов контейнерную часть инфраструктуры.

Как проверить

  1. Есть список запущенных образов с владельцами и датой последней проверки.
  2. Trivy запускается в конвейере, версия закреплена, сборка останавливается на пороге.
  3. Образ с известной критической уязвимостью, для которой есть исправление, не проходит сборку.
  4. Образы работают от пользователя без прав root, секретов в ENV и слоях нет.
  5. Исключения оформлены записью с причиной и сроком пересмотра.

Источники

  • Методика оценки уровня зрелости кибербезопасности компании, Группа Сбер: sberbank.ru.
  • Документация Trivy: trivy.dev; исходный код: github.com/aquasecurity/trivy.
  • OWASP Top 10: A06 Vulnerable and Outdated Components: owasp.org. Международная практика, не российский норматив.

Оставьте свой ответ