Что ломается без сканирования Docker образов
Образ собирается из базового слоя, который обновляют раз в полгода-год. За это время в нём накапливаются устаревшие зависимости: библиотеки с известными уязвимостями остаются внутри, потому что приложение от них не отказалось, а базовый слой никто не пересобирал. Сканирование Docker образов начинается именно с этого слоя — там больше всего находок высокой критичности, и они одинаково затрагивают все сервисы, собранные на общей основе.
Вторая точка деградации — сама сборка. Менеджер пакетов в Dockerfile тянет версии без фиксации, в финальный образ попадают пакеты из состава для сборки и утилиты, которые в работе контейнера не участвуют. Каждый лишний пакет — дополнительная поверхность атаки, но сборка об этом молчит: успешно собранный образ выглядит рабочим.
Риск эксплуатации появляется там, где уязвимая зависимость доступна извне. Контейнер по умолчанию стартует с правами root, библиотека разбирает внешние данные — и одна непроверенная зависимость становится точкой входа, невидимой ни в логах приложения, ни на мониторинге.
Дальше сценарий один: уязвимость живёт в проде месяцами и всплывает только на инциденте после выкладки. Закрытие требует пересборки всех сервисов на общем базовом слое, повторной проверки образов в реестре, отката релиза и ротации секретов. Разбираем, как это закрывается сканированием на каждом этапе.
Что даёт раннее выявление уязвимостей в сборке
Уязвимость в базовом образе или транзитивной зависимости всплывает не тогда, когда её начали эксплуатировать, а когда кто-то спустя месяцы смотрит на старый тег. Раннее выявление уязвимостей переносит проверку на каждый шаг сборки и одновременно фиксирует состав образа: какая версия пакета попала в какой слой и каким изменением. Прослеживаемость зависимостей превращает «где-то внутри» в конкретную строку перечня компонентов — и закрывать её можно точечно, а не пересобирать всё вслепую.
Эффект измерим. Скорость закрытия дефектов меняется с недель на часы: критичное обновление попадает в сборку в тот же день, когда появляется в базе уязвимостей, потому что проверка встроена в конвейер, а не живёт отдельным отчётом. Доля откатов релиза из-за всплывшей зависимости уходит к нулю — несовместимое обновление отсекается до выкладки. Объём ручного разбора сокращается, когда инженер видит не весь список, а только новые находки относительно базовой линии.
Так уходит целый класс отказов: боевая среда с уязвимым базовым образом, который «собирались обновить», и инциденты из-за заброшенного пакета, о котором в проекте уже никто не помнил. Сокращение простоя здесь — следствие, а не лозунг: релиз не разбирают вручную, откат идёт на ранее проверенный образ.
Технически это набор политик: порог критичности, на котором сборка останавливается; список исключений с обязательным обоснованием и сроком пересмотра; сравнение с базовой линией, чтобы старые находки не тонули в шуме ложных срабатываний. Мы запускаем Trivy в конвейере, складываем результат в машиночитаемый отчёт и привязываем его к конкретному артефакту — поэтому вопрос «в каком релизе пришла эта зависимость» закрывается запросом, а не раскопками.
Режимы проверки: ручной прогон или контроль в сборке
Режимы отличаются не сканером, а моментом, когда вердикт становится обязательным. Чем раньше срабатывает проверка, тем дешевле правка — но тем меньше контекст: локально нет политики релиза, а в конвейере нет данных о том, как образ поведёт себя в рабочей среде. Поэтому на практике режимы не заменяют, а дополняют друг друга.
| Вариант | Когда подходит | Ограничения |
|---|---|---|
| Разовая ручная проверка | Разбор инцидента, аудит уже собранного образа, разведка перед внедрением | Закрывает один снимок состояния; результат устаревает вместе с обновлением баз уязвимостей |
| Контроль на машине разработчика | Быстрая обратная связь до отправки в репозиторий | Нет единой политики, версии баз у всех разные, проверку легко отключить |
| Проверка в сборочном конвейере | Основной барьер: сборка падает на критичных находках до публикации | Нужны настроенное обновление баз и разумный порог, иначе сборки тормозят и их начинают обходить |
| Контроль на входе в реестр | Страховка для сторонних образов и сборок в обход конвейера | Блокирует публикацию, но не сообщает автору, что именно исправлять |
| Периодический обход | Ловит уязвимости, раскрытые уже после релиза, и заброшенные теги | Находки приходят задним числом — нужен владелец, который закроет их пересборкой |
Рабочая схема — проверка в конвейере как обязательный барьер плюс регулярный обход реестра по расписанию, одним и тем же сканером, чтобы вердикты совпадали. Порог по критичности и списки исключений с датой пересмотра держим рядом с описанием сборки: без даты исключение быстро превращается в вечную слепую зону.
Этапы внедрения контроля уязвимостей в команде
Внедрение контроля уязвимостей — это не установка сканера, а изменение процесса сборки: проверка должна стоять там, где исправление занимает минуты, а не дни. Идём по шагам — от разбора текущего реестра до передачи регламента команде.
-
Аудит текущей сборки и реестра. Разбираем базовые образы, частоту пересборки, число тегов и возраст слоёв. Уже здесь видно, откуда берётся основная масса находок.
-
Схема контроля. Определяем точки проверки: при сборке, при отправке в реестр, перед выкаткой. Конкретный сканер (Trivy, Grype) здесь вторичен — важнее, где стоит проверка и какой уровень критичности блокирует выпуск, а какой даёт только предупреждение.
-
Настройка порогов и исключений. Порог задаём по критичности, а не по общему числу находок. У каждого исключения — владелец и срок пересмотра, иначе список исключений со временем перекрывает саму проверку.
-
Проверка на стенде. Прогоняем на копии реестра, сверяем результат с ручным разбором нескольких образов, замеряем долю ложных срабатываний до попадания в рабочий контур.
-
Проверка на реальных сборках. Несколько релизов идут в режиме предупреждения: отчёты команда получает, выпуск не блокируется. Так настраиваются правила, а не тормозится работа.
-
Передача регламента и обучение. Отдаём документ: что делать при находке, как её исправить, как оформить исключение, кто отвечает за базовые образы.
Дальше пороги и исключения пересматриваются по расписанию — заброшенные базовые образы и устаревшие исключения дают больше всего шума в отчётах.
Политики доступа, отчёты и регламент обновления
Сканирование Docker образов приносит пользу не отчётом, а набором артефактов, которые живут в репозитории и работают без нашего участия. Ниже — что остаётся у команды: конфигурации, схема запуска, правила реагирования и документы для разработчиков.
Настройки хранятся рядом с кодом и версионируются, поэтому проверка на локальной машине, при сборке образа и по расписанию идёт по одним правилам. Политики Trivy описываются декларативно и переносятся между окружениями без правок.
- Конфигурации проверок — файлы политик с порогами: какой уровень критичности останавливает сборку, какой только фиксируется в отчёте.
- Схема контроля — где запускается проверка: перед слиянием, при сборке образа, ночью по расписанию. И как ведёт себя сборка, если базы уязвимостей недоступны.
- Политика реагирования — сроки устранения по уровням критичности, кто решает выпускать ли образ с открытой находкой, как эскалируется просрочка.
- Перечень исключений — запись на каждое отклонение: обоснование, ответственный, дата пересмотра. Находка без исправления живёт со сроком, а не забывается.
- Регламент обновления базового слоя — как часто образ пересобирается на свежей базе, как проверяется совместимость и как выглядит откат.
- Отчёты по сборкам — что видно по каждой сборке: новый пакет, автор изменения, история по тегам, без запуска сканера вручную.
- Инструкции для команды — памятки: что делать при срабатывании, как оформить исключение, куда смотреть при спорной находке.
Кейс: окно уязвимости сократили с недель до суток
Заказчик — продуктовая команда с ежедневными релизами: 25–30 сборок в неделю, и почти все уходили в прод без проверки. Критичная уязвимость в базовом образе жила в проде от недели до двух, а узнавали о ней из внешнего уведомления, а не из своего контура. Разбор инцидента каждый раз начинался с вопроса «какой образ вообще сейчас в проде».
Мы встроили проверку в конвейер сборки: Trivy просматривает слои образа и манифесты зависимостей на этапе, где выкатку ещё можно остановить. Правило блокировки настроили не по общему числу находок, а по уровням — сборка падает только на критичных и высоких с подтверждённым путём эксплуатации, остальное уходит в список задач с датой разбора.
Метрики до и после: окно уязвимости сократилось с 11–14 дней до 18–24 часов, потому что обновление базового образа автоматически пересобирает зависимые сервисы. Доля ложных срабатываний упала с 40% до 8% — за счёт файла исключений, который мы ведём вместе с командой, а не «настроили однажды и забыли». Ручной разбор сократился с 6 часов в неделю до 40 минут: инженер смотрит только то, что действительно требует решения. Разбор инцидентов теперь идёт по списку компонентов с версиями из отчёта, а не по логам вслепую.
Что делать, если реестр образов уже развёрнут?
Если реестр уже развёрнут, переносить и пересобирать его не нужно: сканер подключается к нему как к обычному источнику и читает манифесты и слои по тому же программному интерфейсу, которым пользуется выкладка. Реестр остаётся рабочим, а проверка становится ещё одним шагом сборочного конвейера — после сборки образа и до публикации тега.
Начинаем с режима отчёта: сканер разбирает образы молча и складывает результаты в отдельное хранилище, ничего не блокируя. За несколько выкладок набирается статистика по настоящим зависимостям — видно, какие уязвимости приходят из базового образа, какие тянет приложение, а какие уже закрыты обновлением. По этой картине настраиваем уровни серьёзности, при которых сборка останавливается.
Миграция без остановки выкладок строится на параллельном проходе: старые теги остаются доступными, новые проходят проверку, а блокировка включается сначала только для критичных находок в наших слоях. Базовые образы, где исправлений ещё нет, на первом этапе уходят в список исключений с датой пересмотра — выкладки не встают, но долг не прячется.
Совместимость с текущей сборкой обеспечивается тем, что сканирование не меняет ни инструмент сборки, ни структуру слоёв: достаточно добавить шаг и выдать сканеру доступ к реестру на чтение. Кэш слоёв продолжает работать, время сборки растёт на десятки секунд, а на неизменившихся слоях почти не растёт. Политику проверок держим в файле рядом с описанием сборки и версионируем — откат делается одним изменением.
Дальше остаётся расширять покрытие: подключать к тем же правилам остальные репозитории и постепенно снимать исключения. Реестр уже развёрнут — меняется не он, а момент, в который мы узнаём об уязвимости.
Ложные срабатывания и медленная сборка: частые сомнения
Сканер, который на первом запуске отдаёт сотни строк, перестают читать через неделю — не потому, что он плох, а потому что в отчёте нет приоритета. Сигнал появляется после трёх настроек: фильтр по критичности и наличию исправленной версии, отсев недостижимого кода и короткий список исключений с обоснованием и датой пересмотра. После этого остаются единицы записей, и каждая требует решения.
Время сборки закрывается кэшированием: результат по неизменённому слою переиспользуется, база уязвимостей обновляется отдельной задачей. Проверка вешается на сборку образа, а не на каждый коммит, и останавливает конвейер только на согласованном уровне критичности.
Уязвимость в базовом слое — вопрос границ ответственности: дистрибутив внутри базового образа обновляет владелец шаблона, прикладные зависимости — команда сервиса. Регламент фиксирует, кто и в какой срок закрывает каждую категорию, иначе находка висит между командами.
Сканер выдаёт сотни уязвимостей, опасны единицы — как это развести?
Отсекаем по трём признакам: критичность, наличие исправленной версии в апстриме и достижимость уязвимого кода из приложения. Остаток уходит в список исключений с владельцем и датой пересмотра — исключение без срока превращается в забытую дыру.
Проверка замедлит сборку и выкатку — насколько?
Основное время съедают первое сканирование и обновление базы уязвимостей, дальше результат по неизменённым слоям берётся из кэша. Порог настраивается: блокируем критичное с доступным исправлением, остальное — уведомление в отчёте.
Обсудим задачу: что уточняем на первом созвоне
Первый созвон — это не презентация, а сбор вводных: мы задаём вопросы, чтобы оценка объёма и план внедрения опирались на вашу инфраструктуру, а не на средние цифры. Полный доступ к боевому контуру не нужен — достаточно схемы сборки, реестра и текущих правил.
- Как устроен сборочный конвейер: где собираются образы, сколько сервисов, кто владеет базовыми слоями.
- Что уже в реестре: сколько тегов на сервис, как глубоко хранится история, есть ли политика очистки — от этого зависит время первого полного сканирования.
- Какие сканеры применяются сейчас (Trivy, Grype, Snyk) и на каком этапе — локально, на сервере сборки или уже в кластере.
- Что именно должно останавливать сборку: только критические уровни, наличие исправленной версии, уязвимости в исполняемых слоях.
- Требования к отчётам и доступам: формат выгрузки (SBOM, SARIF), куда уходят результаты, доступ на чтение к реестру без права записи.
- Кто в вашей команде отвечает за обновление базовых образов — без владельца процесса правило блокировки быстро отключают.
В ответ присылаем оценку объёма работ, пошаговый план внедрения с точками отката и критерии приёмки: какую долю уязвимостей закрывает первый проход, как ведёт себя конвейер при сбое сканера, что делать с образами, которые уже в реестре. Опишите задачу — вернёмся с оценкой и планом.







