GitLab 13.8: встроенный SAST в CI - переводим клиентские пайплайны
Переводим несколько клиентских пайплайнов на встроенный SAST GitLab 13.8 - разбираем что сканируется из коробки и когда это реальная замена SonarQube.
GitLab 13.8 расширяет встроенный SAST/DAST в CI-пайплайнах и добавляет политики безопасности как код через Security Policies
На фоне January supply chain новостей - SolarWinds, разговоры про SBOM, общая нервозность вокруг того что и откуда ставится - несколько клиентов начали спрашивать про security scanning в пайплайнах. Не в духе «пора бы разобраться», а уже конкретнее: «можете настроить?». Совпало с тем, что GitLab 13.8 вышел в январе и привёз заметные изменения в своей встроенной безопасности. Мы как раз начали переводить пару проектов, так что есть что рассказать.
Что вышло в 13.8
GitLab развивает SAST (Static Application Security Testing) и DAST (Dynamic Application Security Testing) как встроенные фичи, не требующие внешних инструментов. В 13.8 основные изменения:
- Расширен список анализаторов SAST. Поддерживается Semgrep как один из движков, что даёт более гибкие правила для Python, JavaScript, Go, Ruby. Плюс обновлены Bandit (Python), ESLint security rules (JS/TS), Gosec (Go), SpotBugs (Java/Scala/Groovy).
- Security Policies как код. Политики безопасности теперь описываются в YAML и хранятся в отдельном репозитории политик. Можно централизованно управлять: какие сканеры запускать, при каких условиях блокировать MR, какие уязвимости критичны.
- Улучшен Security Dashboard. На уровне группы можно видеть агрегированную картину по всем проектам, не заходя в каждый.
- DAST по расписанию. Динамическое сканирование можно запускать не только на каждый пайплайн, но и по cron - удобно для staging-окружений.
Всё это доступно начиная с уровня Ultimate. SAST в базовой форме - доступен и на Free-tier, но с ограниченным набором правил.
Зачем это интересно для небольших команд
У нас несколько клиентов, которые уже используют GitLab как основной инструмент CI/CD в рамках managed-сопровождения. Отдельного SonarQube там нет ни у кого. Исторически это объяснялось просто: SonarQube требует отдельного сервера, настройки, интеграции в пайплайн, поддержки - для команды из 3-5 разработчиков это ощутимый overhead. В итоге security scanning откладывался как «займёмся потом».
GitLab SAST в этой ситуации выглядит практично: сканер запускается как job в пайплайне, результаты видны прямо в интерфейсе GitLab, никакой отдельной инфраструктуры. Вопрос только в том, насколько это полезно по качеству.
Что сканируется из коробки
Включить базовый SAST - одна строчка в .gitlab-ci.yml:
include:
- template: Security/SAST.gitlab-ci.yml
После этого GitLab автоматически определяет языки в репозитории и запускает соответствующие анализаторы. Не нужно вручную указывать что и как сканировать.
Что реально покрывается на проектах, которые мы переводили:
Python (Django/Flask). Bandit ловит очевидные вещи: использование eval() и exec(), небезопасные десериализаторы, жёстко прописанные credentials в коде, слабые алгоритмы хэширования. Semgrep добавляет правила для SQL injection через f-строки и небезопасные конфигурации.
JavaScript/Node. ESLint security plugin - no-eval, небезопасный innerHTML, prototype pollution паттерны. Не так глубоко как специализированные инструменты, но базовые вещи ловит.
Dockerfile. Hadolint проверяет базовые образы и флаги - запуск от root, ADD вместо COPY, отсутствие pinned версий.
Secrets detection. Отдельный шаг, который ищет в коде потенциальные credentials, API-ключи, токены по регулярным выражениям. На первом прогоне у одного клиента нашёл три места с захардкоженными тестовыми паролями в конфигурационных файлах - которые «только для разработки», но лежали в репозитории.
Где встроенный SAST уступает SonarQube
Честно про ограничения. SonarQube с настроенными правилами глубже анализирует data flow - отслеживает как данные проходят через приложение от точки входа до потенциально опасной операции. GitLab SAST на базе Semgrep/Bandit работает больше pattern-matching'ом: видит подозрительный вызов, но не всегда понимает контекст.
Второе - качество правил зависит от выбранного анализатора. Для Java/Kotlin SpotBugs даёт неплохое покрытие, для PHP - анализатор слабее.
Третье - false positives. На Django-проекте средней сложности первый прогон выдал с полсотни предупреждений, из которых реально интересных оказалось около десяти. Остальное - либо шаблонные паттерны без контекста, либо тестовый код, который SAST не умеет отфильтровать без дополнительной конфигурации.
Как мы настраиваем
Базовая конфигурация, которую поставили нескольким клиентам:
include:
- template: Security/SAST.gitlab-ci.yml
- template: Security/Secret-Detection.gitlab-ci.yml
variables:
SAST_EXCLUDED_PATHS: "tests/, spec/, vendor/"
SAST_EXCLUDED_ANALYZERS: "eslint" # если проект не JS
sast:
stage: test
Исключение tests/ убирает большую часть false positives - тестовый код часто содержит намеренно небезопасные паттерны. После этого отношение сигнал/шум становится значительно лучше.
Где сейчас
Два проекта уже ходят с включённым SAST в каждом пайплайне - разработчики привыкают смотреть на вкладку Security в MR. Один проект ждёт - там PHP-легаси и нужно сначала понять, что анализатор выдаст, чтобы не заблокировать работу потоком ложных срабатываний.
Полноценного SonarQube встроенный SAST не заменяет - это честная позиция. Но для небольшой команды, у которой сейчас нет вообще никакого статического анализа, это реальный шаг вперёд без отдельного сервера и отдельного специалиста по ИБ. Главное - не включать и забывать: кто-то должен периодически смотреть в Security Dashboard и разбирать накопившиеся предупреждения. Иначе это просто job, который бегает и ничего не меняет.