SecurityFlow Кабинет лицензий , откроется в новой вкладке

Документация / Сканирование

Как работает Radar

Обновлено 20 октября 2026

Radar запускает сканеры в контейнерах Docker и отправляет их отчёты в Core. Что и когда сканировать, решает Core: он передаёт в Radar список джоб и переменные ассета. Radar исполняет джобы по очереди, доставляет отчёты и хранит логи.

Термины:

  • Джоба - шаблон запуска одного контейнера: образ, команда, переменные. Подробно - Джобы и последовательности.
  • Последовательность - упорядоченный список джоб. Хранится в Core.
  • Пайплайн - один запуск последовательности для одного ассета. В Core ему соответствует аудит.

Компоненты

Компонент Образ Что делает
Веб-интерфейс sf-radar-front nginx на порту 8080: отдаёт интерфейс, запросы /api/v1 проксирует в API Radar, порт 8090
API sf-radar-back FastAPI на порту 8090, API_WORKERS процессов uvicorn (по умолчанию 4). При старте применяет миграции БД и обновляет каталог джоб
Воркер sf-radar-worker процессы Celery: исполнитель пайплайнов, утилитарный воркер, планировщик очистки. Запускает контейнеры сканеров в демоне Docker (DOCKER_HOST, по умолчанию unix:///var/run/docker.sock). Образ собран на docker:dind и может поднять демон сам - для этого контейнеру нужен режим privileged
PostgreSQL - джобы и их настройки, пайплайны, логи завершённых джоб, статистика, токен доступа (хеш), учётные данные реестров, настройки
Брокер RabbitMQ или Redis очереди Celery
Redis - живые логи выполняющихся джоб. Нужен и при брокере RabbitMQ

Параметры окружения компонентов - на странице Параметры конфигурации.

Процессы воркера

Процесс Очередь Что делает Сколько экземпляров
Исполнитель пайплайнов pipeline_queue исполняет пайплайны один процесс - один пайплайн. Число процессов - MAX_SCALEWORKERS_COUNT, по умолчанию 2
Утилитарный воркер utils_queue останавливает джобы, отдаёт артефакты, удаляет образы, чистит тома по числу CPU контейнера (значение Celery по умолчанию)
Планировщик - раз в сутки в 00:00 UTC ставит задачу очистки строго один

Число одновременных пайплайнов равно числу процессов исполнителя на всех воркерах. Отдельного ограничения сверх этого нет. Состояние видно в Radar: "Настройки" → "Воркеры" и строка "Активные Воркеры:" / "Активные Потоки:" на экране "Пайплайны".

Фоновые проверки API

Если API задан ACCESS_TOKEN, он сам вызывает две служебные задачи:

  • раз в 10 секунд - проверку таймаутов джоб и пайплайнов;
  • раз в час - сбор статистики времени выполнения джоб.

Без ACCESS_TOKEN таймауты не работают

Если ACCESS_TOKEN не задан, джобы и пайплайны не прерываются по таймауту, а оценка длительности не обновляется. Значение должно совпадать с действующим токеном доступа Radar. Если джобы не прерываются по таймауту, сверьте ACCESS_TOKEN с токеном доступа и перезапустите API.

Путь скана

  1. Core формирует по пайплайну на каждый ассет: имя - название последовательности, джобы - в порядке последовательности, переменные - адрес приёма отчётов, токен, ассет, ветка, номер аудита. Ассеты уходят в Radar пачками до 100 запросом POST /api/v1/pipelines/bulk-run/.
  2. Radar создаёт пайплайн в статусе "В ожидании" и ставит задачу в очередь pipeline_queue. Core получает ответ 202.
  3. Свободный процесс исполнителя берёт пайплайн, проверяет доступ к API Radar (GET /api/v1/auth-health-check/) и переводит пайплайн в "Выполняется".
  4. Джобы идут строго по порядку, по одной. Для каждой воркер создаёт том джобы, скачивает образ и запускает контейнер.
  5. Когда джоба типа "Сканнер" завершилась, воркер читает её отчёт и отправляет в Core. Отчёт уходит сразу после своей джобы, не дожидаясь остальных.
  6. Лог джобы переносится из Redis в PostgreSQL.
  7. Если ни одна джоба не остановила пайплайн, он получает статус "Завершен".

Core разбирает отчёт асинхронно. Статус "Завершен" в Radar значит, что Core принял отчёты, а не что находки уже созданы.

Проверяйте связь с Radar

Если Radar недоступен или отклонил запрос, ошибка записывается в журнал воркера Core, а аудит остаётся без находок. Перед запуском проверяйте связь: в Core "Radar" → "Настройки", блок "Статус подключения".

Как исполняется контейнер

Параметр Значение
Команда sh -c "<Команда запуска>" - в образе нужен sh
ENTRYPOINT из образа; пустой, если включено "Перезаписывать Энтрипоинт Контейнера"
Рабочий каталог /code
Тома том джобы → /data, том пайплайна → /code
Пользователь root, даже если в образе задан другой USER
Сеть host - сеть демона Docker, в котором запущен сканер
Возможности ядра добавлена CAP_NET_RAW, режима privileged нет
DNS серверы из "Настройки" → "DNS"
Переменные переменные джобы и переменные пайплайна
Лимиты CPU и памяти не задаются
Образ скачивается перед каждым запуском джобы; при заданных "Учетные данные" перед этим выполняется вход в реестр

После завершения контейнер удаляется, тома остаются.

Изоляция сканеров

Контейнер сканера работает от root, в сети демона Docker и без лимитов ресурсов. Все переменные пайплайна, включая скрытые (токен Core, SSH-ключ, пароль реестра), доступны каждой джобе. Запускайте Radar на выделенном демоне Docker и выделенных узлах, ограничивайте ресурсы на уровне пода или узла и включайте в последовательности только образы, которым доверяете.

Тома и рабочие каталоги

Каталог в контейнере Том Время жизни Что там
/code pipeline_volume-<uuid> - общий том пайплайна весь пайплайн и дальше до очистки код из Code Downloader и артефакты джоб с включённым копированием
/data <Имя_джобы>-<uuid> - том джобы до очистки; удаляется сразу, если включено копирование отчёт сканера /data/$REPORT_FILE_NAME
  • Том пайплайна монтируется в /code каждой джобе. Code Downloader клонирует репозиторий прямо в /code, поэтому код видят все следующие джобы.
  • Флаг джобы "Копировать артефакты в следующие джобы из дирректории {directory}" после её завершения копирует содержимое /data в /code. Так джоба передаёт файлы следующим.
  • Отчёт должен лежать в /data. Файл в /code в Core не уходит.

Тома удаляет ежедневная очистка: всё старше "Дней хранить артефакты до очистки" (по умолчанию 1). Настройка - на странице Настройки Radar.

Очистка затрагивает весь демон Docker

Очистка удаляет все неиспользуемые тома демона Docker старше заданного срока, а не только тома Radar. Не запускайте сканеры на демоне, где хранятся тома других приложений.

Доставка отчёта в Core

Отчёт отправляется, если джоба имеет тип "Сканнер" и завершилась без ошибки воркера. Ненулевой код выхода сканера при включённом "Разрешить падение" отправке не мешает.

  1. Воркер запускает служебный контейнер из UTILITY_IMAGE (по умолчанию alpine) с томом джобы и читает /data/$REPORT_FILE_NAME частями по 10 МБ. Файл целиком собирается в памяти воркера.
  2. Если PORTAL_IMPORT_URL или PORTAL_TOKEN не заданы, воркер пишет об этом в лог и пропускает отправку. Джоба завершается успешно.
  3. Воркер отправляет POST $PORTAL_IMPORT_URL в формате multipart/form-data: файл file и метаданные из переменных пайплайна. Заголовок - Authorization: Token $PORTAL_TOKEN.
  4. Таймаут запроса - 20 секунд. Сертификат Core проверяется, если воркеру не задан HTTP_SSL_SKIP_VERIFY.
  5. Ответ не 202 - джоба получает статус "Джоба остановлена".
Поле запроса Откуда Что значит в Core
scanner_name SCAN_TYPE имя сканера и его импортёр. Допустимы только имена из списка сканеров Core
product_name, product_type PRODUCT_NAME, PRODUCT_TYPE продукт
repository, docker_image, domain, host, cloud_account REPOSITORY, DOCKER_IMAGE, DOMAIN, HOST, CLOUD_ACCOUNT ассеты
branch BRANCH ветка находок
docker_image_tag DOCKER_IMAGE_TAG тег образа
audit_id AUDIT_ID аудит, к которому относится отчёт

Адрес и токен подставляет Core:

  • адрес - "Внутренний URL приложения" + api/v1/scan/import/ ("Глобальные настройки" → "Рабочий процесс"). Он должен открываться из сети, где работают контейнеры сканеров;
  • токен - API-токен пользователя, запустившего аудит. Для расписания - автора расписания, для вебхуков систем контроля версий и реестров - автора интеграции. Если токена нет, Core создаёт его. У этого пользователя должно быть право "Уязвимости" - "Изменение", иначе Core отклонит отчёт с кодом 403 и джоба будет остановлена.

Поля запроса и ответы приёма отчётов - на странице Загрузка отчётов из CI.

Статусы

Значение API Пайплайн Джоба
PENDING "В ожидании" "Джоба в ожидании"
IN_PROGRESS "Выполняется" "Джоба выполняется"
FINISHED "Завершен" "Джоба завершена"
KILLED "Остановлен" "Джоба остановлена"
TIMED_OUT "Тайм-аут" "Джоба прервана по тайм-ауту"

Джоба получает "Джоба остановлена", если:

  • контейнер вернул ненулевой код и у джобы выключено "Разрешить падение";
  • не задана обязательная переменная (в логе Missing required variables: [...]);
  • у джобы-сканера нет файла отчёта в /data;
  • Core не принял отчёт.

Остановленная или прерванная по таймауту джоба с выключенным "Разрешить падение" останавливает весь пайплайн. Следующие джобы не запускаются.

При включённом "Разрешить падение" ненулевой код выхода статус не меняет: джоба получает "Джоба завершена", а джоба-сканер всё равно отправляет отчёт. Причину смотрите в логе джобы.

Таймауты

Таймаут Где задаётся Единица 0 Как срабатывает
Джобы поле джобы "Таймаут джобы (в минутах)" минуты без таймаута отсчёт от старта джобы; по истечении контейнер останавливается, статус "Джоба прервана по тайм-ауту"
Пайплайна "Настройки" → "Таймаут Пайплайнов" минуты без таймаута (значение по умолчанию) отсчёт от старта пайплайна
Проверка таймаутов API Radar раз в 10 секунд - работает только при заданном ACCESS_TOKEN
Отправка отчёта в Core воркер 20 секунд - ответ не получен - джоба остановлена

Наблюдение и управление

Экран "Пайплайны":

  • фильтры "Статус", "Джоба", "Аудит", "Аудит из списка" и "Поиск" - по тексту логов джоб;
  • колонки "Имя", "Статус", "Прогресс", "Оценка", "Дата Запуска", "Дата Завершения", "Аудит";
  • кнопки "Логи", "Скачать Артефакты", "Остановить Джобу", "Остановить Пайплайн", "Остановить все пайплайны".

"Оценка" - ожидаемая длительность: сумма средних времён джоб за последние сутки.

Логи:

  • выполняющейся джобы - из Redis, завершённой - из PostgreSQL;
  • в начале лога печатаются видимые переменные джобы целиком, значения скрытых заменяются на ***MASKED***;
  • лог живёт столько же, сколько пайплайн: "Дней хранить пайплайны до очистки", по умолчанию 1 день.

Секреты - только в скрытых переменных

Видимая переменная попадает в лог. Не передавайте токен в URL репозитория: для доступа к репозиториям используйте SSH-ключ из настроек Radar в Core.

"Скачать Артефакты" отдаёт tar-архив тома джобы. Если у джобы включено копирование артефактов - архив тома пайплайна.

"Остановить все пайплайны" переводит ожидающие пайплайны в "Остановлен", очищает очередь и останавливает выполняющиеся. Кнопка останавливает все сканы, в том числе запущенные из Core другими пользователями.

Перезапуск

Перезапуск API Radar прерывает сканы

При каждом старте sf-radar-back останавливает все пайплайны в статусах "В ожидании" и "Выполняется" и очищает очередь. Обновляйте и перезапускайте API, когда на экране "Пайплайны" нет активных сканов. Прерванные аудиты запустите заново из Core.

При старте API также:

  • применяет миграции БД (alembic upgrade head);
  • создаёт недостающие стандартные джобы каталога и обновляет их "Настройки Поставщика";
  • записывает хеш токена из ACCESS_TOKEN, если токена в БД ещё нет.

Порядок первичной настройки

Создайте токен доступа до того, как добавлять свои джобы: пока токена в БД нет, API при старте пересоздаёт каталог джоб из поставки. Как создать токен - Настройки Radar.

API Radar

  • Аутентификация - общий токен доступа Radar в заголовке Authorization: Bearer <токен>. Пользователей и ролей в Radar нет.
  • Описание API: /api/v1/docs (Swagger), /api/v1/redoc, схема - /api/v1/openapi.json.
  • Проверка живости без токена: GET /api/v1/health-check/ → {"is_healthy": true}.
  • Core обращается к API Radar сам и проксирует его для своего интерфейса через /api/v1/ci/proxy/<путь>.

Куда дальше