Сканирование образов через Grype: где теряются уязвимости
Анализ образа идёт по слоям, и базовый слой почти всегда зафиксирован на момент сборки. Syft снимает инвентарь — перечень пакетов операционной системы и зависимостей приложения с их версиями. По этому перечню Grype сопоставляет версии с базами уязвимостей и отдаёт находки с оценкой критичности и указанием слоя, из которого они приехали.
Разрыв возникает между сборкой и пересборкой. Приложение обновляется каждый релиз, а системные библиотеки в базовом слое остаются неизменными месяцами. Уязвимость уже опубликована, база обновлена, но в образе живёт прежняя версия пакета — и проверка контейнеров при выкладке её не показывает, если запускается по факту готового образа, а не на этапе сборки.
Вторая точка потерь — фильтры. Отсечение по уровню критичности или отключение проверки устаревшего базового слоя убирает шум, но одновременно прячет самый частый класс находок: высокое влияние при низкой формальной оценке.
Третья — формат результата. Плоский список удобен для чтения и бесполезен для управления: не видно, повторяется ли находка из релиза в релиз и закрылась ли она после обновления. Инвентарь состава привязывает каждую запись к конкретному пакету и слою, поэтому понятно, что именно нужно обновить.
Разбираем этот путь по шагам: снятие инвентаря, настройка порогов, автоматическая пересборка базовых слоёв — и показываем, где именно уязвимости в образах теряются.
Что даёт регулярное сканирование Docker-образов
Автоматическое сканирование на этапе сборки превращает безопасность контейнеров из ручной проверки перед релизом в штатный шаг конвейера. Инструмент разбирает слои образа, сверяет пакеты и их версии с базами уязвимостей и отдаёт находки до того, как образ попал в реестр. Ниже — три эффекта, которые видны уже через два-три релиза.
Окно уязвимости сжимается до одного цикла сборки
Пока образ лежит в реестре и не пересобирается, уязвимость в нём живёт месяцами: о находке узнают на очередном аудите или после разбора инцидента. При сканировании при сборке и по расписанию срок от публикации уязвимости до её закрытия в рабочем окружении падает с недель до одного-двух циклов — обычно в пределах суток.
Ручная приёмка релиза уходит
Политика по уровням критичности («критичные — стоп сборки, высокие — предупреждение и запись в отчёт») даёт формальный вердикт вместо просмотра списка глазами. Релиз либо проходит, либо падает с указанием конкретного пакета и слоя — приёмка перестаёт быть узким местом и не зависит от того, кто сегодня на дежурстве.
Единый список находок по всем реестрам
Сканирование всех репозиториев одной конфигурацией даёт единый формат отчёта и единый порог. Видно, пришла уязвимость из базового слоя или из зависимостей приложения: понятно, кто правит — команда сопровождения базовых образов или разработчик. Контроль базовых слоёв становится регулярным, а не разовым.
Мы настраиваем Grype вместе с формированием перечня компонентов образа — по нему находки можно перепроверять и сравнивать между релизами.
Подходы к сканированию образов: сравнение вариантов
Один режим проверки почти всегда оставляет дыру. Проверка на сборке ничего не знает о том, что уже неделями работает в кластере, а регулярный обход развёрнутых образов не остановит выкладку уязвимой сборки. Причина в асимметрии: образ собирается один раз, а база известных уязвимостей обновляется ежедневно — вчерашний чистый образ сегодня содержит проблемы.
Ниже — четыре режима, между которыми реально выбирают, и границы применимости каждого.
| Режим сканирования | Когда подходит | Ограничения |
|---|---|---|
| На этапе сборки, блокирующий | Новые сервисы и активная разработка; нужно не пустить уязвимость дальше конвейера | Ловит только то, что известно на момент сборки; ложные срабатывания тормозят релизы, если порог строгий |
| Перед выкладкой, по манифесту | Регулярные релизы в несколько сред; нужен контроль на входе в продакшн | Требует доступа к реестру и прав на остановку выкладки; не покрывает образы, выложенные в обход конвейера |
| Периодический обход развёрнутых образов | Уже работающий контур, долгоживущие сервисы, требования комплаенса | Не предотвращает — только фиксирует; нужен разбор находок и план обновления |
| Проверка по сохранённому перечню компонентов | Закрытые контуры без доступа к образам; разбор инцидента задним числом | Перечень нужно формировать заранее и хранить вместе с релизом |
На практике режимы не конкурируют, а дополняют друг друга: блокирующая проверка на сборке отсекает явный брак, периодическая — поднимает то, что стало уязвимым после выкладки, а сохранённый перечень компонентов позволяет за минуты ответить на вопрос «где ещё встречается эта библиотека», когда по ней выходит критичное уведомление. Grype и Syft работают с одним и тем же перечнем компонентов, поэтому все режимы опираются на единый источник правды, а не на три несогласованных отчёта.
Внедрение Grype в конвейер сборки образов: этапы работ
Сканирование образов встраиваем в конвейер сборки, а не запускаем отдельным заданием по расписанию: проверка происходит до публикации образа в реестр, иначе дефект уже в продакшене. Syft собирает состав пакетов по слоям, Grype сопоставляет его с базами уязвимостей, а сборка получает код возврата, по которому решается — пропускать образ дальше или останавливать. Порядок работ выстроен так, чтобы к моменту включения блокировок команда понимала каждое срабатывание.
- Инвентаризация образов. Собираем перечень сервисов, базовых слоёв и внешних зависимостей — без него пороги блокировок ставятся наугад и останавливают сборку на первом же изменении.
- Схема интеграции. Определяем точку вызова в конвейере (после сборки, до публикации), способ хранения отчётов и локального зеркала баз уязвимостей, поведение на узлах без доступа во внешнюю сеть.
- Настройка Grype. Задаём набор источников уязвимостей, форматы вывода — читаемый для логов, машиночитаемый для разбора, — и исключения для заведомо неприменимых срабатываний со сроком пересмотра.
- Пороги блокировок и политики безопасности. Уровни критичности разделяем: сборка падает на уязвимостях с доступным исправлением и высоким риском, остальное уходит в отчёт и в очередь на устранение. Пороги калибруем по реальному составу образов, чтобы не получить стену ложных остановок.
- Проверка на боевых сборках. Прогоняем на действующих сервисах: замеряем время добавленного шага, долю срабатываний и стоимость поддержки баз в закрытом контуре.
- Передача регламентов. Отдаём описание политик, инструкцию по разбору срабатываний и порядок действий при остановленной сборке — команда меняет пороги и исключения самостоятельно.
После передачи ведём сопровождение: обновление баз, пересмотр исключений и правка порогов по мере изменения состава сервисов.
Политики сканирования, регламенты и пороги блокировок
Сканирование без регламента быстро превращается в фон: отчёты формируются, находки копятся, а решения по ним принимаются каждый раз заново. К моменту включения Grype в конвейер команда получает пакет артефактов, где у каждого правила есть владелец, срок и понятный способ оспорить — иначе первая же блокировка сборки учит инженеров обходить проверку, а не исправлять причину.
- Конфигурация сканирования: файл политики с порогами по уровням критичности, перечнем проверяемых слоёв и режимом работы для каждой ветки — где достаточно предупреждения, а где сборка останавливается.
- Матрица приоритетов: какие находки закрываются в ближайшем релизе, какие уходят в плановый порядок, а какие допустимо принять как известный риск.
- Список исключений уязвимостей: каждая запись с обоснованием, ответственным и датой пересмотра — исключение перестаёт быть вечным и возвращается в работу автоматически.
- Регламент реагирования: кто получает уведомление, за какое время подтверждает находку, как выпускается исправленный образ и при каких условиях блокировка снимается.
- Документация по сканированию: где хранится состав образа, снятый Syft, как воспроизвести проверку локально теми же правилами и как читать отчёт при разборе инцидента.
- Отчётность по образам: сводка по репозиториям и тегам — доля образов без критичных находок, динамика по неделям, перечень просроченных исключений.
- Порядок ревизии: плановый пересмотр порогов и исключений, а также внеплановый — после смены базового образа или появления исправления у поставщика компонента.
- Роли и точка эскалации: кто владеет политикой и кто принимает решение, когда находка конфликтует со сроком выпуска.
Такой пакет остаётся у команды, а не у подрядчика: проверку можно перезапустить, пороги — обосновать, а любое исключение — снять одной правкой конфигурации.
Кейс: сократили долю непроверенных образов в разы
До работ образы собирались вручную, а сканирование запускалось от случая к случаю — обычно перед крупным релизом. Реестр при этом рос быстрее, чем кто-либо успевал смотреть его содержимое, и находки всплывали уже в эксплуатации: по факту инцидента или обращения.
Что было до внедрения
Замер базовой картины дал конкретные цифры: под регулярной проверкой находилась примерно десятая часть образов, остальные жили в реестре без контроля. Время реакции на новую уязвимость в используемом пакете измерялось неделями, а определить, в каком именно образе сидит проблемная библиотека, можно было только ручным разбором.
Что изменили
В конвейер сборки добавили два шага. Syft разбирает образ на перечень пакетов с версиями, Grype сверяет этот перечень с базами уязвимостей и отдаёт находки с уровнем критичности. Отчёт стал обязательным артефактом: без него образ не попадает в реестр, а критичные находки блокируют продвижение в среду эксплуатации. Отдельно прогнали накопившийся реестр — старые находки разобрали по приоритету, а не «когда-нибудь».
Что стало
Доля непроверенных образов сократилась до единиц процентов — вне контроля остаются только локальные сборки, которые не покидают машины разработчиков. Время реакции на критичную находку сжалось до часов: она приходит вместе с результатом сборки, а не после инцидента в эксплуатации. Метрики безопасности снимаются автоматически, и рост реестра больше не означает рост слепой зоны.
Чем сканирование слоёв отличается от проверки файловой системы?
Образ — это не монолитный слепок, а стек слоёв: каждый добавляет или перекрывает файлы предыдущего. Сканирование слоёв читает манифест и собранный перечень пакетов, поэтому видит, какой менеджер пакетов поставил компонент, в каком слое он появился и что притянуло его транзитивной зависимостью. Ответ приходит с происхождением, а не только с номером версии.
Проверка файловой системы контейнера работает с тем, что реально смонтировано и доступно процессу: распакованные бинарники, библиотеки, файлы, положенные копированием в обход менеджера пакетов. Зато родословной она не знает — по находке не видно, из какого слоя она пришла и обновлялась ли позже.
Разница подходов видна на двух классах ошибок. Проверка по слоям покажет компонент из нижнего слоя, даже если верхний его заменил или удалил, — в отчёте всплывает уже несуществующая версия. Файловая система маркеры удаления не учитывает и описывает финальное состояние, но пропускает всё, что не дожило до рабочего контейнера.
Поэтому охват собирают из двух источников: перечень пакетов формируется по слоям на этапе сборки, а готовая файловая система проверяется после — как страховка от ручных копирований и распаковок. Grype сопоставляет находки с базой уязвимостей, но полнота отчёта зависит от того, чем собран перечень и по какому источнику — образ целиком, директория или отдельный слой. Мы настраиваем оба режима и разводим находки, чтобы отчёт не тонул в ложных срабатываниях.
Технические ограничения и вопросы по сканированию образов
Сканирование образа встраивается в сборку и сразу поднимает четыре инженерных вопроса: сколько времени оно добавляет, что делать с уязвимостями без исправления, как отсекать ложные срабатывания и нужна ли пересборка после обновления баз. Ниже — как мы отвечаем на каждый.
Замедлит ли сканирование сборку?
Syft разбирает слои образа и составляет перечень пакетов, Grype сверяет его с базой уязвимостей. Основное время уходит на чтение слоёв, а не на поиск, поэтому проверка идёт параллельно с остальными шагами и на типовом образе не меняет общее время выпуска.
Что делать с уязвимостями, для которых нет исправления?
Часть находок — в пакетах, где поставщик ещё не выпустил обновление, и установкой новой версии их не закрыть. Такие случаи не блокируют выпуск: правила настраиваются по уровням опасности, а неисправимое уходит в список принятого риска с датой пересмотра.
Как отсекать ложные срабатывания?
Ложное срабатывание возникает, когда совпадение идёт по имени пакета, а не по фактически собранному коду. Лечится исключениями с обоснованием и привязкой к номеру уязвимости — правило живёт в репозитории, его видно на review и можно отозвать.
Нужна ли пересборка при обновлении баз?
Нет. База уязвимостей хранится отдельно от образа: повторное сканирование уже собранных тегов даёт свежую картину без выпуска новых версий. Пересборка требуется только при смене базового образа или самих правил.
Обсудим задачу: сканирование ваших образов и пороги блокировок
Чтобы оценка задачи опиралась на вашу схему сборки, а не на усреднённые цифры, разбор начинаем с того, как образы появляются и живут у вас. Пришлите файлы сборки, выгрузку манифестов из реестра, перечень базовых образов и порядок выпуска релизов — по ним видно, на каком шаге сканирование Grype и Syft встраивается, не останавливая выпуск.
После разбора вы получаете:
- карту текущего потока: от коммита до публикации образа в реестре и дальше до стенда;
- перечень базовых образов и слоёв с оценкой уязвимостей по каждому;
- предложенные пороги блокировок по уровням критичности и правило их пересмотра;
- схему подавления ложных срабатываний с журналом исключений и сроками, когда запись истекает;
- вариант встраивания — на сборке, в проверке перед слиянием или в реестре — с обоснованием выбора;
- план работ этапами, где отмечено, на каких шагах выпуск можно остановить, а на каких нет;
- список того, что нужно от ваших инженеров: доступы, сервисные учётные записи, окна изменений.
Опишите задачу как удобно: абзацем в письме или коротким созвоном с вашим инженером. Мы вернёмся с оценкой, планом работ и понятной картиной того, что изменится в выпуске после внедрения безопасности контейнеров.







