Документация / Сканирование
Свой и коммерческий сканер
Radar запускает любой сканер, упакованный в образ Docker, если тот пишет отчёт в файл. Подключение состоит из двух частей:
- джоба в Radar - как запустить сканер и где взять отчёт;
- сканер в Core с импортёром - как разобрать отчёт в уязвимости.
Связывает их переменная джобы SCAN_TYPE: её значение должно точно совпадать с названием сканера в Core.
Перед началом
- Лицензия с доступом к Radar. Свой импортёр - платная функция, см. Лицензирование.
- Роль в Core: "Глобальные настройки" - "Изменение" (сканер и импортёр), "Radar" - "Изменение" (последовательность).
- Пример отчёта сканера в формате JSON.
- Образ сканера в реестре, доступном демону Docker воркера Radar.
Требования к образу
| Требование | Почему |
|---|---|
В образе есть sh |
команда джобы выполняется как sh -c "<Команда запуска>" |
ENTRYPOINT не мешает sh -c |
иначе включите в джобе "Перезаписывать Энтрипоинт Контейнера" |
Сканер читает код из /code |
это рабочий каталог джобы, туда Code Downloader клонирует репозиторий |
| Сканер работает от root | Radar запускает контейнер с user=root независимо от USER в образе |
| Образ доступен демону Docker воркера | образ скачивается перед каждым запуском. Закрытый реестр - "Настройки" → "Уч. Данные Docker" и поле "Учетные данные" в джобе |
Требования к отчёту
| Требование | Почему |
|---|---|
Файл /data/$REPORT_FILE_NAME |
воркер читает ровно этот путь. Файл в другом каталоге в Core не уйдёт |
| Имя без подкаталогов | REPORT_FILE_NAME - имя файла, а не путь |
| Один отчёт на джобу | одна джоба отправляет один файл с одним SCAN_TYPE. Несколько отчётов - несколько джоб |
| Текст в UTF-8 | Core читает файл как текст UTF-8 |
| Укладывается в 20 секунд отправки | воркер собирает файл целиком в памяти и отправляет с таймаутом 20 секунд. Radar размер не ограничивает, nginx Core принимает запрос до 4 ГБ |
Если сканер возвращает ненулевой код при найденных уязвимостях, оставьте в джобе включённым "Разрешить падение". Тогда отчёт всё равно уйдёт в Core, а пайплайн продолжится.
Подключение
1. Заведите сканер в Core
- Откройте "Глобальные настройки" → "Сканеры", вкладка "Свои сканеры".
- Нажмите "Создать сканер".
- Заполните поля:
| Поле | Что задаёт |
|---|---|
| "Название" | имя сканера. Это значение SCAN_TYPE в джобе, регистр и пробелы важны |
| "Тип сканера" | "Секреты", "SAST", "SCA", "DAST", "Инфра", "Облако" или "Не указан". Используется в метриках и фильтрах |
| "Теги" | необязательно |
API: POST /api/v1/scanners/ с полями name и scanner_type (0 - не указан, 1 - секреты, 2 - SAST, 3 - SCA, 4 - DAST, 5 - инфраструктура, 6 - облако).
2. Настройте разбор отчёта
- В карточке сканера откройте "Настройка логики разбора отчётов".
- Нажмите "Настроить свою логику разбора".
- Пройдите мастер: загрузите пример отчёта, укажите путь к списку уязвимостей и поля уязвимости. Для отчёта в формате SARIF мастер предложит "Применить стандартную структуру".
- Нажмите "Загрузить предпросмотр" и убедитесь, что уязвимости и ассеты разобраны без ошибок.
- Сохраните конфигурацию.
Подробно о мастере - Импорт отчётов. Предпросмотр через API: POST /api/v1/custom-importer/parse-report/ с полями report_config и report.
3. Создайте джобу в Radar
- В Radar откройте "Джобы" → "Создать Джобу".
- Заполните поля:
| Поле | Значение |
|---|---|
| "Имя джобы" | уникальное имя, например My Scanner |
| "Образ" | registry.example.ru/my-scanner:1.0 |
| "Команда запуска" | команда, которая пишет отчёт в /data/$REPORT_FILE_NAME |
| "Тип джобы" | "Сканнер" |
| "Переменные окружения:" | REPORT_FILE_NAME, SCAN_TYPE и переменные ассета, см. ниже |
| "Таймаут джобы (в минутах)" | с запасом к обычному времени скана |
| "Разрешить падение" | включено, если сканер возвращает ненулевой код при находках |
| "Учетные данные" | если образ в закрытом реестре |
Переменные:
| Переменная | Значение | Свойства |
|---|---|---|
REPORT_FILE_NAME |
my-scanner.json |
"Видимая" |
SCAN_TYPE |
My Scanner - название сканера в Core |
"Видимая" |
REPOSITORY |
пусто, подставит Core | "Обязательна для запуска Джобы", если сканер работает с кодом |
SEC_CODE_FOLDER |
пусто | подкаталог /code для сканирования |
| ключи и токены сканера | значения | "Скрытая" |
Ту же джобу можно загрузить файлом через "Импорт Джоб":
[
{
"name": "My Scanner",
"docker_credentials_id": null,
"user_settings": {
"image": "registry.example.ru/my-scanner:1.0",
"run_command": "my-scanner scan --source /code/$SEC_CODE_FOLDER --format json --output /data/$REPORT_FILE_NAME",
"environment_variables_dict": "[{\"name\":\"REPORT_FILE_NAME\",\"value\":\"my-scanner.json\",\"masked\":false,\"required\":false},{\"name\":\"SCAN_TYPE\",\"value\":\"My Scanner\",\"masked\":false,\"required\":false},{\"name\":\"SEC_CODE_FOLDER\",\"value\":\"\",\"masked\":false,\"required\":false},{\"name\":\"REPOSITORY\",\"value\":\"\",\"masked\":false,\"required\":true}]",
"use_pipeline_volume": false,
"type": "SCANNER",
"allow_failure": true,
"timeout": 30,
"overwrite_entrypoint": false
}
}
]
Формат импорта - Джобы и последовательности.
4. Добавьте джобу в последовательность
- В Core откройте "Radar" → "Последовательности" и выберите последовательность или создайте новую.
- Добавьте джобу: в поле "Джоб Radar" укажите имя джобы точно как в Radar.
- Для сканеров кода поставьте джобу после Code Downloader.
Если в последовательности уже есть джоба с тем же SCAN_TYPE, а у сканера включено автозакрытие, отчёты будут закрывать находки друг друга.
5. Проверьте
- Запустите аудит тестового ассета с этой последовательностью.
- В Radar откройте пайплайн и лог джобы ("Логи").
- В Core откройте аудит: у сканера появилась запись с числом добавленных находок, сами находки - в "Уязвимости".
При успешной доставке в логе джобы есть строки:
Accessing /data/my-scanner.json.
Got report file.
Using SCAN_TYPE: My Scanner as scanner_name
Portal response with code: 202
Коммерческий сканер
Коммерческий сканер подключается так же. Учтите:
- лицензионный ключ и токены сервера сканера передавайте в скрытых переменных джобы. Видимые переменные печатаются в лог;
- если скан выполняется на сервере сканера, команда джобы запускает CLI клиента: отправляет задание, ждёт результата и сохраняет отчёт в
/data. Задайте "Таймаут джобы" с учётом очереди на сервере сканера; - откройте сетевой доступ с узлов сканирования Radar к серверу сканера;
- один и тот же дефект, найденный коммерческим и открытым сканером, Core склеит, только если критерии дедупликации не учитывают сканер. По умолчанию критерий "Тот же сканер" включён, см. Дедупликация.
Диагностика
| В логе джобы | Причина | Что сделать |
|---|---|---|
Missing required variables: [...] |
пустая обязательная переменная | передайте значение или снимите обязательность |
Failed to access scanning results: docker.NotFound |
нет файла /data/$REPORT_FILE_NAME |
сверьте путь в команде с REPORT_FILE_NAME; проверьте, что сканер не упал до записи отчёта |
Portal response with code: 400 |
Core не принял запрос, чаще всего SCAN_TYPE не совпадает с названием сканера |
сверьте SCAN_TYPE с "Глобальные настройки" → "Сканеры" |
Portal response with code: 403 |
у пользователя, запустившего аудит, нет права "Уязвимости" - "Изменение" | выдайте право или запускайте от другого пользователя |
The variables required to send the report to the portal: (PORTAL_IMPORT_URL, PORTAL_TOKEN) were not provided. |
пайплайн запущен напрямую в Radar без переменных Core | запустите аудит из Core или передайте переменные, см. Запуск напрямую в Radar |
| ответ 202, но находок нет | импортёр не разобрал отчёт | проверьте конфигурацию разбора предпросмотром на реальном отчёте |
| контейнер завершается сразу с ошибкой запуска команды | в образе нет sh или ENTRYPOINT перехватывает команду |
включите "Перезаписывать Энтрипоинт Контейнера" или соберите образ с sh |