Где разместить quality gates в пайплайне: расположение важнее, чем то, что вы сканируете
Вы пушите коммит. Пайплайн запускается. Вы ждете. И ждете. Через пятнадцать минут пайплайн падает из-за уязвимости низкой степени серьезности в библиотеке, которую ваш код даже не использует. Вы исправляете, пушите снова и снова ждете пятнадцать минут.
Это цена размещения всех quality gates в одной точке пайплайна. Альтернатива не менее раздражает: все сканирования выполняются в самом конце, прямо перед продакшеном. Код проходит сборку, юнит-тесты, интеграционные тесты и стейджинг. А затем падает, потому что хардкодный секрет лежал в конфигурационном файле с первого коммита. Вы только что потратили часы времени пайплайна на то, что можно было отловить за секунды.
Позиция каждого gate определяет две вещи: как быстро разработчики получают обратную связь и сколько времени и вычислительных ресурсов вы тратите впустую при сбое. Правильное расположение — это не выбор между скоростью и безопасностью. Это порядок проверок, при котором они работают вместе.
Быстрые и легкие проверки — первыми, тяжелые — позже
Основной принцип прост: быстрые, легковесные проверки выполняются в начале пайплайна. Тяжелые проверки, требующие больше контекста, — позже. Но это не про разделение сканирований на две группы. У каждого типа сканирования есть свое естественное место, где оно приносит максимальную пользу с минимальными помехами.
Диаграмма ниже показывает соответствие каждого gate рекомендуемому этапу пайплайна:
Secret Scan: запускать до сборки
Секреты должны обнаруживаться до того, как что-либо будет собрано. Как только секрет попадает в образ контейнера или артефакт, удалить его становится гораздо сложнее. Образ уже может быть запушен в registry, стянут другими системами или развернут в окружении. Даже если вы удалите образ, секрет может остаться в кеше или логах.
Запускайте сканирование секретов сразу после checkout кода, до любого шага сборки. Если пайплайн находит хардкодный API-ключ или пароль к БД, разработчик получает мгновенную обратную связь. Он исправляет файл, пушит снова, и пайплайн перезапускается, не дожидаясь сборки, которая в любом случае была бы напрасной.
Dependency Scan: до создания артефакта
Сканирование зависимостей проверяет библиотеки, которые подтягивает ваш проект. Ему нужен манифест зависимостей, который доступен сразу после checkout. Естественное место для этого сканирования — после checkout, но до сборки артефакта.
Если у новой добавленной библиотеки есть критическая уязвимость, пайплайн падает рано. Разработчик не ждет сборки, юнит-тестов или интеграционных тестов. Он исправляет зависимость и пушит снова. В этом суть ранней обратной связи: быстро падать на проблемах, которые дешево исправить.
Некоторые сканеры зависимостей достаточно быстры, чтобы запускаться до сборки. Другие — медленнее. Если ваш сканер работает несколько минут, рассмотрите запуск на каждый коммит только для основной ветки, а для feature-веток — только на pull request. Это сохраняет быструю обратную связь для повседневной работы, но все еще ловит проблемы до того, как они попадут в продакшен.
Container Image Scan: после сборки, до registry
Сканирование образов контейнеров отличается. Вы не можете отсканировать образ, пока он не существует. Правильное место — после сборки образа, до его пуша в registry или использования в любом окружении.
Если образ содержит уязвимости, пайплайн останавливается здесь. Образ никогда не попадает в стейджинг или продакшен. Это важно, потому что, как только образ оказывается в registry, другие пайплайны или команды могут его стянуть. Остановка пайплайна в этой точке предотвращает распространение уязвимых образов.
Компромисс в том, что сканирование образов занимает время. Если ваша команда пушит много коммитов в день, запуск полного сканирования образов на каждый коммит может значительно замедлить пайплайн. Распространенный подход — запускать быстрое сканирование на каждый коммит и полное сканирование на слияния в основную ветку. Другой вариант — кешировать результаты сканирования и пересканировать только при изменении базового образа или зависимостей.
IaC Scan и Policy Check: два места, две цели
Сканирование инфраструктуры как кода и проверки политик могут выполняться в двух разных точках, и каждая служит своей цели.
Во-первых, запускайте их, когда пишется код инфраструктуры. Это дает разработчикам быструю обратную связь, пока они еще работают над конфигурацией. Им не нужно ждать полного прогона пайплайна, чтобы узнать, что правило security group слишком разрешающее или что storage bucket общедоступен.
Во-вторых, запускайте их снова перед применением конфигурации к окружению. Это compliance gate. Даже если разработчик проигнорировал раннее предупреждение, пайплайн обеспечивает соблюдение политики до того, как любые изменения инфраструктуры вступят в силу.
Первый gate — для удобства разработчика. Второй — для уверенности в соответствии требованиям. Нужны оба, но они не обязаны выполнять одни и те же проверки. Ранний gate может выполнять более легкие проверки, в то время как поздний запускает полный набор политик.
Чего избегать: один большой gate в конце
Худший паттерн — поместить все сканирования в один блок в конце пайплайна. Это создает длинный цикл обратной связи для любого типа проблем. Пропущенный секрет, уязвимая зависимость, неверно настроенный IaC-файл и уязвимость контейнера — все сообщается одновременно, после того как разработчик прождал сборку, юнит-тесты, интеграционные тесты и стейджинг.
Этот паттерн также делает пайплайн хрупким. Одно медленное сканирование блокирует все остальные. Если сканирование падает, разработчику нужно исправить проблему и снова ждать весь пайплайн, включая все шаги, которые уже прошли.
Распределите gates по пайплайну так, чтобы у каждого этапа была четкая ответственность. Ранние этапы быстро ловят дешевые проблемы. Поздние этапы ловят дорогие проблемы до того, как они достигнут продакшена.
Учитывайте стоимость сканирования
Некоторые сканирования дороги. Полные проверки баз данных зависимостей, глубокий анализ контейнеров и всесторонние оценки политик могут занимать минуты и потреблять значительные вычислительные ресурсы. Запускать их на каждый коммит для каждой ветки расточительно.
Решение — не пропускать сканирования. Размещать их стратегически. Запускайте дорогие сканирования только на основной ветке или на pull request, нацеленных на основную ветку. Для feature-веток запускайте только быстрые проверки: сканирование секретов, быстрое сканирование зависимостей и проверку синтаксиса. Это сохраняет пайплайн быстрым для повседневной работы, но все еще обеспечивает качество перед попаданием кода в продакшен.
Практический чеклист
- Secret scan запускается до сборки, сразу после checkout.
- Dependency scan запускается до создания артефакта, используя манифест.
- Container image scan запускается после сборки, до пуша в registry.
- IaC scan запускается в двух точках: во время разработки и перед применением к окружению.
- Дорогие сканирования запускаются только на основной ветке или целях слияния.
- Быстрые сканирования запускаются на каждый коммит для всех веток.
Вывод
Правильно размещенный gate ловит проблемы рано, когда их дешево исправить. Неправильно размещенный gate ловит проблемы поздно, после того как время и ресурсы потрачены впустую. Цель — не сканировать все везде. Цель — разместить каждое сканирование там, где оно дает самую быструю обратную связь для проблем, которые оно предназначено ловить. Когда расположение правильное, разработчики получают быстрые победы, compliance — свои гарантии, а пайплайн остается достаточно быстрым, чтобы никому не захотелось его обходить.