Skip to content

Self-host эксплуатация

Команды, развёртывающие CVE Radar на внутренних серверах, Kubernetes или Docker, нуждаются в возможностях production из той же MIT-кодовой базы: audit-логи JSON, mount секретов, RBAC, мультитenant PostgreSQL, метрики Prometheus, offline-зеркала и обнаружение стека в Kubernetes.

Enterprise-уровня и лицензионных блокировок нет. Переменные окружения меняют только операционное поведение. См. Эксплуатация и Конфигурация.

flowchart TB
  classDef ui fill:#e9edf5,stroke:#00baba,color:#253343
  classDef api fill:#f3fcfc,stroke:#008c8c,color:#253343
  classDef data fill:#fff7ed,stroke:#eda232,color:#253343
  classDef ext fill:#f5f5f5,stroke:#666,color:#253343

  subgraph deploy["Self-host развёртывание"]
    Browser[Browser SPA]:::ui
    API[Express API]:::api
    PG[(PostgreSQL опционально)]:::data
    Metrics["GET /metrics"]:::api
    Audit[stdout audit JSON]:::ext
  end

  Browser --> API
  API --> PG
  API --> Metrics
  API --> Audit
  API --> Feeds[NVD / OSV / mirrors]:::ext
  API --> Notify[Slack / SMTP / webhooks]:::ext

На схеме: опциональный Postgres, scrape Prometheus на /metrics, audit в stdout и исходящие уведомления после watch. В airgap публичные feeds заменяются локальными зеркалами (см. Airgap).

Audit-логирование

Одна JSON-строка на событие в stdout для ELK/Loki/Splunk или Docker json-file.

action Когда
scan После каждого POST /api/scan
watch После каждого POST /api/watch
health При AUDIT_HEALTH=true и detailed health
export Пока только в браузере
{
  "audit": true,
  "ts": "2026-06-06T14:30:00.000Z",
  "action": "scan",
  "ip": "10.0.0.42",
  "stack": ["redis", "nginx"],
  "duration_ms": 8420,
  "sources_failed": ["NVD"],
  "result_count": 12,
  "mode": "full"
}

TRUST_PROXY_HOPS за reverse proxy. Заголовки CVE и ключи API не логируются.

docker logs cve-radar 2>&1 | grep '"audit":true'

Секреты

env *_FILE
NVD_API_KEY NVD_API_KEY_FILE
GITHUB_TOKEN GITHUB_TOKEN_FILE
DEEPL_API_KEY DEEPL_API_KEY_FILE
ALERT_WEBHOOK_URL ALERT_WEBHOOK_URL_FILE
NOTIFICATION_SLACK_WEBHOOK_URL
NOTIFICATION_DISCORD_WEBHOOK_URL
NOTIFICATION_TELEGRAM_BOT_TOKEN
NOTIFICATION_SMTP_PASS mount через env file в Compose
API_SECRET API_SECRET_FILE

Пример Compose: docker-compose.secrets.example.yml. В Kubernetes — mount Secret как файлы.

RBAC и API

С API_SECRET все /api/* кроме GET /api/health и GET /api/v1/health требуют ключ. API_ROLE:

Роль Права
admin Настройки, tenant CRUD, scan/watch, translate, meta и history
scanner scan/watch/validate, translate, meta и history
viewer meta и history — без scan
auditor history/trends и meta — без scan

По умолчанию admin. viewer на POST /api/scan получает 403 { "code": "FORBIDDEN" }.

Уведомления watch

Self-host часто нужны out-of-band алерты при новых CVE в watch. CVE Radar отправляет уведомления асинхронно после POST /api/watch с непустым newVulns — ответ HTTP не меняется.

Канал env
Slack NOTIFICATION_SLACK_WEBHOOK_URL или legacy ALERT_WEBHOOK_URL
Discord NOTIFICATION_DISCORD_WEBHOOK_URL
Telegram NOTIFICATION_TELEGRAM_BOT_TOKEN, NOTIFICATION_TELEGRAM_CHAT_ID
SMTP NOTIFICATION_SMTP_HOST, FROM, TO; опционально PORT, USER, PASS
Webhook NOTIFICATION_WEBHOOK_URL
Параметр env По умолчанию
Мин. severity NOTIFICATION_MIN_SEVERITY / ALERT_MIN_SEVERITY HIGH
Dedup (ms) NOTIFICATION_DEDUP_MS 900000
Формат Slack ALERT_WEBHOOK_FORMAT slack / generic

Legacy ALERT_WEBHOOK_URL работает через NotificationService. NOTIFICATION_* поддерживает mounts *_FILE. Проверка: GET /api/health?detailed=truealerts.webhookConfigured. См. Оповещения и NOTIFICATIONS.md.

Мультитenant (PostgreSQL)

DATABASE_URL=postgres://cve_radar:cve_radar@127.0.0.1:5432/cve_radar

Migrations при первом подключении pool. Schema в server/db/schema.ts (Drizzle ORM) для постепенной ORM-миграции; runtime-запросы tenant/stack и scan-history используют Drizzle через getDb() (общий pool pg).

X-Tenant-Id: arvancloud-sre
Method Path Описание
POST /api/v1/tenants Создать tenant
GET /api/v1/tenants/stacks Список стеков
POST /api/v1/tenants/stacks Создать стек
GET /api/v1/tenants/stacks/:id Стек по UUID
PUT /api/v1/tenants/stacks/:id Обновить стек
DELETE /api/v1/tenants/stacks/:id Удалить стек
GET /api/v1/scans/history History tenant
GET /api/v1/scans/trends Trends tenant

History фильтруется по tenant_id. Legacy /api/* пишет в default.

Prometheus и Grafana

GET /metrics. METRICS_ENABLED (true), METRICS_PROTECT для auth.

Метрика Тип Описание
cve_radar_scans_total counter scan/watch
cve_radar_vulns_found gauge последний успешный scan
cve_radar_scan_duration_seconds histogram длительность
cve_radar_source_reachable gauge upstream
cve_radar_cache_entries_total gauge размер cache

Дашборд: docs/self-hosted/grafana/cve-radar-dashboard.json.

sum(rate(cve_radar_scans_total{status="success"}[5m]))
  / sum(rate(cve_radar_scans_total[5m]))

Airgap-развёртывание

AIRGAPPED=true
NVD_MIRROR_URL=http://internal-mirror/nvd
KEV_MIRROR_URL=http://internal-mirror/kev/catalog.json
# OSV — mirror или bulk:
OSV_MIRROR_URL=http://internal-mirror/osv
# OSV_BULK_PATH=/data/osv/extracted

С OSV_BULK_PATH OSV читается из локального JSON (scripts/sync-osv-bulk.sh / make sync-osv-bulk) без query API. GitHub/RSS/перевод отключены. Нет mirror env для NVD/KEV → fail-closed. jq .airgap на detailed health. scripts/sync-mirrors.sh, scripts/sync-osv-bulk.sh.

Kubernetes discovery

K8S_DISCOVERY_ENABLED=true
# K8S_DISCOVERY_NAMESPACES=production,staging

GET /api/v1/discovery/kubernetes — auth в production. Отключено → 503 K8S_DISCOVERY_DISABLED.

{
  "enabled": true,
  "images": ["haproxy", "nginx", "redis"],
  "tools": ["HAProxy", "Nginx", "Redis"],
  "unmapped": ["my-sidecar"]
}

SA только read на deployments. Сочетайте с tenant.

Краткий справочник

Тема env
Audit AUDIT_HEALTH, TRUST_PROXY_HOPS
Secrets *_FILE
RBAC API_SECRET, API_ROLE
Уведомления NOTIFICATION_*, ALERT_WEBHOOK_URL
Tenant DATABASE_URL, X-Tenant-Id
Metrics METRICS_ENABLED, METRICS_PROTECT
Airgap AIRGAPPED, *_MIRROR_URL, OSV_BULK_PATH
K8s K8S_DISCOVERY_ENABLED, K8S_DISCOVERY_NAMESPACES
Enrichment EPSS_ENABLED, COMPLIANCE_ENABLED

Maintainer-копии: docs/self-hosted/.

Домой · Назад: Эксплуатация