6969d0c62e
VulnCheck - Open Source Vulnerability Management for Wazuh Features: - Vulnerability management with Wazuh integration - AI-powered CVE analysis (OpenAI, Anthropic, Google, DeepSeek, Ollama, Infomaniak) - SLA policy enforcement with automated email alerts - Automated patch verification via Wazuh Syscollector - Role-based access control (Admin, Editor, Readonly) - PDF/CSV reporting for compliance workflows - Full audit trail https://gitea.isuit.ch/vulncheck/vulncheck
16 KiB
16 KiB
VulnManager - Database Schema
Entity Relationship Diagram (ERD)
┌─────────────────┐
│ users │
├─────────────────┤
│ id (PK) │
│ username │◄────────┐
│ email │ │
│ password_hash │ │
│ role │ │
│ is_active │ │
│ is_verified │ │
│ failed_login │ │
│ created_at │ │
│ updated_at │ │
└─────────────────┘ │
│ (1:N)
│
┌───────┴──────────┐
│ audit_logs │
├──────────────────┤
│ id (PK) │
│ user_id (FK) │
│ event_type │
│ event_description│
│ ip_address │
│ user_agent │
│ resource_type │
│ resource_id │
│ old_value │
│ new_value │
│ timestamp │
└──────────────────┘
┌─────────────────────┐
│ assets │
├─────────────────────┤
│ id (PK) │◄──────────┐
│ hostname │ │
│ ip_address │ │ (1:N)
│ wazuh_agent_id │ │
│ operating_system │ │
│ os_version │ ┌─────┴──────────────┐
│ kernel_version │ │ vulnerabilities │
│ source │ ├────────────────────┤
│ status │ │ id (PK) │
│ last_scan │ │ cve_id │
│ last_seen │ │ asset_id (FK) │◄────┐
│ description │ │ cvss_score │ │
│ location │ │ cvss_vector │ │
│ owner │ │ severity │ │ (1:1)
│ created_at │ │ status │ │
│ updated_at │ │ title │ │
└─────────────────────┘ │ description │ │
│ │ package_name │ │
│ (1:N) │ package_version │ │
│ │ fixed_version │ │
└─────────┐ │ exploitable │ │
│ │ exploit_available │ │
┌─────┴──────┤ exploit_maturity │ │
│ scans ││ published_date │ │
├────────────┤│ detected_at │ │
│ id (PK) ││ patched_at │ │
│ asset_id ││ references │ │
│ scan_type ││ cwe_id │ │
│ status ││ created_at │ │
│ started_at ││ updated_at │ │
│ completed │└────────────────────┘ │
│ vuln_found │ │
│ vuln_new │ │
│ vuln_resolv│ │
│ error_msg │ ┌───────────────────┘
│ created_at │ │
│ updated_at │ │
└────────────┘ │
┌──────┴───────────────┐
│ ai_analyses │
├──────────────────────┤
│ id (PK) │
│ vulnerability_id (FK)│
│ analysis_text │
│ threat_level │
│ exploits_found │
│ workarounds │
│ remediation_steps │
│ threat_intel_sources │
│ model_version │
│ confidence_score │
│ analysis_timestamp │
│ cache_expires_at │
│ created_at │
│ updated_at │
└──────────────────────┘
Table Details
1. users
Stores user accounts with Role-Based Access Control (RBAC).
Columns:
id(INTEGER, PK): Unique User IDusername(VARCHAR(50), UNIQUE): Login nameemail(VARCHAR(255), UNIQUE): Email addresspassword_hash(VARCHAR(255)): bcrypt hash of the passwordrole(ENUM):admin,editor,readonlyis_active(BOOLEAN): Account active/deactivatedis_verified(BOOLEAN): Email verifiedfailed_login_attempts(INTEGER): Counter for failed loginscreated_at,updated_at(TIMESTAMP): Timestamps
Indexes:
ix_users_username(UNIQUE)ix_users_email(UNIQUE)ix_users_role
Permission Hierarchy:
ADMIN
└─> All rights (User Management, Config, Delete)
EDITOR
└─> Read + Write (Change vulnerability status, create assets)
READONLY
└─> Read only (Dashboard, Reports)
2. assets
Inventory of all monitored systems (Wazuh Agents + manual entries).
Columns:
id(INTEGER, PK): Unique Asset IDhostname(VARCHAR(255)): Hostname of the systemip_address(VARCHAR(45)): IPv4/IPv6 addresswazuh_agent_id(VARCHAR(10), UNIQUE): Wazuh Agent ID (e.g., "001")operating_system(VARCHAR(255)): OS Name (e.g., "Ubuntu 22.04")os_version(VARCHAR(100)): Versionkernel_version(VARCHAR(100)): Kernel Versionsource(ENUM):wazuh,manualstatus(ENUM):active,inactive,decommissionedlast_scan(TIMESTAMP): Last vulnerability scanlast_seen(TIMESTAMP): Last contact (for Wazuh Agents)description(TEXT): Free-text descriptionlocation(VARCHAR(255)): Physical locationowner(VARCHAR(255)): Responsible person/teamcreated_at,updated_at(TIMESTAMP): Timestamps
Indexes:
ix_assets_hostnameix_assets_ip_addressix_assets_wazuh_agent_id(UNIQUE)ix_assets_sourceix_assets_status
Use Cases:
- Wazuh Agents are automatically added upon the first scan
- Manual assets for systems without an agent (e.g., network hardware)
last_seenfor health monitoring (Alert if agent > 24h offline)
3. vulnerabilities
Central table for all detected security vulnerabilities.
Columns:
id(INTEGER, PK): Unique Vulnerability IDcve_id(VARCHAR(20)): CVE identifier (e.g., "CVE-2024-1234")asset_id(INTEGER, FK → assets.id): Affected systemcvss_score(FLOAT): CVSS Score (0.0-10.0)cvss_vector(VARCHAR(100)): CVSS Vector Stringseverity(ENUM):critical,high,medium,low,nonestatus(ENUM):open,patched,pending_verification,patch_failed,accepted_risk,false_positivetitle(VARCHAR(500)): Short descriptiondescription(TEXT): Detailed descriptionpackage_name(VARCHAR(255)): Affected software packagepackage_version(VARCHAR(100)): Installed versionfixed_version(VARCHAR(100)): Version with fixexploitable(BOOLEAN): Potentially exploitableexploit_available(BOOLEAN): Public exploit availableexploit_maturity(VARCHAR(50)):poc,functional,highpublished_date(TIMESTAMP): CVE publication datedetected_at(TIMESTAMP): First detectedpatched_at(TIMESTAMP): Marked as patchedreferences(TEXT): JSON array with URLs (NVD, Vendor Advisories)cwe_id(VARCHAR(20)): CWE identifier (e.g., "CWE-79")created_at,updated_at(TIMESTAMP): Timestamps
Indexes:
ix_vulnerabilities_cve_idix_vulnerabilities_asset_idix_vulnerabilities_cvss_scoreix_vulnerabilities_severityix_vulnerabilities_statusix_vulnerabilities_package_nameix_vulnerabilities_exploitableix_vulnerabilities_detected_atidx_vuln_status_severity(Composite)idx_vuln_asset_status(Composite)
Severity Mapping (based on CVSS):
CRITICAL → 9.0-10.0
HIGH → 7.0-8.9
MEDIUM → 4.0-6.9
LOW → 0.1-3.9
NONE → 0.0
Priority Score Calculation:
Priority = (CVSS × 5) + (Exploitability × 30) + (Age × 20)
= 0-50 points + 0-30 points + 0-20 points
= 0-100 points
Exploitability:
- Exploit available: 30 points
- Exploitable: 15 points
- No info: 0 points
Age:
- Linearly increasing: 0-20 points (0 days = 0, 30+ days = 20)
4. scans
History of all performed vulnerability scans.
Columns:
id(INTEGER, PK): Unique Scan IDasset_id(INTEGER, FK → assets.id): Scanned assetscan_type(ENUM):full,syscollector,manualstatus(ENUM):pending,running,completed,failedstarted_at(TIMESTAMP): Scan startcompleted_at(TIMESTAMP): Scan endvulnerabilities_found(INTEGER): Number of vulnerabilities foundvulnerabilities_new(INTEGER): New vulnerabilities since last scanvulnerabilities_resolved(INTEGER): Resolved vulnerabilitieserror_message(TEXT): Error message if status = failedcreated_at,updated_at(TIMESTAMP): Timestamps
Indexes:
ix_scans_asset_idix_scans_status
Scan Types:
full: Complete Wazuh scan (all packages)syscollector: Syscollector rescan after patchmanual: Manually triggered (e.g., after system update)
5. ai_analyses
Cached AI analyses of CVEs (Infomaniak AI API).
Columns:
id(INTEGER, PK): Unique Analysis IDvulnerability_id(INTEGER, FK → vulnerabilities.id, UNIQUE): 1:1 Relationshipanalysis_text(TEXT): Full LLM Output (Markdown)threat_level(VARCHAR(20)):low,medium,high,criticalexploits_found(TEXT): JSON array with exploit linksworkarounds(TEXT): JSON array with temporary fixesremediation_steps(TEXT): JSON array with step-by-step instructionsthreat_intel_sources(TEXT): JSON array with Threat Intel URLsmodel_version(VARCHAR(50)): LLM Model (e.g., "gpt-4o")confidence_score(VARCHAR(20)):low,medium,highanalysis_timestamp(TIMESTAMP): Time of analysiscache_expires_at(TIMESTAMP): Cache expiration (24h TTL)created_at,updated_at(TIMESTAMP): Timestamps
Indexes:
ix_ai_analyses_vulnerability_id(UNIQUE)
Cache Strategy:
TTL: 24 hours
- After expiration: New API call on next request
- On CVE update (e.g., new exploit): Invalidate cache
6. audit_logs
Audit trail for security and compliance requirements.
Columns:
id(INTEGER, PK): Unique Log IDuser_id(INTEGER, FK → users.id, NULLABLE): User (NULL for system events)event_type(ENUM): See Event Types belowevent_description(VARCHAR(500)): Human-readable descriptionip_address(VARCHAR(45)): Client IPuser_agent(VARCHAR(500)): Browser/Client Inforesource_type(VARCHAR(50)): e.g., "vulnerability", "asset"resource_id(VARCHAR(50)): ID of the affected resourceold_value(TEXT): JSON with old values (for diffs)new_value(TEXT): JSON with new valuestimestamp(TIMESTAMP): Event time
Indexes:
ix_audit_logs_user_idix_audit_logs_event_typeix_audit_logs_timestamp
Event Types:
Authentication:
login_success: Successful loginlogin_failed: Failed login (Rate-Limiting trigger)logout: Logoutpassword_change: Password changed
Authorization:
access_denied: Access denied (403)permission_escalation: Role changed (Admin action)
Data Operations:
vulnerability_status_change: Status changed (e.g., open → patched)asset_created: New asset addedasset_updated: Asset data updatedasset_deleted: Asset deleted
Scans:
scan_triggered: Scan startedscan_completed: Scan completed
AI:
ai_analysis_requested: AI analysis requested
System:
config_change: Configuration changedsecurity_alert: Security alert (e.g., Critical CVE)
Retention Policy:
Standard: 90 days
Critical Events (security_alert, access_denied): 1 year
Compliance: Adjustable per GDPR/HIPAA/SOC2
Constraints and Foreign Keys
-- Foreign Key Constraints
ALTER TABLE vulnerabilities
ADD CONSTRAINT fk_vulnerability_asset
FOREIGN KEY (asset_id) REFERENCES assets(id)
ON DELETE CASCADE;
ALTER TABLE scans
ADD CONSTRAINT fk_scan_asset
FOREIGN KEY (asset_id) REFERENCES assets(id)
ON DELETE CASCADE;
ALTER TABLE ai_analyses
ADD CONSTRAINT fk_ai_analysis_vulnerability
FOREIGN KEY (vulnerability_id) REFERENCES vulnerabilities(id)
ON DELETE CASCADE;
ALTER TABLE audit_logs
ADD CONSTRAINT fk_audit_log_user
FOREIGN KEY (user_id) REFERENCES users(id)
ON DELETE SET NULL; -- Logs remain when user is deleted
Migration Commands
run initial Migration
# Create migration (autogenerate)
alembic revision --autogenerate -m "Initial schema"
# Apply migration
alembic upgrade head
# Revert migration
alembic downgrade -1
# Show current state
alembic current
Seed Data (Create Admin User)
from app.models.user import User, UserRole
from app.database import SessionLocal
from passlib.hash import bcrypt
db = SessionLocal()
admin = User(
username="admin",
email="admin@vulnmanager.local",
password_hash=bcrypt.hash("changeme"),
role=UserRole.ADMIN,
is_active=True,
is_verified=True
)
db.add(admin)
db.commit()
Performance Optimizations
1. Partitioning (for large datasets)
-- Partition vulnerabilities by status
CREATE TABLE vulnerabilities_open PARTITION OF vulnerabilities
FOR VALUES IN ('open', 'pending_verification');
CREATE TABLE vulnerabilities_closed PARTITION OF vulnerabilities
FOR VALUES IN ('patched', 'patch_failed', 'accepted_risk', 'false_positive');
2. Materialized Views for Dashboard
CREATE MATERIALIZED VIEW dashboard_stats AS
SELECT
COUNT(*) FILTER (WHERE status = 'open') AS open_vulnerabilities,
COUNT(*) FILTER (WHERE severity = 'critical') AS critical_count,
AVG(cvss_score) AS avg_cvss,
COUNT(DISTINCT asset_id) AS affected_assets
FROM vulnerabilities
WHERE status = 'open';
-- Refresh every 5 minutes via Cronjob
REFRESH MATERIALIZED VIEW dashboard_stats;
3. Read-Replica for Reports
Primary DB (Write) → Streaming Replication → Replica DB (Read-only)
└─> Dashboard Queries
Backup Strategy
# Daily Backup (every 03:00 AM)
pg_dump -Fc vulnmanager > /backups/vulnmanager_$(date +%Y%m%d).dump
# Activate Point-in-Time-Recovery
# postgresql.conf:
wal_level = replica
archive_mode = on
archive_command = 'cp %p /var/lib/postgresql/wal_archive/%f'
Retention:
- Daily backups: 7 days
- Weekly backups: 4 weeks
- Monthly backups: 12 months