Обнаружение секретов в 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» указан сканируемый проект или его группа.

Включение сканирования

Чтобы включить сканирование в редакторе политик:

  1. В проекте или группе выберите «Безопасность» → «Политики».
  2. Нажмите «Новая политика».
  3. На экране «Выберите тип политики» выберите «Политика выполнения сканирования».
  4. Назовите политику. Новая политика уже содержит это сканирование: раздел «Обнаружение секретов (встроенный Gitleaks)» в блоке «Сканирования безопасности» раскрыт, флажок «Включить этот сканер» установлен. Если флажок снят, установите его.
  5. Настройте группы раздела, как описано в разделе Что задаёт политика.
  6. Нажмите «Настройка с запросом на слияние».

Это откроет запрос на слияние в проекте политик. Если проект политик ещё не привязан, редактор сначала создаст и привяжет его. Политика вступит в силу после того, как этот запрос на слияние будет принят.

Вместо этого действие можно добавить прямо в файл .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_.

Чтобы дать сканированию доступ к закрытому хранилищу образов:

  1. В сканируемом проекте или его группе создайте две переменные CI/CD типа «Переменная (по умолчанию)»: одну с логином, другую с паролем или токеном. Включите маскирование для переменной с паролем. Пароль не может содержать " или \.
  2. Укажите их имена в полях «Переменная логина реестра» и «Переменная пароля реестра».

Переменные читаются на стороне сканируемого проекта: групповая политика опирается на переменную группы, а переменная проекта с тем же именем занимает её место, и если её значение неверно, загрузка образа завершается с ошибкой. Учётные данные получает только 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 самого сканируемого проекта не могут его переопределить. Порядок разрешения:

  1. поле «Образ сканера» самой политики, если это полная ссылка на образ: путь из двух и более частей и тег или дайджест;
  2. иначе образ, заданный в переменной окружения FE_SCANS_GITLEAKS_IMAGE сервера Deckhouse Code;
  3. иначе образ этого релиза, 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)Вкладка «Тесты» пайплайна и виджет «Сводка сканирований безопасности» запроса на слияние
Отчёт о безопасности (обнаружение секретов)Страница «Отчёт об уязвимостях»
Несоответствия, переданные в DefectDojoDefectDojo, если настроена интеграция с 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 не публикует несоответствий из неполного отчёта и завершается с ошибкой

Дополнительные ресурсы