بهرهبرداری self-host¶
تیمهایی که CVE Radar را روی سرور داخلی، Kubernetes یا Docker اجرا میکنند به چیزی فراتر از گردش کار پیشفرض مرورگر تککاربره نیاز دارند. این فصل قابلیتهای آمادهٔ production را که در همان کدبیس MIT عرضه میشوند مستند میکند: لاگ audit ساختیافته، mount فایل secret، RBAC، چندمستاجری PostgreSQL، متریک Prometheus، mirror آفلاین و کشف پشته در Kubernetes.
سطح enterprise یا قفل مجوزی وجود ندارد. متغیرهای محیط فقط رفتار عملیاتی را تنظیم میکنند (airgap، Postgres اختیاری، محافظت متریک). برای عیبیابی روز دوم و rate limit به بهرهبرداری و برای env پایه به پیکربندی مراجعه کنید.
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[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 / mirror]:::ext
API --> Notify[Slack / SMTP / webhook]:::ext
نمودار Postgres اختیاری برای چندمستاجری، scrape Prometheus روی /metrics، خطوط audit روی stdout و کانالهای اعلان پس از watch را نشان میدهد. در نصب airgap، feedهای عمومی با mirror محلی جایگزین میشوند (بخش استقرار airgap).
لاگ audit¶
CVE Radar میتواند یک خط JSON به ازای هر رویداد audit روی stdout بنویسد تا ELK، Loki، Splunk یا driver json-file در Docker آن را جذب کند. این مسیر برای تیم امنیت و پلتفرم، ردپای tamper-friendly از trigger اسکنها را بدون لاگ عنوان CVE یا secret فراهم میکند.
| action | زمان ثبت |
|---|---|
scan |
پس از هر POST /api/scan (موفق، شکست جزئی منبع، یا خطای سخت) |
watch |
پس از هر POST /api/watch |
health |
فقط وقتی AUDIT_HEALTH=true و GET /api/health?detailed=true |
export |
هنوز سمت سرور نیست (export فقط در مرورگر) |
هر خط یک شیء JSON با "audit": true است:
{
"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"
}
پشت reverse proxy مقدار TRUST_PROXY_HOPS را تنظیم کنید تا ip کلاینت واقعی باشد (مثل rate limiting). فیلتر لاگ Docker:
docker logs cve-radar 2>&1 | grep '"audit":true'
رویدادهای audit هرگز عنوان آسیبپذیری، URL webhook یا کلید API را شامل نمیشوند — فقط نام ابزار پشته و شمارش تجمیعی.
secret و کلید production¶
در توسعه میتوان از .env محلی استفاده کرد. در production secret را بهصورت فایل یا sync از vault پلتفرم mount کنید — نه در لایهٔ image و نه در Compose commitشده.
| env مستقیم | 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 |
وقتی *_FILE تنظیم است، سرور مسیر را میخواند و قبل از load شدن routeها env مستقیم را پر میکند. نمونه Docker Compose: docker-compose.secrets.example.yml.
mkdir -p secrets
printf '%s' 'your-nvd-key' > secrets/nvd_api_key.txt
chmod 600 secrets/*.txt
docker compose -f docker-compose.secrets.example.yml up -d
در Kubernetes، Secret را بهصورت فایل mount کنید و NVD_API_KEY_FILE=/etc/cve-radar-secrets/nvd_api_key بگذارید. از External Secrets Operator برای sync از Vault استفاده کنید.
RBAC و احراز هویت API¶
با تنظیم API_SECRET، همهٔ routeهای /api/* بهجز GET /api/health و GET /api/v1/health به X-Api-Key یا Authorization: Bearer نیاز دارند. روی پروسهٔ سرور API_ROLE را یکی از موارد زیر بگذارید:
| نقش | مجوزها |
|---|---|
| admin | تنظیمات، CRUD پشتهٔ tenant، scan/watch، translate، meta و history |
| scanner | scan/watch/validate، translate، meta و history |
| viewer | meta، translate، history — بدون اجرای scan |
| auditor | history/trends و meta — بدون scan یا تغییر پشته |
پیشفرض admin است. viewer با POST /api/scan 403 { "code": "FORBIDDEN" } میگیرد. برای پلتفرم مشترک RBAC را با چندمستاجری و network policy ترکیب کنید.
مرورگر میتواند VITE_API_KEY build-time مطابق API_SECRET داشته باشد — فقط برای نصب تکمستاجری مورد اعتماد.
اعلانهای watch¶
اپراتورهای self-host اغلب به هشدار out-of-band وقتی watch زمانبندیشده CVE جدید پیدا میکند نیاز دارند. CVE Radar پس از POST /api/watch با آرایهٔ غیرخالی newVulns، اعلان سمت سرور را ناهمزمان ارسال میکند — پاسخ HTTP تغییر نمیکند و dispatch handler را block نمیکند.
| کانال | 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, NOTIFICATION_SMTP_FROM, NOTIFICATION_SMTP_TO; اختیاری PORT, USER, PASS |
| webhook عمومی | NOTIFICATION_WEBHOOK_URL |
| کنترل | env | پیشفرض |
|---|---|---|
| حداقل severity | NOTIFICATION_MIN_SEVERITY یا legacy ALERT_MIN_SEVERITY |
HIGH |
| پنجره dedup (ms) | NOTIFICATION_DEDUP_MS |
900000 (۱۵ دقیقه) |
| قالب Slack | ALERT_WEBHOOK_FORMAT |
slack یا generic |
webhook تک Slack قدیمی (ALERT_WEBHOOK_URL) همچنان کار میکند — server/services/alerts.ts به NotificationService واگذار میشود. NOTIFICATION_* از mountهای *_FILE پشتیبانی میکند (مثل NVD) — یا از env پلتفرم / env file gitignoreشده استفاده کنید. بررسی: GET /api/health?detailed=true → alerts.webhookConfigured. جزئیات: اعلانها و docs/self-hosted/NOTIFICATIONS.md.
چندمستاجری (PostgreSQL)¶
جداسازی PostgreSQL اختیاری برای deploy مشترک CVE Radar است. بدون DATABASE_URL اپ تکمستاجری میماند (فقط localStorage مرورگر).
DATABASE_URL=postgres://cve_radar:cve_radar@127.0.0.1:5432/cve_radar
migrationها در اولین اتصال pool اجرا میشوند. تعریف schema در server/db/schema.ts (Drizzle ORM) برای مهاجرت تدریجی ORM است؛ queryهای runtime مربوط به tenant/stack و scan-history از Drizzle و getDb() (pool مشترک pg) استفاده میکنند. tenant default برای نصبهای موجود seed میشود. slug را در v1 بفرستید:
X-Tenant-Id: arvancloud-sre
بدون header از default استفاده میشود. routeهای کلیدی v1:
| Method | Path | توضیح |
|---|---|---|
POST |
/api/v1/tenants |
ایجاد tenant { slug, name } |
GET |
/api/v1/tenants/stacks |
لیست پشتههای tenant جاری |
POST |
/api/v1/tenants/stacks |
ایجاد پشته { name, tools, settings? } |
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 |
routeهای legacy /api/* history را زیر default ذخیره میکنند. SQL همیشه WHERE tenant_id = … دارد — tenant A به ردیف tenant B دسترسی ندارد.
متریک Prometheus و Grafana¶
متریکها در GET /metrics (مسیر root، نه زیر /api) در دسترساند.
| متغیر | پیشفرض | توضیح |
|---|---|---|
METRICS_ENABLED |
true |
false → 404 |
METRICS_PROTECT |
false |
true → نیاز به API_SECRET روی /metrics |
| متریک | نوع | برچسب | توضیح |
|---|---|---|---|
cve_radar_scans_total |
counter | mode, status |
درخواست scan/watch |
cve_radar_vulns_found |
gauge | severity, source |
از آخرین scan موفق |
cve_radar_scan_duration_seconds |
histogram | mode |
مدت handler |
cve_radar_source_reachable |
gauge | source |
دسترسی upstream |
cve_radar_cache_entries_total |
gauge | — | اندازه cache |
برای scrape در cluster، METRICS_PROTECT را خاموش بگذارید و با NetworkPolicy محدود کنید. داشبورد JSON: docs/self-hosted/grafana/cve-radar-dashboard.json.
نمونه PromQL:
sum(rate(cve_radar_scans_total{status="success"}[5m]))
/ sum(rate(cve_radar_scans_total[5m]))
استقرار airgap¶
بدون دسترسی خروجی به NVD/OSV/CISA عمومی، با mirror محلی یا پوشهٔ bulk OSV:
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) انجام میشود و API query OSV فراخوانی نمیشود.
با AIRGAPPED=true GitHub Advisories، RSS و ترجمهٔ خارجی رد میشوند. env mirror گمشده برای NVD/KEV → خطای fail-closed. وضعیت:
curl -s 'http://localhost:3001/api/health?detailed=true' | jq .airgap
برای layout mirror از scripts/sync-mirrors.sh و برای bulk OSV از scripts/sync-osv-bulk.sh در zone sync خود استفاده کنید.
کشف پشته Kubernetes¶
کشف اختیاری imageهای Deployment و نگاشت به presetها: GET /api/v1/discovery/kubernetes.
K8S_DISCOVERY_ENABLED=true
# K8S_DISCOVERY_NAMESPACES=production,staging
# K8S_KUBECONFIG=/path/to/kubeconfig
در production احراز هویت لازم است (نقش admin یا scanner). وقتی غیرفعال است 503 { "code": "K8S_DISCOVERY_DISABLED" }. نمونه پاسخ:
{
"enabled": true,
"images": ["haproxy", "nginx", "redis"],
"tools": ["HAProxy", "Nginx", "Redis"],
"unmapped": ["my-sidecar"]
}
ServiceAccount فقط list/get روی deployments — بدون secrets یا write. با جداسازی tenant روی cluster مشترک ترکیب کنید. وقتی features.k8sDiscovery در /api/capabilities true است، تب Stack میتواند ابزارهای کشفشده را import کند.
مرجع سریع¶
| موضوع | env کلیدی |
|---|---|
| Audit | AUDIT_HEALTH, TRUST_PROXY_HOPS |
| Secret | mount *_FILE |
| Auth / RBAC | API_SECRET, API_ROLE |
| اعلان | NOTIFICATION_*, legacy ALERT_WEBHOOK_URL |
| Tenant | DATABASE_URL, X-Tenant-Id |
| متریک | METRICS_ENABLED, METRICS_PROTECT |
| Airgap | AIRGAPPED, *_MIRROR_URL, OSV_BULK_PATH |
| K8s | K8S_DISCOVERY_ENABLED, K8S_DISCOVERY_NAMESPACES |
| غنیسازی | EPSS_ENABLED, COMPLIANCE_ENABLED (پیشفرض روشن) |
نسخهٔ maintainer این راهنماها در docs/self-hosted/ (انگلیسی، همتراز این فصل).
بازگشت به خانه · قبلی: بهرهبرداری