Сканирование Docker-образов на уязвимости (Trivy/Snyk/Grype)

Уязвимость в базовом слое образа уходит в рабочую среду вместе с релизом и всплывает уже под нагрузкой. Мы настраиваем сканирование Docker образов под ключ: проверка на каждом этапе сборки, понятные отчёты, регламент обновления. Критичные находки останавливают выпуск до исправления, а окно уязвимости сокращается с недель до суток.
Часто задаваемые вопросы

Что ломается без сканирования Docker образов

Образ собирается из базового слоя, который обновляют раз в полгода-год. За это время в нём накапливаются устаревшие зависимости: библиотеки с известными уязвимостями остаются внутри, потому что приложение от них не отказалось, а базовый слой никто не пересобирал. Сканирование Docker образов начинается именно с этого слоя — там больше всего находок высокой критичности, и они одинаково затрагивают все сервисы, собранные на общей основе.

Вторая точка деградации — сама сборка. Менеджер пакетов в Dockerfile тянет версии без фиксации, в финальный образ попадают пакеты из состава для сборки и утилиты, которые в работе контейнера не участвуют. Каждый лишний пакет — дополнительная поверхность атаки, но сборка об этом молчит: успешно собранный образ выглядит рабочим.

Риск эксплуатации появляется там, где уязвимая зависимость доступна извне. Контейнер по умолчанию стартует с правами root, библиотека разбирает внешние данные — и одна непроверенная зависимость становится точкой входа, невидимой ни в логах приложения, ни на мониторинге.

Дальше сценарий один: уязвимость живёт в проде месяцами и всплывает только на инциденте после выкладки. Закрытие требует пересборки всех сервисов на общем базовом слое, повторной проверки образов в реестре, отката релиза и ротации секретов. Разбираем, как это закрывается сканированием на каждом этапе.

Что даёт раннее выявление уязвимостей в сборке

Уязвимость в базовом образе или транзитивной зависимости всплывает не тогда, когда её начали эксплуатировать, а когда кто-то спустя месяцы смотрит на старый тег. Раннее выявление уязвимостей переносит проверку на каждый шаг сборки и одновременно фиксирует состав образа: какая версия пакета попала в какой слой и каким изменением. Прослеживаемость зависимостей превращает «где-то внутри» в конкретную строку перечня компонентов — и закрывать её можно точечно, а не пересобирать всё вслепую.

Эффект измерим. Скорость закрытия дефектов меняется с недель на часы: критичное обновление попадает в сборку в тот же день, когда появляется в базе уязвимостей, потому что проверка встроена в конвейер, а не живёт отдельным отчётом. Доля откатов релиза из-за всплывшей зависимости уходит к нулю — несовместимое обновление отсекается до выкладки. Объём ручного разбора сокращается, когда инженер видит не весь список, а только новые находки относительно базовой линии.

Так уходит целый класс отказов: боевая среда с уязвимым базовым образом, который «собирались обновить», и инциденты из-за заброшенного пакета, о котором в проекте уже никто не помнил. Сокращение простоя здесь — следствие, а не лозунг: релиз не разбирают вручную, откат идёт на ранее проверенный образ.

Технически это набор политик: порог критичности, на котором сборка останавливается; список исключений с обязательным обоснованием и сроком пересмотра; сравнение с базовой линией, чтобы старые находки не тонули в шуме ложных срабатываний. Мы запускаем Trivy в конвейере, складываем результат в машиночитаемый отчёт и привязываем его к конкретному артефакту — поэтому вопрос «в каком релизе пришла эта зависимость» закрывается запросом, а не раскопками.

Режимы проверки: ручной прогон или контроль в сборке

Режимы отличаются не сканером, а моментом, когда вердикт становится обязательным. Чем раньше срабатывает проверка, тем дешевле правка — но тем меньше контекст: локально нет политики релиза, а в конвейере нет данных о том, как образ поведёт себя в рабочей среде. Поэтому на практике режимы не заменяют, а дополняют друг друга.

Вариант Когда подходит Ограничения
Разовая ручная проверка Разбор инцидента, аудит уже собранного образа, разведка перед внедрением Закрывает один снимок состояния; результат устаревает вместе с обновлением баз уязвимостей
Контроль на машине разработчика Быстрая обратная связь до отправки в репозиторий Нет единой политики, версии баз у всех разные, проверку легко отключить
Проверка в сборочном конвейере Основной барьер: сборка падает на критичных находках до публикации Нужны настроенное обновление баз и разумный порог, иначе сборки тормозят и их начинают обходить
Контроль на входе в реестр Страховка для сторонних образов и сборок в обход конвейера Блокирует публикацию, но не сообщает автору, что именно исправлять
Периодический обход Ловит уязвимости, раскрытые уже после релиза, и заброшенные теги Находки приходят задним числом — нужен владелец, который закроет их пересборкой

Рабочая схема — проверка в конвейере как обязательный барьер плюс регулярный обход реестра по расписанию, одним и тем же сканером, чтобы вердикты совпадали. Порог по критичности и списки исключений с датой пересмотра держим рядом с описанием сборки: без даты исключение быстро превращается в вечную слепую зону.

Этапы внедрения контроля уязвимостей в команде

Внедрение контроля уязвимостей — это не установка сканера, а изменение процесса сборки: проверка должна стоять там, где исправление занимает минуты, а не дни. Идём по шагам — от разбора текущего реестра до передачи регламента команде.

  1. Аудит текущей сборки и реестра. Разбираем базовые образы, частоту пересборки, число тегов и возраст слоёв. Уже здесь видно, откуда берётся основная масса находок.

  2. Схема контроля. Определяем точки проверки: при сборке, при отправке в реестр, перед выкаткой. Конкретный сканер (Trivy, Grype) здесь вторичен — важнее, где стоит проверка и какой уровень критичности блокирует выпуск, а какой даёт только предупреждение.

  3. Настройка порогов и исключений. Порог задаём по критичности, а не по общему числу находок. У каждого исключения — владелец и срок пересмотра, иначе список исключений со временем перекрывает саму проверку.

  4. Проверка на стенде. Прогоняем на копии реестра, сверяем результат с ручным разбором нескольких образов, замеряем долю ложных срабатываний до попадания в рабочий контур.

  5. Проверка на реальных сборках. Несколько релизов идут в режиме предупреждения: отчёты команда получает, выпуск не блокируется. Так настраиваются правила, а не тормозится работа.

  6. Передача регламента и обучение. Отдаём документ: что делать при находке, как её исправить, как оформить исключение, кто отвечает за базовые образы.

Дальше пороги и исключения пересматриваются по расписанию — заброшенные базовые образы и устаревшие исключения дают больше всего шума в отчётах.

Политики доступа, отчёты и регламент обновления

Сканирование Docker образов приносит пользу не отчётом, а набором артефактов, которые живут в репозитории и работают без нашего участия. Ниже — что остаётся у команды: конфигурации, схема запуска, правила реагирования и документы для разработчиков.

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

  • Конфигурации проверок — файлы политик с порогами: какой уровень критичности останавливает сборку, какой только фиксируется в отчёте.
  • Схема контроля — где запускается проверка: перед слиянием, при сборке образа, ночью по расписанию. И как ведёт себя сборка, если базы уязвимостей недоступны.
  • Политика реагирования — сроки устранения по уровням критичности, кто решает выпускать ли образ с открытой находкой, как эскалируется просрочка.
  • Перечень исключений — запись на каждое отклонение: обоснование, ответственный, дата пересмотра. Находка без исправления живёт со сроком, а не забывается.
  • Регламент обновления базового слоя — как часто образ пересобирается на свежей базе, как проверяется совместимость и как выглядит откат.
  • Отчёты по сборкам — что видно по каждой сборке: новый пакет, автор изменения, история по тегам, без запуска сканера вручную.
  • Инструкции для команды — памятки: что делать при срабатывании, как оформить исключение, куда смотреть при спорной находке.

Кейс: окно уязвимости сократили с недель до суток

Заказчик — продуктовая команда с ежедневными релизами: 25–30 сборок в неделю, и почти все уходили в прод без проверки. Критичная уязвимость в базовом образе жила в проде от недели до двух, а узнавали о ней из внешнего уведомления, а не из своего контура. Разбор инцидента каждый раз начинался с вопроса «какой образ вообще сейчас в проде».

Мы встроили проверку в конвейер сборки: Trivy просматривает слои образа и манифесты зависимостей на этапе, где выкатку ещё можно остановить. Правило блокировки настроили не по общему числу находок, а по уровням — сборка падает только на критичных и высоких с подтверждённым путём эксплуатации, остальное уходит в список задач с датой разбора.

Метрики до и после: окно уязвимости сократилось с 11–14 дней до 18–24 часов, потому что обновление базового образа автоматически пересобирает зависимые сервисы. Доля ложных срабатываний упала с 40% до 8% — за счёт файла исключений, который мы ведём вместе с командой, а не «настроили однажды и забыли». Ручной разбор сократился с 6 часов в неделю до 40 минут: инженер смотрит только то, что действительно требует решения. Разбор инцидентов теперь идёт по списку компонентов с версиями из отчёта, а не по логам вслепую.

Что делать, если реестр образов уже развёрнут?

Если реестр уже развёрнут, переносить и пересобирать его не нужно: сканер подключается к нему как к обычному источнику и читает манифесты и слои по тому же программному интерфейсу, которым пользуется выкладка. Реестр остаётся рабочим, а проверка становится ещё одним шагом сборочного конвейера — после сборки образа и до публикации тега.

Начинаем с режима отчёта: сканер разбирает образы молча и складывает результаты в отдельное хранилище, ничего не блокируя. За несколько выкладок набирается статистика по настоящим зависимостям — видно, какие уязвимости приходят из базового образа, какие тянет приложение, а какие уже закрыты обновлением. По этой картине настраиваем уровни серьёзности, при которых сборка останавливается.

Миграция без остановки выкладок строится на параллельном проходе: старые теги остаются доступными, новые проходят проверку, а блокировка включается сначала только для критичных находок в наших слоях. Базовые образы, где исправлений ещё нет, на первом этапе уходят в список исключений с датой пересмотра — выкладки не встают, но долг не прячется.

Совместимость с текущей сборкой обеспечивается тем, что сканирование не меняет ни инструмент сборки, ни структуру слоёв: достаточно добавить шаг и выдать сканеру доступ к реестру на чтение. Кэш слоёв продолжает работать, время сборки растёт на десятки секунд, а на неизменившихся слоях почти не растёт. Политику проверок держим в файле рядом с описанием сборки и версионируем — откат делается одним изменением.

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

Ложные срабатывания и медленная сборка: частые сомнения

Сканер, который на первом запуске отдаёт сотни строк, перестают читать через неделю — не потому, что он плох, а потому что в отчёте нет приоритета. Сигнал появляется после трёх настроек: фильтр по критичности и наличию исправленной версии, отсев недостижимого кода и короткий список исключений с обоснованием и датой пересмотра. После этого остаются единицы записей, и каждая требует решения.

Время сборки закрывается кэшированием: результат по неизменённому слою переиспользуется, база уязвимостей обновляется отдельной задачей. Проверка вешается на сборку образа, а не на каждый коммит, и останавливает конвейер только на согласованном уровне критичности.

Уязвимость в базовом слое — вопрос границ ответственности: дистрибутив внутри базового образа обновляет владелец шаблона, прикладные зависимости — команда сервиса. Регламент фиксирует, кто и в какой срок закрывает каждую категорию, иначе находка висит между командами.

Сканер выдаёт сотни уязвимостей, опасны единицы — как это развести?

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

Проверка замедлит сборку и выкатку — насколько?

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

Обсудим задачу: что уточняем на первом созвоне

Первый созвон — это не презентация, а сбор вводных: мы задаём вопросы, чтобы оценка объёма и план внедрения опирались на вашу инфраструктуру, а не на средние цифры. Полный доступ к боевому контуру не нужен — достаточно схемы сборки, реестра и текущих правил.

  • Как устроен сборочный конвейер: где собираются образы, сколько сервисов, кто владеет базовыми слоями.
  • Что уже в реестре: сколько тегов на сервис, как глубоко хранится история, есть ли политика очистки — от этого зависит время первого полного сканирования.
  • Какие сканеры применяются сейчас (Trivy, Grype, Snyk) и на каком этапе — локально, на сервере сборки или уже в кластере.
  • Что именно должно останавливать сборку: только критические уровни, наличие исправленной версии, уязвимости в исполняемых слоях.
  • Требования к отчётам и доступам: формат выгрузки (SBOM, SARIF), куда уходят результаты, доступ на чтение к реестру без права записи.
  • Кто в вашей команде отвечает за обновление базовых образов — без владельца процесса правило блокировки быстро отключают.

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

Наши компетенции:

Последние работы

  • Разработка сайта компании B2B ADVANCE
    Разработка сайта компании B2B ADVANCE
    1542
  • Разработка веб-приложения для компании FEEDME
    Разработка веб-приложения для компании FEEDME
    1394
  • Разработка веб-сайта для компании БЕЛФИНГРУПП
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    1081
  • Разработка интернет магазина для компании FURNORO
    Разработка интернет магазина для компании FURNORO
    1369
  • Разработка логотипа компании B2B Advance
    Разработка логотипа компании B2B Advance
    816
  • Разработка веб-приложения для компании Enviok
    Разработка веб-приложения для компании Enviok
    1142