Сканирование контейнеров: где ломается контроль образов
Базовый образ в проекте обычно не ревьюят: инженер берёт публичную сборку, добавляет зависимости приложения и отправляет в реестр. Обновление «чужой» базовой сборки проходит незаметно — её нет в дереве проекта, никто не смотрит её слои, а тег остаётся прежним, меняется только содержимое под ним.
Через недели сканирование контейнеров показывает критичную уязвимость в системном пакете, которого нет в исходниках приложения. Она пришла из базового слоя — и на той же сборке стоят ещё десятки сервисов. Патч одного сервиса ничего не закрывает: следующий релиз соседа соберётся поверх той же дыры.
Контроль образов перед выкладкой пробуют делать руками: посмотреть тег, пробежать список пакетов, сверить с прошлым релизом. На нескольких десятках сервисов и двух-трёх средах это не воспроизводится — результат зависит от того, кто дежурит, а история слоёв нигде не сохраняется. Уязвимые образы в продакшене живут не потому, что их не искали, а потому что искали один раз и не там.
Цена: экстренный откат в разгар инцидента, внеплановый выпуск и ручной обход реестра, чтобы оценить масштаб. Часть сервисов остаётся на старой сборке месяцами — её нужно пересобрать, перепроверить и выкатить, а это ручная работа на каждый сервис по отдельности.
Разбираем, как это закрывается: где в сборке появляется обязательный шлюз, что он проверяет до выкладки и как ловится уязвимость, пришедшая из чужой базовой сборки.
Что даёт ранняя проверка образов в конвейере
Ранняя проверка образов смещает точку контроля влево: сканирование идёт сразу после сборки, до публикации в реестр. Сканер разбирает слои и манифест, сверяет системные пакеты и зависимости приложения с базой уязвимостей и отдаёт находки с уровнями критичности. На этом этапе сбой стоит пересборки, а не отката релиза.
Политика сборки отсекает находки высокого и критического уровня в тех слоях, что попадают в среду исполнения; замечания к зависимостям уровня разработки остаются предупреждением. Так уходит целый класс отказов — уязвимый базовый образ, забытый пакет, библиотека без обновлений. Пороги блокировки мы настраиваем по классификации рисков контейнерной среды, описанной в OWASP: это даёт общий язык с командой безопасности вместо ручных договорённостей.
Время выкладки при этом не растёт: проверка идёт параллельно тестам, сканируются только изменившиеся слои, а неизменный базовый образ берётся из кэша. Результат приходит раньше, чем завершается сборка, — отдельного ожидающего этапа в конвейере нет. Релиз, который раньше уходил в эксплуатацию и откатывался, теперь просто не проходит дальше.
Время реакции на инцидент определяется не скоростью сканера, а наличием инвентаря. К каждому образу привязан перечень компонентов с версиями, поэтому при появлении сведений о новой уязвимости мы находим все затронутые образы одним запросом, а не перебором реестра вручную. Дальше — пересборка на исправленном базовом слое, и откат на предыдущий тег остаётся доступным.
Итог: контроль переносится туда, где исправление дешевле, а данные о составе образа остаются под рукой в момент инцидента.
Способы сканирования контейнеров: сравнение режимов
Режимы различаются тем, на каком этапе жизненного цикла образа выполняется проверка и какой слой она видит. Проверка при сборке ловит уязвимости до публикации, проверка в реестре образов страхует теги, пришедшие извне, а периодическая инвентаризация находит то, что уже работает на стендах. Поэтому сканирование контейнеров выстраивают как последовательность режимов, а не выбирают один.
| Режим | Когда подходит | Ограничения |
|---|---|---|
| При сборке образа | Свой код, контроль на входе: конвейер останавливается на критичных находках | Замедляет сборку; не видит образы, собранные вне конвейера |
| При публикации в реестр | Несколько команд и общий реестр: единая политика для всех тегов | Реагирует после факта сборки; нужна интеграция с реестром |
| Перед выкладкой | Кластеры с жёсткими требованиями: запуск отклоняется до прохождения политики | Хрупко: ломает выкладку при смене правил, нужен список исключений |
| Периодическая инвентаризация запущенного | Долгоживущие стенды: видно фактическое состояние, а не намерение | Запаздывает: образ уже работает, пока идёт проверка |
Общее ограничение проверок — база уязвимостей обновляется, и вчера чистый образ сегодня получает критичные находки. Кроме того, проверка не различает библиотеку, которая реально вызывается во время работы, и мёртвый код. Поэтому политику строят на приоритетах: блокировать только то, для чего уже есть исправленная версия, остальное — в очередь с фиксированным сроком устранения.
Как мы встраиваем проверки в конвейер: этапы работ
Порядок этапов зависит от того, как устроен ваш конвейер сборки: где собирается образ, как попадает в реестр, кто вправе его публиковать. Встраиваем сканирование контейнеров так, чтобы шаг проверки не растягивал сборку и не останавливал релизы на ложных срабатываниях.
- Аудит конвейера сборки. Разбираем стадии, где формируются образы и какие политики доступа к реестру уже действуют. Фиксируем время сборки до изменений — это точка отсчёта для оценки накладных расходов.
- Схема проверок образов. Определяем, что и на каком шаге проверяем: базовый слой, зависимости, учётные данные в слоях, конфигурацию запуска. Быстрые проверки — на каждый коммит, полный разбор — на релизную ветку.
- Настройка правил допуска. Критичные уязвимости блокируют публикацию, средний уровень уходит в очередь на разбор. Исключения оформляем письменно, с причиной и сроком пересмотра, иначе правила быстро становятся формальностью.
- Проверка на стенде. Прогоняем сценарий на реальных образах проекта: замеряем добавленное время, смотрим долю ложных срабатываний и проверяем откат на предыдущую сборку.
- Передача регламентов. Описание схемы, порядок чтения отчётов, правила обновления базы уязвимостей и матрица ответственности: кто разбирает замечания и как менять пороги без правки самого конвейера.
Политики допуска, отчёты и схемы: что остаётся команде
Сканирование перестаёт быть разовой проверкой, когда опирается на артефакты, которые живут в репозитории и внутренней базе знаний. Ниже — тот минимум, с которым дежурная смена и релиз-инженеры работают без нашего участия.
- Конфигурации проверок в репозитории: этапы сборки, пороги критичности, правила исключений для ложных срабатываний и внешних зависимостей.
- Политики допуска образов — какие уровни уязвимостей блокируют выпуск, что проходит по исключению и кто подписывает его на срок.
- Отдельные правила для служебных и прикладных образов, чтобы выпуск не вставал из-за находок, неприменимых к роли контейнера.
- Схемы конвейера: место проверки в цепочке и реакция на срабатывание — остановка, предупреждение или выпуск с отметкой.
- Шаблоны отчётов по уязвимостям: состав находок, приоритет, ответственный, срок устранения, признак повторного появления.
- Инструкции для дежурной смены: как читать отчёт, что делать при блокировке перед релизом и по какому признаку эскалировать.
- Регламент синхронизации баз уязвимостей и ревизии исключений — чтобы временное послабление не стало постоянным.
Артефакты лежат рядом с кодом и связаны со схемой конвейера: при правке политики сразу видно, какие проверки затронуты. Решение о допуске образа становится воспроизводимым — его принимает описанное правило, а не конкретный инженер.
Кейс: как убрали уязвимые образы из выкладки
Что было
Образы собирались теми же заданиями, что и сейчас, но уязвимости всплывали уже на проде — их находил сканер периметра или инцидент. Замечания службы безопасности копились отдельным реестром: критичных набралось несколько десятков, срок закрытия доходил до трёх недель, потому что обновление базового слоя тянуло пересборку зависимых сервисов.
Что изменили
Проверку поставили между сборкой и отправкой образа в реестр, отчёт на базе Trivy разложили на два порога. Критичные уязвимости с доступным исправлением блокируют выкладку, средние уходят задачей со сроком, ложные срабатывания гасятся исключениями в файле политики. Обойти порог можно только правкой политики — это остаётся в истории изменений.
| Показатель | До | После |
|---|---|---|
| Доля отклонённых образов | блокировки не было | 17–20% сборок |
| От обнаружения до исправления | 2 суток | 3–5 часов |
| Закрытие замечаний безопасности | до 3 недель | 2–4 дня |
| Критичные уязвимости в проде | десятки | единицы |
Сканирование добавило к сборке около сорока секунд — цену приняли сознательно, потому что срок выкладки определяло ожидание проверок, а не сборка. Доля отклонённых образов стабилизировалась не сразу: сначала отклонялась почти четверть сборок, затем сервисы перешли на поддерживаемые базовые образы, и показатель держится на одном-двух релизах в неделю.
Чем проверка базового образа отличается от проверки слоёв?
Проверка базового образа отвечает на вопрос, не приехало ли уязвимое наследие из родительского слоя. Сканер идёт по манифесту и сверяет версии пакетов дистрибутива: вердикт почти не зависит от вашего кода и меняется, когда обновляется сам базовый образ.
Проверка слоёв добавляет всё, что вы доложили сверху: собранные бинарники, зависимости приложения, скопированные конфиги. Сканеры вроде Trivy читают историю слоёв, и здесь же всплывают секреты — файл, удалённый в следующем слое, остаётся в предыдущем и достаётся из реестра. Поэтому контроль базового образа не отменяет послойную проверку.
Третий уровень — проверка запущенного экземпляра. Она видит фактически смонтированную файловую систему, права процесса и подключённые тома, включая пакеты, доустановленные при старте.
Строгость правил растёт вместе с уровнем: на базовом образе сборку валят по критичным, на слоях — предупреждают и требуют разбора, на запущенном экземпляре блокируют выкатку только по достижимым уязвимостям.
Частые технические сомнения перед внедрением проверок
Инженерные возражения перед внедрением проверок обычно одни и те же: анализ замедлит сборку, поднимет шум ложными срабатываниями и заставит пересобирать уже выпущенные образы. Ниже — как каждое из них закрывается на практике, без остановки выпуска.
Как гасить ложные срабатывания?
Мы не спорим с находками, а настраиваем политику: правила исключений с указанием пакета, пути и причины, обязательным сроком пересмотра и владельцем. Блокируют выпуск только уязвимости критического и высокого уровня, остальное уходит в отчёт и разбирается по плану. Так очередь заявок на «отключите проверку» не растёт.
Насколько проверка замедлит сборку?
Базовый образ сканируется один раз и переиспользуется из кэша, на каждой сборке проверяется только изменённый слой — то есть новый код и обновлённые зависимости. Полный обход запускается по расписанию, а не на каждый коммит, поэтому рост времени сборочной задачи измеряется секундами, а не минутами.
Что делать с уже опубликованными образами?
Включаем режим наблюдения: реестр обходится целиком, находки складываются в отчёт, выпуск не блокируется. Дальше по критичным находкам идёт отдельный план замены, а ворота с блокировкой включаются только для новых сборок — старые теги живут до планового обновления, без аврального переписывания релиза.
Можно ли проверить сторонние образы поставщика?
Да, но доверять чужому отчёту нельзя: проверяем базовый слой и зависимости своими правилами, а непрозрачно собранные базовые образы пересобираем у себя из исходников. Теги фиксируем по контрольной сумме образа, иначе поставщик подменит содержимое под тем же именем, и проверка потеряет смысл.
Придётся менять свой инструмент сканирования?
Нет. Существующий сканер подключается как отдельный шаг сборочной цепочки, а отчёты приводятся к единому виду — срабатывания из разных источников попадают в одну очередь. Замену делаем только если инструмент не умеет нужный формат вывода или не закрывает требуемые классы уязвимостей.
Обсудим задачу: с чего начинается внедрение проверок
Внедрение проверок начинается не с настройки сканера, а с инвентаризации: что уже собирается, из каких базовых образов и куда попадает при выпуске. Первый этап — доступы и разбор текущего конвейера, потому что политики, написанные без понимания ветвления и порядка сборки, блокируют релизы вместо того, чтобы их защищать. План работ по конвейеру строится волнами: сначала проверка на этапе сборки в режиме наблюдения, затем — блокирующие правила для критичных сервисов.
Чтобы вернуться с оценкой и планом, а не с общими словами, нам нужен от вашей стороны короткий стартовый набор:
- читающий доступ к репозиториям и настройкам ветвления — видим, где точки входа и кто вправе менять правила;
- доступ к реестру образов с правом читать метаданные тегов и историю слоёв;
- описание текущего конвейера: этапы, триггеры, кто и как выпускает в промышленную среду;
- ответственный за правила — инженер, принимающий решения по порогам критичности и исключениям;
- перечень сервисов, которые нельзя останавливать, и перечень тех, где допустим блокирующий режим;
- сведения о базовых образах: свои или публичные, кто отвечает за их обновление;
- контакт для приёмки — тот, кто подтвердит, что проверка не ломает выпуск.
Опишите задачу в двух-трёх абзацах: сколько сервисов, какой конвейер, где сейчас проходит граница между сборкой и выпуском. Мы вернёмся с оценкой сроков, последовательностью этапов и тем, что вы получите на каждом шаге — от первого прогона в режиме наблюдения до блокирующих политик.







