Почему ваш пайплайн должен проверять безопасность и соответствие требованиям
Когда ваша команда впервые настраивает CI/CD пайплайн, проверки обычно касаются очевидных технических аспектов: компилируется ли код, проходят ли юнит-тесты, запускается ли приложение. Это логично. На этом этапе самые заметные проблемы — это сломанный код и неработающие функции.
Но как только реальные пользователи начинают использовать ваше приложение, появляются новые вопросы. Есть ли в этом коде уязвимость? Известна ли уязвимость для этой библиотеки? Соответствует ли конфигурация сервера политикам компании? Не закоммитил ли кто-то пароль по ошибке?
Большинство команд отвечают на эти вопросы вручную. Команда безопасности проводит периодические аудиты. Кто-то заполняет чек-лист соответствия перед каждым релизом. У такого ручного подхода есть три проблемы.
Во-первых, проверки выполняются после того, как код готов, а иногда и после того, как он уже попал в продакшен. Когда вы находите проблему, её исправление требует постоянного согласования между командой разработки и командой безопасности. Это дорого и медленно.
Во-вторых, ручные проверки непоследовательны. Один и тот же человек может упустить разные вещи в разные дни. Два человека могут интерпретировать одно и то же правило по-разному.
В-третьих, ручные процессы не успевают за вашей командой, если вы выкатываете изменения несколько раз в день. Узким местом становится не написание кода, а ожидание утверждений и заполнение чек-листов.
Пайплайн как автоматический шлюз безопасности
Вот почему проверки безопасности и соответствия требованиям должны быть встроены в ваш пайплайн. Идея проста: каждый раз, когда кто-то отправляет изменения, пайплайн выполняет одни и те же проверки, одним и тем же способом и даёт последовательные результаты.
Если есть уязвимость, пайплайн сообщит вам до того, как код попадёт в продакшен. Если конфигурация нарушает политику компании, пайплайн остановит процесс до того, как проблема распространится.
Речь не о замене команды безопасности. Речь о том, чтобы автоматически выявлять очевидные проблемы, чтобы команда безопасности могла сосредоточиться на более сложных вопросах, требующих человеческого суждения.
Проблема скорости
Многие команды опасаются, что добавление проверок безопасности замедлит пайплайн. Это опасение обоснованно, но проблема не в самих проверках. Проблема в том, чтобы запускать каждую проверку на каждый коммит, не задумываясь, какие проверки когда нужны.
Запуск полного сканирования зависимостей на уязвимости, которое занимает пятнадцать минут на каждый коммит, определённо расстроит разработчиков. Но запуск того же тяжёлого сканирования раз в день или только перед слиянием в основную ветку оказывает минимальное влияние на скорость разработки.
Ключ в разделении быстрых и медленных проверок.
Быстрые проверки выполняются за секунды. Сканирование на предмет случайно закоммиченных секретов занимает почти no time. Проверка приемлемости лицензий библиотек так же быстра. Эти проверки должны выполняться на каждый коммит. Они выявляют проблемы на ранней стадии и достаточно дёшевы, чтобы никто не замечал задержки.
Медленные проверки занимают минуты или больше. Сканирование зависимостей по базе уязвимостей требует загрузки и сравнения данных. Сканирование образов контейнеров на известные CVE включает анализ слоёв и установленных пакетов. Эти проверки ценны, но их не нужно запускать на каждый пуш кода. Запускайте их, когда кто-то открывает pull request, или перед развёртыванием в staging-среду.
Как выглядят проверки безопасности в пайплайне на практике
Давайте сделаем это конкретным. Вот распространённые категории проверок безопасности и соответствия, которые должны быть в пайплайне:
Сканирование секретов. Инструменты, которые обнаруживают API-ключи, пароли, токены и сертификаты, закоммиченные в репозиторий. Они работают быстро и должны запускаться на каждый коммит. Если кто-то случайно запушит учётные данные, вы хотите узнать об этом немедленно, а не после того, как код попадёт в продакшен.
Сканирование зависимостей. Проверки, которые сравнивают зависимости вашего проекта с базами данных известных уязвимостей. Они сообщают, есть ли у используемой вами библиотеки опубликованный CVE. Запускайте их на pull request и перед развёртыванием в продакшен.
Статическое тестирование безопасности приложений (SAST). Инструменты, которые анализируют исходный код на наличие уязвимостей без его выполнения. Они ищут риски SQL-инъекций, межсайтового скриптинга, небезопасных криптографических функций и подобные проблемы. Инструменты SAST различаются по скорости, но многие могут выполниться за минуту-две на кодовых базах разумного размера.
Сканирование образов контейнеров. Если вы собираете образы контейнеров, сканируйте их на уязвимости в базовом образе и установленных пакетах. Это выявляет проблемы на уровне операционной системы и зависимостей времени выполнения, которыми ваш код напрямую не управляет.
Вот как выглядит шаг сканирования образа контейнера в workflow GitHub Actions:
- name: Scan container image for vulnerabilities
uses: aquasecurity/trivy-action@master
with:
image-ref: 'my-app:${{ github.sha }}'
format: 'table'
exit-code: '1'
severity: 'CRITICAL,HIGH'
Этот шаг запускает Trivy для собранного образа, выводит таблицу результатов и завершает задачу с ошибкой, если найдены уязвимости критического или высокого уровня. Параметр exit-code: '1' гарантирует остановку пайплайна, выступая в роли автоматического шлюза.
Сканирование инфраструктуры как кода. Если вы определяете инфраструктуру с помощью Terraform, CloudFormation или аналогичных инструментов, сканируйте эти определения на предмет неправильных конфигураций. Например, открытые группы безопасности, нешифрованное хранилище или излишне разрешительные политики IAM.
Проверка лицензий. Проверка совместимости лицензий ваших зависимостей с лицензированием проекта и политикой компании. Это особенно важно для коммерческих продуктов или проектов, которые могут распространяться внешне.
Практический подход к началу работы
Вам не нужно внедрять всё сразу. Начните с проверок, которые закрывают ваши самые актуальные риски.
Если ваша команда случайно коммитила секреты, начните со сканирования секретов. Если вас подводила уязвимая библиотека, начните со сканирования зависимостей. Если команда инфраструктуры находила неправильные конфигурации в продакшене, начните со сканирования IaC.
Добавляйте проверки постепенно. Запускайте быстрые проверки на каждый коммит. Планируйте медленные проверки на момент pull request или перед развёртыванием в staging. Пусть пайплайн сообщает вам о сбое проверки, и убедитесь, что сообщение об ошибке достаточно понятно, чтобы разработчик знал, что исправлять.
Краткий чек-лист для вашего пайплайна
- Сканирование секретов запускается на каждый коммит
- Сканирование зависимостей запускается на pull request и перед развёртыванием в продакшен
- SAST запускается на pull request
- Сканирование образов контейнеров запускается перед развёртыванием в staging
- Сканирование инфраструктуры как кода запускается на изменения инфраструктуры
- Проверка лицензий запускается на pull request
- Быстрые проверки (секунды) запускаются на каждый коммит
- Медленные проверки (минуты) запускаются на pull request или перед staging
Реальная ценность
Проверки безопасности и соответствия в вашем пайплайне — это не лишняя бюрократия, которая вас замедляет. Это ограждения, которые позволяют вашей команде двигаться быстрее и увереннее. Когда каждое изменение проходит одни и те же автоматические проверки, вам не нужно гадать, есть ли в этом релизе известная уязвимость или нарушает ли он политику компании. Пайплайн уже ответил на эти вопросы.
Ваша команда может сосредоточиться на создании функций и исправлении ошибок, зная, что базовые фильтры безопасности и соответствия работают автоматически, последовательно и немедленно. В этом разница между надеждой, что ничего не пойдёт не так, и знанием, что ничего очевидного не пошло.