Обнаружение секретов в Deckhouse Code ищет учётные данные, попавшие в собственный исходный код проекта. Для
этого используется сканер Gitleaks, сканирование называется
gitleaks_secret_detection. Сканирование обязательное: его задаёт политика выполнения сканирования в отдельном
проекте политик; файл .gitlab-ci.yml самого проекта его не добавляет. Политика решает, что приводит к ошибке
пайплайна; сканируемый проект не может изменить это в своих настройках CI/CD.
Что делает сканирование
Действие gitleaks_secret_detection добавляет в пайплайн две задачи на этапе политики — fe-security-scanner,
если в поле политики «CI-этап» не указан другой. К имени каждой задачи добавляется суффикс
:<короткое имя политики>-p<ID проекта политик>, поэтому групповая и проектная политики, которые задают одно и
то же сканирование, получают отдельные задачи.
| Задача | Что делает |
|---|---|
gitleaks_secret_scan | Запускает Gitleaks по репозиторию и публикует его JSON-вывод как артефакт |
gitleaks_secret_junit | Строит из этого JSON отчёт JUnit и отчёт о безопасности и завершает задачу с ошибкой, если несоответствие не проходит порог |
Обе задачи загружают артефакты с when: always, поэтому несоответствия, из-за которых пайплайн завершился с
ошибкой, остаются в его артефактах. gitleaks_secret_junit также сохраняет несоответствия в формате SARIF,
security-reports/sarif/gitleaks.sarif, — обычным артефактом для инструментов, которые читают этот формат.
Сканирование читает рабочую копию собираемого коммита. Коммит, который удаляет секрет, снимает несоответствие,
но секрет остаётся в истории репозитория, пока историю не перепишут. Редактор политик другого выбора не
предлагает. В политике, написанной вручную, можно задать FE_SCANS_GITLEAKS_SCOPE: history среди variables
действия, чтобы читать всю историю, и FE_SCANS_GITLEAKS_LOG_OPTS, чтобы сузить её до диапазона коммитов в
терминах git log.
Файл, хранящийся в Git LFS, сканируется по настоящему содержимому: указатель, который стоит вместо него в репозитории, не читается. Подмодуль не сканируется: читается только то, что оказалось в рабочей копии самого проекта.
Лог задачи сканирования указывает версию Gitleaks, а после завершения сканирования — сколько несоответствий
найдено, по правилам. Сканирование, которое ничего не нашло, всё равно публикует отчёт — [].
Предварительные требования
Чтобы сканирование могло запуститься, убедитесь, что:
- администратор включил флаг функций
fe_security_scan_policiesтак, как описано на странице Ранний доступ; - к проекту или к группе над ним привязан проект политик либо редактор политик создаст и привяжет его при сохранении первой политики по шагам из раздела Включение сканирования;
- доступен раннер, который выполняет задачи в образах контейнеров и может загрузить оба образа сканирования:
- образ сканера, выбранный так, как описано в разделе Откуда берётся образ сканера; для образа в закрытом хранилище образов политика называет переменные CI/CD, в которых хранятся логин и пароль, в полях переменных реестра;
- образ
gitleaks_secret_junit, по умолчаниюruby:3.3.10-slim, переопределяется переменной окружения сервераFE_SCANS_REPORT_CONVERTER_IMAGE; политика не передаёт этой задаче учётных данных хранилища образов, поэтому раннер загружает образ без них;
- проект, в котором лежит файл конфигурации или файл игнорируемых несоответствий, названный в политике, разрешает задачам сканируемого проекта читать его: в этом проекте в разделе «Настройки» → «CI/CD» → «Права доступа токена заданий CI/CD» указан сканируемый проект или его группа.
Включение сканирования
Чтобы включить сканирование в редакторе политик:
- В проекте или группе выберите «Безопасность» → «Политики».
- Нажмите «Новая политика».
- На экране «Выберите тип политики» выберите «Политика выполнения сканирования».
- Назовите политику. Новая политика уже содержит это сканирование: раздел «Обнаружение секретов (встроенный Gitleaks)» в блоке «Сканирования безопасности» раскрыт, флажок «Включить этот сканер» установлен. Если флажок снят, установите его.
- Настройте группы раздела, как описано в разделе Что задаёт политика.
- Нажмите «Настройка с запросом на слияние».
Это откроет запрос на слияние в проекте политик. Если проект политик ещё не привязан, редактор сначала создаст и привяжет его. Политика вступит в силу после того, как этот запрос на слияние будет принят.
Вместо этого действие можно добавить прямо в файл .deckhouse_code/security-policies/policy.yml в проекте
политик:
scan_execution_policy:
- name: Secret detection everywhere
enabled: true
rules:
- type: pipeline
branches: ["*"]
actions:
- scan: gitleaks_secret_detectionЧто задаёт политика
В редакторе политик сканирование gitleaks_secret_detection — это раздел «Обнаружение секретов (встроенный
Gitleaks)» в блоке «Сканирования безопасности». У раздела один флажок — «Включить этот сканер»; когда он
установлен, раздел показывает все свои группы: образ сканера, приводит ли несоответствие к ошибке пайплайна,
файл конфигурации, файл игнорируемых несоответствий и дополнительные параметры. Ниже групп — поле тегов раннера
для обеих задач сканирования с подсказкой «Теги раннера через запятую». В свёрнутом виде рядом с заголовком
раздела показано «Включён» или «Отключён».
Образ сканера
| Поле | Что задаёт |
|---|---|
| «Образ сканера» | Ссылку на образ, в котором выполняется сканирование: путь из двух и более частей и тег или дайджест |
| «Переменная логина реестра» | Имя переменной CI/CD проекта или его группы, в которой хранится логин для хранилища образов, в виде $ИМЯ или ${ИМЯ}. По умолчанию пусто |
| «Переменная пароля реестра» | Имя переменной CI/CD, в которой хранится пароль или токен для этого хранилища образов, в том же виде. По умолчанию пусто |
Если оставить «Образ сканера» пустым, сканирование выполняется в образе, на который настроен Deckhouse Code, —
он показан серым прямо в поле как подсказка; этот образ определяют шаги 2 и 3 из раздела
Откуда берётся образ сканера.
Для образа с Docker Hub адрес хранилища образов можно не указывать, как в zricethezav/gitleaks:v8.30.1.
Неполная ссылка, например из одной части gitleaks:v8.30.1, не мешает сохранить политику: задача сканирования
останавливается с this scan was not given what the policy asks for: scanner image: ….
Поля переменных нужны для образа в закрытом хранилище образов. Политика называет переменные, но не их значения.
В файле политики это FE_SCANS_REGISTRY_LOGIN_VARIABLE и FE_SCANS_REGISTRY_PASSWORD_VARIABLE среди
variables действия. Политика не сохраняется, если:
- заполнено только одно из двух полей;
- значение записано не в виде
$ИМЯили${ИМЯ}; - имя начинается с
FE_,CI_илиGITLAB_.
Чтобы дать сканированию доступ к закрытому хранилищу образов:
- В сканируемом проекте или его группе создайте две переменные CI/CD типа «Переменная (по умолчанию)»: одну с
логином, другую с паролем или токеном. Включите маскирование для переменной с паролем. Пароль не может
содержать
"или\. - Укажите их имена в полях «Переменная логина реестра» и «Переменная пароля реестра».
Переменные читаются на стороне сканируемого проекта: групповая политика опирается на переменную группы, а
переменная проекта с тем же именем занимает её место, и если её значение неверно, загрузка образа завершается
с ошибкой. Учётные данные получает только gitleaks_secret_scan, и для образа, который поставляется с
продуктом, они не используются.
Ронять пайплайн при находках
Флажок, по умолчанию установлен.
| Значение | Что делает |
|---|---|
| Установлен (по умолчанию) | Несоответствие приводит к ошибке пайплайна |
| Снят | Несоответствие всё равно попадает в отчёт и доходит до отчёта об уязвимостях; пайплайн при этом не останавливается |
В файле политики флажку соответствует FE_SECURITY_FAIL_ON: info, когда он установлен, и report_only, когда
снят.
Каждое несоответствие получает уровень CRITICAL, поэтому здесь нет порога между уровнями, как в
SAST-сканировании с помощью Opengrep: несоответствие либо приводит к ошибке пайплайна, либо нет.
Файл конфигурации
| Поле | Что задаёт |
|---|---|
| «Путь к файлу» | Путь к собственной TOML-конфигурации сканера, которую задача сканирования читает из проекта, названного рядом. По умолчанию пусто; тогда сканирование использует только конфигурацию, встроенную в образ сканера |
| «Проект» | Репозиторий, из которого читается файл, в формате группа/проект, с его ветки по умолчанию. Нужен, как только заполнен «Путь к файлу» |
В файле могут быть секция [extend], списки исключений (allowlist) отдельных правил и выключенные правила.
Набор, встроенный в образ сканера, остаётся в силе, пока файл не определит иначе; файл без секции [extend]
читается как его расширение. Секция [extend] принимается, только если в ней есть useDefault = true и, кроме
него, не более чем disabledRules. Задача останавливается до сканирования, если в [extend] есть что-то ещё,
если в файле вторая секция [extend], allowlist верхнего уровня или disabledRules вне [extend].
Задача сканирования читает файл своим токеном задачи, поэтому проект, указанный в поле «Проект», должен дать сканируемому проекту доступ, описанный в разделе Предварительные требования.
Политика сохраняется, если поле «Проект» пустое или в нём указан сам сканируемый проект, но задача сканирования
затем останавливается до сканирования. Собственный файл .gitleaks.toml сканируемого проекта сканирование не
читает, он остаётся в рабочей копии.
Файл игнорируемых находок
| Поле | Что задаёт |
|---|---|
| «Путь к файлу» | Путь к файлу с отпечатками несоответствий, по одному в строке, в том виде, в каком их печатает сканер. По умолчанию пусто; тогда не исключается ни одно несоответствие |
| «Проект» | Репозиторий, из которого читается файл, по тем же правилам, что и «Файл конфигурации» → «Проект» |
Собственный файл .gitleaksignore сканируемого проекта удаляется из рабочей копии перед сканированием, поэтому
файл, названный в этом поле, — единственное место, где несоответствие можно исключить. Комментарий
gitleaks:allow на строке секрета тоже не учитывается: сканирование передаёт флаг --ignore-gitleaks-allow,
поэтому комментарий рядом с секретом не заглушает несоответствие по нему.
Дополнительные параметры
| Поле | Что задаёт |
|---|---|
| «Дополнительные параметры» | Флаги, передаваемые сканированию как есть, для всего, чего нет в этой форме |
Примечание рядом с полем напоминает, что результаты сканирования публикуются как отчёт о безопасности, поэтому попадают в отчёт об уязвимостях и в системы, которые к нему подключил администратор.
Флаги, которые задаёт сама задача, отклоняются с указанием имени флага: те, что уводят или меняют отчёт,
подменяют конфигурацию, исключают несоответствия (--baseline-path, --ignore-gitleaks-allow, --enable-rule),
задают код выхода, маскирование, баннер, цвета или диагностику, называют коммиты для чтения (--log-opts),
переключают сканер в другой режим (--pre-commit, --staged), задают платформу для ссылок на несоответствия
(--platform) или печатают справку вместо сканирования. Уровни логирования warn, error, fatal, panic и
disabled останавливают задачу: она читает лог сканера.
Откуда берётся образ сканера
Сервер определяет образ один раз, до старта задачи, и записывает его как готовое значение: настройки CI/CD самого сканируемого проекта не могут его переопределить. Порядок разрешения:
- поле «Образ сканера» самой политики, если это полная ссылка на образ: путь из двух и более частей и тег или дайджест;
- иначе образ, заданный в переменной окружения
FE_SCANS_GITLEAKS_IMAGEсервера Deckhouse Code; - иначе образ этого релиза,
zricethezav/gitleaks:v8.30.1.
FE_SCANS_GITLEAKS_IMAGE — переменная окружения серверных процессов, которые формируют пайплайны: веб-сервера
и Sidekiq; администратор задаёт её в их окружении. Переменная CI/CD проекта или группы с тем же именем ни на что
не влияет. В файле политики поле «Образ сканера» — это ключ FE_SCANS_GITLEAKS_IMAGE в variables действия.
Заполненное поле, которое не является полной ссылкой, не откатывается к шагам 2–3 для сканирования: задача
останавливается с this scan was not given what the policy asks for: scanner image: … ещё до сканирования. Сама
задача при этом запускается в образе из шага 2 или 3, поэтому этот образ должен загружаться.
Если у Deckhouse Code нет доступа в интернет, этот образ зеркалируют в своё хранилище образов, а зеркальную
ссылку указывают в переменной окружения сервера FE_SCANS_GITLEAKS_IMAGE или в поле политики «Образ сканера».
Если хранилище образов требует входа, заполните в политике поля переменных реестра.
Куда попадают результаты
| Отчёт | Где смотреть |
|---|---|
| Тесты (JUnit) | Вкладка «Тесты» пайплайна и виджет «Сводка сканирований безопасности» запроса на слияние |
| Отчёт о безопасности (обнаружение секретов) | Страница «Отчёт об уязвимостях» |
| Несоответствия, переданные в DefectDojo | DefectDojo, если настроена интеграция с DefectDojo |
Каждый тестовый случай назван CRITICAL <правило> <описание> [<файл>:<строка>]. Описание — то, которое Gitleaks
даёт правилу; правило без описания названо своим идентификатором один раз. К повторяющемуся имени добавляется
#2, #3 и так далее. Описание несоответствия заканчивается отдельной строкой Gitleaks rule: <правило>.
Успешный тестовый случай gitleaks scan сообщает, что сканировалось (рабочая копия коммита или история), сколько
отпечатков в файле игнорируемых несоответствий политики и какие дополнительные параметры были переданы, если были.
Имя задачи несёт короткое имя политики и ID её проекта политик, и DefectDojo сверяет тесты по этому имени целиком: переименование политики или перенос в другой проект политик начинает в DefectDojo новый тест.
Диагностика
| Сообщение задачи | Что оно значит |
|---|---|
gitleaks is missing from this scan job image | В выбранном образе нет gitleaks в PATH. Проверьте раздел Откуда берётся образ сканера |
this scan was not given what the policy asks for: <detail> | Сервер отклонил часть политики ещё до старта задачи. В пояснении названо поле: scanner image (не полная ссылка), blocking (значение, отличное от info и report_only), what the scan reads (область, отличная от working_copy и history), additional arguments (флаг, который задаёт сама задача), configuration file или ignore file (путь без проекта, проект без пути либо неверно записанные путь или проект). Несколько причин разделяются точкой с запятой |
this policy names a configuration file in the project being scanned, which this scan never reads | В поле «Файл конфигурации» → «Проект» указан сам сканируемый проект. Укажите проект, в котором лежит файл |
this policy names an ignore file in the project being scanned, which is the file this scan removes from the checkout | В поле «Файл игнорируемых находок» → «Проект» указан сам сканируемый проект. Укажите проект, в котором лежит файл |
<project> does not let this project's jobs read it | Проект с файлом не указывает сканируемый проект в разделе «Настройки» → «CI/CD» → «Права доступа токена заданий CI/CD» |
<path> is not on the default branch of <project>, or that project does not exist | Путь или проект указаны неверно либо права доступа токена задач этого проекта не пускают сканируемый проект |
<path> in <project> is empty, and this policy names it | Названный файл пуст. Заполните файл или очистите поле «Путь к файлу» |
this scanner's image carries no curl, python3 or wget, so a file in another project cannot be read | В собственном образе сканера нет инструментов, которые загружают файл конфигурации или игнорируемых несоответствий |
the configuration this policy names would switch off the set this scan is for: … | Файл, названный в «Файле конфигурации», содержит конструкцию, которая заменила бы или опустошила штатный набор правил или которую сканер не прочитал бы: вторую секцию [extend], секцию или ключ allowlist верхнего уровня, ключ extend, записанный через точку, [extend] без useDefault = true или с ключом, отличным от useDefault и disabledRules, либо disabledRules вне [extend] |
the policy names rules this scanner does not have: … | Запись disabledRules в файле конфигурации называет правило, которого нет у Gitleaks |
this scan was asked to log at <level>, which is quieter than this job can read back | В «Дополнительных параметрах» задан уровень логирования warn, error, fatal, panic или disabled |
gitleaks exited with status <n>: the scan did not complete | Сам сканер завершился с ошибкой; в логе задачи есть его строки об ошибке |
gitleaks exited with status 0 but wrote no report: the scan did not run | Сканер остановился, ничего не просканировав и не вернув код ошибки. Прочитайте строки сканера в логе задачи |
ruby is missing from this converter job image | В выбранном образе конвертера нет ruby в PATH |
The scan did not run: it left no report behind (в тестовом случае gitleaks scan) | gitleaks_secret_scan завершился с ошибкой или был отменён; gitleaks_secret_junit не публикует несоответствий из неполного отчёта и завершается с ошибкой |