Cтатья будет полезна разработчикам и инженерам по ИБ, желающим повысить уровень безопасности приложений за счет внедрения проверок, запрещающих вносить секреты в открытом виде в исходный код. Автор: DevSecOps, в информационной безопасности с 2013 года, в СПАО «‎Ингосстрах»‎ встраиваю безопасность в процесс разработки Разработчики размещают в исходном коде различные секреты в открытом виде: В случае утечки исходного кода либо ознакомления с ним неуполномоченными лицами компания понесет ущерб. В статье поэтапно рассмотрен процесс внедрения Gitleaks для анализа pull request на наличие секретов в Azure DevOps Server. Этапы: Создать YML-файл конвейера-шаблона, реализующий логику поиска секретов; Создать валидационную сборку на основе YML-файла; Настроить запуск валидационной сборки в каждом запросе на вытягивание; Разработать FAQ для разработчиков и безопасников. Секрет — переменная, являющаяся аутентификатором (пароль, JSON Web Token, API-ключ, закрытый криптографический ключ). Допустимо относить к секретам и сами логины, например, опасно, если логин от внешней общедоступной системы, связанной с денежными переводами (например, логин мерчанта) будет известен каждому, кто имеет доступ к исходному коду приложения. А доступ, бывает, имеют не только разработчики, но и бизнес-пользователи. Поиск секретов — часть процесса по управлению секретами, заключающаяся в выявлении секретов в исходном коде на этапе внесения секретов в исходный код. Иные рекомендации OWASP по секретам: OWASP Secrets Management Cheat Sheet. Идентификация слабости ПО при хранении секретов в исходном коде: CWE-259: Использование жестко закодированного пароля. Идентификация риска информационной безопасности: риск OWASP TOP10:05 Security Misconfiguration. Среди рисков, актуальных для Kubernetes, проблемы с секретами даже выделены в целую категорию рисков Top 10 Kubernetes Risks K08: Secrets Management. Как видим, согласно лучшим практикам секреты искать нужно, не давать вносить секреты в открытом виде в исходный код также необходимо. Искать секреты можно в: IDE (привет, shift-left); Git (Azure Repos в рамках данной статьи). Искать секреты можно: Руками (глазами); Автоматически/автоматизированно. Стоит отметить, какое бы крутое решение по автоматизированному поиску секретов вы не выбрали, всё равно многие секреты вы будете находить глазами, просто листая код в репозитории. Причин несколько: Какие-то решения не поддерживают поиск секретов в нескольких строках; Регулярные выражения от автора выбранного решения могут не поддерживать поиск секретов в: XML, см. Secrets in web.config files · Issue #813 · gitleaks/gitleaks (github.com); Строках некоторых языков программирования; Строках с секретами на русском языке, например такие:# мой суперсекретныйпароль = &NB^IRU%&G (движок регулярного выражения не поддерживает кириллицу). Полезно знать, в каких файлах чаще всего разработчик оставляет секреты применительно в вашей компании. Чем будем искать секреты? В этой статье рассмотрим внедрение Gitleaks применительно к Azure DevOps Server в процесс анализа запросов на вытягивание при слиянии ветвей. Система управления исходным кодом Azure Repos является частью Azure DevOps Server. На момент публикации статьи упрощенно наша схема выглядит так: Эта же схема, но текстом и кратко: Разработчик создает запрос на вытягивание с целью объединить свою feature-ветвь с защищаемой ветвью. Запускается валидационная сборка с целью проверки секретов во вносимом коде и проверка завершается: С ошибкой при нахождении секретов; Успешно с предупреждением при нахождении секрета в репозитории, который внесен в исключение; Успешно при отсутствии секретов. Графически схема работы в разрезе сущностей Azure DevOps Server выглядит так: Предварительно на агент сборки необходимо положить gitleaks.exe, но можно его каждый раз из репозитория или менеджера пакетов подгружать. Второй вариант приоритетнее. Для реализации проверки секретов во вносимом коде потребуется: Создать YML-файл конвейера-шаблона (pipeline.yml), реализующий логику поиска секретов; Добавить в защищаемые репозитории другой YML-файл (gitleaks-pipeline.yml) вызывающий YML-файл конвейер-шаблон (pipeline.yml) в качестве шаблона (template); Создать конвейер на основе YML-файла (создать валидационный конвейер), руководствуясь Create your first pipeline | Microsoft Learn; Настроить в политике защиты выбранных ветвей (например, текущей и релизной) запуск валидационного конвейера, руководствуясь Git branch policies and settings | Microsoft Learn; Инструкция на wiki с порядком действия разработчика в случае выявления секретов; Инструкция для безопасника по обработке ошибочных сработок. Далее рассмотрим этапы подробнее. Для начала создадим отдельный репозиторий, например, с названием Gitleaks-PR. Поместим YML-файл pipeline.yml в репозиторий, файл будет шаблоном задач в валидационной сборке — набор задач по поиску секретов в исходном коде. Пример YML (pipeline.yml):  Предварительно потребуется создать группу переменных с названием GitleaksVariables с персональным токеном, используя который бот будет работать с API Azure DevOps Server. Запускаем Gitleaks, получает отчет с секретами и сохраняем отчет в файл. Данную работу выполняет Gitleaks.ps1:  Вот так выглядит лог данного шага в валидационной сборке: Сохраненный отчет публикуется в результаты конвейера для истории:  Ознакомиться с полным отчетом можно в артефактах валидационной сборки: Полученный отчет Gitleaks необходимо считать и принять решение о возможности успешного завершения валидационной сборки. Данный этап самый вариативный в зависимости от принятой методологии обработки уязвимостей. На данном этапе можно не только принять решение, но и: Оставить комментарий к запросу на вытягивание с полезной информацией; Передать во внешнюю систему информацию о найденной уязвимости, например, сгенерировать фичу на устранение уязвимости или отправить данные в SIEM; Уведомить ответственных за репозиторий по почте или в мессенджере о сработке; Автоматически проанализировать сработку и принять решение основываясь не на простом факте наличия сработки (возможно ошибочной), но и автоматизировано её обработать; Запустить иной конвейер, например, выполняющий незамедлительное удаление секрета из ветви, в которой выявлен секрет. Пример такого этапа:  Вот так выглядит лог данного шага в валидационной сборке: Как видим, разработчику приводится общая информация о том, что ему делать дальше, также разработчик может развернуть список с найденными секретами в маскированном виде: По сути, всё что требуется, это запустить Gitleaks и сохранить отчет Gitleaks в папку. Скрипт, выполняющий запуск Gitleaks, может быть таким:  Скрипт, выполняющий принятие решения, может быть любым и соответствовать принятому процессу по обработке уязвимостей в компании. Допустим, что принята следующая логика: Найден секрет — завершить валидационную сборку с ошибкой; Репозиторий может быть внесен в исключения — валидационная сборка завершается успешно с ошибкой, но не блокируется слияние ветвей. Добавляется комментарий к запросу на вытягивание с полезной информацией; При отсутствии секретов во вносимом коде — валидационная сборка успешно завершается. Попробуем описать такую логику:  Рассмотрим визуальную составляющую возможных вариантов проверки вносимого кода на наличие секретов для разработчика. Найден секрет либо найдена ошибочная сработка, это приводит к неуспешному выполнению валидационной сборки: При этом завершить запрос на слияние не удастся: Допустим, что во вносимом коде найден секрет либо найдена ошибочная сработка, но сам репозиторий в конфигурационном файле внесен в исключения: На изображении выше замазаны наименования проектов Azure Devops, под каждый проект делается свой файл с исключениями. Пример конфигурационного файла по умолчанию (gitleaks-default.json): Валидационная сборка будет успешно завершена с предупреждением: Сам же запрос на вытягивание выглядит довольно мирно: Как указано ранее, на этапе принятия решения можно выполнять дополнительные действия, например, чтобы стимулировать разработчиков избавляться от секретов в исходном коде, к запросу на вытягивание можно добавлять комментарий. Текст комментария может быть любым, например, таким: Как видно, комментарий содержит: Уведомление о проблеме; Ссылку на wiki с описанием действий разработчика в случае появления такого комментария. Для удобства разработчика из отчета Gitleaks можно достать номер строки из feature-ветви в которой найдена сработка и в тексте комментария добавить гиперссылку прямо на исходный код с секретом. В случае, если для защищаемой ветви дополнительно настроен параметр «Проверка разрешения комментария»: То разработчику придется выполнить управление комментарием: Поскольку теперь завершить запрос на вытягивание без обработки комментария нельзя: В дальнейшем разработчику будет проще удалить секрет из исходного кода, чем каждый раз выполнять это действие. Если по результату валидационной сборки не выявлены секреты, то результат сборки следующий: Разработчик может спокойно завершить запрос на вытягивание. Чтобы создать конвейер, который будет запускать шаблон заданий из pipeline.yml нам необходимо в каждый защищаемый репозиторий добавить YML-файл конвейер (gitleaks-pipeline.yml) который вызывает шаблон задач из pipeline.yml: Поскольку для того, чтобы в каждый репозиторий в вашем Azure DevOps Server добавить такой файл gitleaks-pipeline.yml, вам придется выполнить множество действий, рекомендуется разработать скрипты оркестрации. Примерное содержимое такого конвейера (gitleaks-pipeline.yml):  Для каждого репозитория, запросы на вытягивания в который требуется анализировать на наличие секретов, необходимо создать конвейер ссылающийся на файл gitleaks-pipeline.yml. Такой конвейер поместить в отдельную папочку, например, с названием Gitleaks: Поскольку для того, чтобы в каждый проект в вашем Azure DevOps Server добавить такой конвейер, вам придется выполнить множество действий, реккомендуется разработать скрипты оркестрации. Для того, чтобы в каждом запросе на вытягивания запускалась созданная валидационная сборка, необходимо добавить политику ссылающуюся на конвейер: Поскольку для того, чтобы на каждую выбранную ветвь каждого репозитория в вашем Azure DevOps Server назначить запуск валидационной сборки, вам придется выполнить множество действий, рекомендуется разработать скрипты оркестрации. Как мы указали ранее, в логе валидационной сборки нет смысла указывать полную инструкцию разработчику с тем, как ему завершить запрос на вытягивание при выявлении секрета. Проще разместить ссылку на wiki на FAQ: Пример такого FAQ: Каждая ошибочная сработка, каждый вопрос разработчика должны быть обработаны безопасником, поэтому без четкой и пошаговой инструкции не обойтись. Как вариант, некоторые компании для удобства дают возможность разработчикам самим вносить свои репозитории в списки исключений либо перекладывают данную активность на security champion-ов. На первый взгляд один раз запустить Gitleaks просто, другое дело встроить его в проверку основных (текущих) и релизных ветвей, и выстроить целый процесс это совсем другой — долгий, но увлекательный процесс. Итого, какие возможны проблемы при встраивании поиска секретов в запросах на вытягивание: Это долго при наличии хотя бы сотни репозиториев, требуется разработать оркестратор для встраивания; Если добавлять в репозитории gitleaks-pipeline.yml честно, через запросы на вытягивание, которые утверждаются командами разработки, то это отнимает очень много времени; Необходимо продумать схему работы разработчика над упавшей валидационной сборкой: Если завершать сборку с ошибками просто запуская Gitleaks без обработки отчета и комментирования запросов на вытягивание, то разработчик растеряется и разгневается; Разработка обработчика отнимает больше времени. Необходимо первично выполнить сканирование всех репозиториев на наличие секретов, в единый конфигурационный файл Gitleaks внести исключения, временные как-то пометить; Не все команды работают по одной методологии разработки и просто так встроить поиск секретов не удастся, например, команды работающие проектно. Если им на начале этапа утверждения требований ИБ к проекту не было заложено устранение секретов в коде, могут совсем отказать в сотрудничестве, устранение секретов в коде до конца проекта и не начнется; Необходимо иметь готовый сервис хранения секретов, например, HashiCorp Vault, иначе не получится вырезать секреты, ведь их некуда складывать, а предварительное внедрение HashiCorp Vault с правильно построенным регламентом его работы же может занять месяцы или годы; Некоторое легаси может вообще не подлежать переработке ради устранения проблемы с секретами; Специалисты по безопасности должны быть готовы ответить на любой вопрос по вопросу управления секретами; Нужен построенный процесс управления конфигурационным файлом Gitleaks для внесения в него исключений либо новых регулярных выражений для поиска неизвестных для Gitleaks секретов; Не получится встроить Gitleaks в блокирующем режиме в тех репозиториях, в которых секреты ещё не были вырезаны из кода; Помните, удаляя секрет из кода, он остается в истории и Gitleaks всё равно его найдет, поэтому следует проработать инструкцию для команд по окончательному удалению секретов из истории коммитов, см. Removing sensitive data from a repository и BFG Repo-Cleaner by Rtyley Было бы интересно узнать мнение сообщества о том: С какими трудностями столкнулись в процессе анализа запросов на вытягивание на наличие секретов; Охотно ли команды исправляют уже ранее найденные секреты. Другие мои кейсы в части безопасности разработки смотри в статьях: Дерево атак на исходный код в Azure Repos (руководство по защите от атак направленных на компрометацию исходного кода и выбору мер защиты); Шпаргалка по сегментации приложений от OWASP (автор шпаргалки); Небезопасная разработка в Github (примеры публичных ошибок разработчиков); История утечки персональных данных через Github (пример публичных ошибок одного разработчика).  Cybersecurity evangelist