В первый раз я добавил Semgrep в продовый пайплайн без настройки порогов - все правила, severity: warning, blocking stage. Через час в Slack прилетело сорок сообщений: мёрж заблокирован на двести находок, из которых сто восемьдесят - false positives. Релиз сдвинулся на два дня, а слово «безопасность» стало ругательным в чате команды на три недели. С тех пор DevSecOps внедрение я начинаю с плана, а не с инструмента. Ниже - roadmap, который выстроился после трёх таких провалов на разных проектах.
Статья составлена командой Codeby. Публикую повествование от первого лица.
Shift left security: зачем двигать проверки к началу пайплайна
Принцип shift left security сводится к арифметике: уязвимость, пойманная на этапе коммита, стоит разработчику одну правку в строке. Та же уязвимость в продакшене - инцидент, хотфикс, постмортем и потерянное доверие бизнеса. Русскоязычные статьи по DevSecOps практике обычно останавливаются на этом тезисе. Но за ним прячется менее очевидная штука: незащищённый CI/CD-пайплайн - полноценный вектор атаки сам по себе. Подробнее - в нашем подробном разборе атаки на цепочку поставок.В матрице MITRE ATT&CK задокументированы конкретные техники, нацеленные именно на пайплайн:
- Poisoned Pipeline Execution (PPE, OWASP CICD-SEC-04) - внедрение вредоносного кода через модификацию конфигурации пайплайна
- Compromise Software Dependencies and Development Tools (T1195.001, Initial Access) - компрометация зависимостей и инструментов сборки
- Credentials In Files (T1552.001, Credential Access) - секреты, забытые в конфигах CI/CD
DevSecOps инструменты: минимальный стек для первого шага
Не нужно прикручивать десять сканеров за один спринт. По рекомендациям Cloud Security Alliance, зрелые DevSecOps-практики включают SAST, DAST, SCA и secrets detection - но начинать стоит с набора, который даёт максимальный эффект при минимальном трении с командой разработки.| Категория | Инструмент | Что закрывает | Где в пайплайне |
|---|---|---|---|
| Secrets Detection | Gitleaks | Захардкоженные API-ключи, пароли, токены | Pre-commit / CI |
| SAST | Semgrep | Паттерны уязвимостей в собственном коде | CI (этап сборки) |
| SCA | Trivy | Известные CVE в зависимостях и контейнер-образах | CI (после сборки) |
| DAST | OWASP ZAP | Уязвимости в запущенном приложении (runtime) | Staging |
Semgrep - open-source SAST с поддержкой кастомных правил, активно развивается (релизы каждые 2-3 недели). Я выбираю его за синтаксис правил - они читаются почти как псевдокод, а не как регулярки из ада. Ограничение: статический анализ не видит проблем конфигурации runtime-окружения и не заменяет DAST. Gitleaks - легковесный детектор секретов для pre-commit хуков и CI-этапа, активно поддерживается. Не ловит секреты, переданные через переменные окружения вне репозитория - это его слепая зона. Trivy от Aqua Security - сканер зависимостей и контейнеров, работает с
package-lock.json, requirements.txt, go.sum и Dockerfile. Уязвимости в собственном коде вне его зоны - для этого Semgrep. OWASP ZAP - бесплатный DAST, проект OWASP. Требует запущенного приложения, поэтому подключается на staging, не раньше.Этот набор закрывает четыре вектора: секреты в коде (T1552.001 - Credentials In Files, T1552.004 - Private Keys), уязвимости в собственном коде, уязвимые зависимости (T1195.001) и проблемы, проявляющиеся только в рантайме. Ни один инструмент не покрывает все четыре - именно поэтому стек, а не один сканер.
Интеграция безопасности в CI/CD: пошаговый roadmap
Требования к окружению
- CI/CD-платформа: GitLab CI, GitHub Actions или Jenkins
- Runner/агент: Linux (Ubuntu 20.04+), минимум 2 ГБ RAM, 1 vCPU
- Сеть: доступ к интернету для скачивания баз уязвимостей (Trivy обновляет базу при каждом запуске, Semgrep подтягивает правила из registry)
- Права: доступ на редактирование
.gitlab-ci.yml/.github/workflows//Jenkinsfile - Версии инструментов: Semgrep >= 1.0, Gitleaks >= 8.0, Trivy >= 0.50
- Для изолированных сред (offline): предварительно скачать базы Trivy командой
trivy image --download-db-onlyи кешировать правила Semgrep
Шаг 1: Gitleaks - секреты не должны попадать в git-историю
Секрет, попавший в git-историю, остаётся там даже после удаления файла -git log помнит всё. Это прямой вектор Credentials In Files (T1552.001). Начинаем с non-blocking stage:
YAML:
gitleaks-scan:
stage: test
image: zricethezav/gitleaks:latest
variables:
GIT_DEPTH: 0 # полная история, иначе shallow clone пропустит старые коммиты
script:
- gitleaks detect --source . --report-format json --report-path gitleaks-report.json
allow_failure: true
artifacts:
paths:
- gitleaks-report.json
allow_failure: true - критически важная настройка на старте. Сканер показывает находки, но не блокирует мёрж. Разработчики видят результаты без потери скорости. Убираешь эту строку в первый день - получаешь бунт. Проверено.Шаг 2: Semgrep - статический анализ кода без лавины алёртов
Главная ошибка - включить все правила сразу. Начинайте с набораp/owasp-top-ten, а не с полного p/security-audit:
YAML:
semgrep-sast:
stage: test
image: returntocorp/semgrep:latest
script:
- semgrep --config p/owasp-top-ten --error --severity ERROR .
allow_failure: true
--severity ERROR оставляет только правила с уровнем ERROR, отсекая WARNING и INFO. Да, часть находок пролетит мимо - но начинать с WARNING на проекте с историей в пару лет это гарантированный путь к моей ошибке из первого абзаца. Тюнинг порогов - не слабость, а осознанный выбор: лучше ловить двадцать реальных проблем, чем тонуть в двухстах ложных.Шаг 3: Trivy - SCA на уязвимости в зависимостях
Trivy сканирует манифесты зависимостей и контейнер-образы. Уязвимые библиотеки - один из самых частых векторов supply chain атак (T1195.002). Подключается аналогично, черезallow_failure: true.На этом этапе в пайплайне три security-проверки, и ни одна не блокирует релиз. Через два-три спринта, когда команда привыкнет к отчётам и начнёт сама разбирать находки, переводите Gitleaks в blocking-режим (убираете
allow_failure). Ещё через месяц - Semgrep. DAST через OWASP ZAP добавляется последним, на staging-окружение, когда базовый стек уже работает стабильно.Ошибки, которые убивают DevSecOps практику
Блокировка пайплайна с первого дня. Если каждый мёрж-реквест падает на SAST - разработчики найдут способ обойти сканер (видел отдельные ветки «без проверок») или эскалируют на руководство. Advisory-режим на первые две-четыре недели - не компромисс, а стратегия внедрения.Игнорирование false positives. Каждый ложный алёрт подрывает доверие к инструменту. Потратьте полдня на
.semgrepignore: исключите файлы тестов, вендорный код, legacy-участки, которые никто не трогает. Десять минут настройки экономят часы разбора.Один инструмент на все задачи. SAST не видит runtime-конфигурацию. DAST не найдёт захардкоженный токен. SCA не проверяет собственный код. Попытка заменить стек одним сканером оставляет слепые зоны - а атакующий пойдёт именно туда.
Отсутствие ownership. Находки, падающие в общий Slack-канал без ответственного, копятся бесконечно. Назначьте security champion в каждой продуктовой команде - человека, который разбирает находки еженедельно и решает: fix, suppress с обоснованием или defer с конкретным сроком.
Что видит атакующий в пайплайне без AppSec
Пайплайн без автоматизации безопасности DevOps - не просто «мы не проверили код». Это конкретные точки входа, задокументированные в MITRE ATT&CK:- Code Repositories (T1213.003, Collection) - атакующий с доступом к репозиторию собирает секреты, внутренние URL, ключи из конфигов и комментариев
- Private Keys (T1552.004, Credential Access) - приватный ключ в репозитории = прямой доступ к инфраструктуре без дополнительной эксплуатации
- Software Deployment Tools (T1072, Execution / Lateral Movement) - скомпрометированный CI/CD-сервер (Jenkins, GitLab Runner) превращается в точку для латерального перемещения по сети
- Disable or Modify Tools (T1562.001, Defense Evasion) - атакующий модифицирует конфигурацию пайплайна, чтобы отключить security-стейджи и проходить незамеченным
Большинство провалов DevSecOps внедрения, которые я разбирал на ретроспективах, начинались одинаково: руководитель прочитал статью про безопасность в разработке, купил лицензию на коммерческий SAST, включил blocking на все severity - и через неделю разработчики выстраивают обходные пайплайны без сканеров. Проблема не в инструментах и не в бюджете. Проблема - в попытке внедрить безопасный SDLC приказом сверху, а не как привычку команды.
Gitleaks в advisory-режиме, Semgrep только на ERROR, Trivy в отчётном режиме - выглядит мягко. Но через месяц тимлид, который изначально сопротивлялся, начинает сам добавлять правила в конфиг Semgrep. Видел это трижды на проектах разного масштаба. Четыре инструмента, четыре стадии, ноль блокирующих правил на старте - и через квартал команда сама попросит закрутить гайки. Это работает надёжнее любого корпоративного приказа о «переходе на DevSecOps». Если хочется разобраться в ИБ шире, чем один пайплайн - на IB Basics разбирают безопасность от сети до приложений, без допущения, что ты уже всё знаешь.