Architektur¶
Übersicht¶
Vesana ist ein push-basiertes Monitoring-System: Agents und Collectors verbinden sich von außen zum Server und schicken Check-Ergebnisse rein. Der Server hat keine ausgehende Verbindung zu den überwachten Maschinen.
Drei Monitoring-Modi¶
Jeder Check läuft in genau einem von drei Modi (check_mode). Alle drei führen denselben Check-Code aus — ein SNMP- oder HTTP-Check liefert das gleiche Ergebnis, egal wer ihn ausführt. Nur der Ausführer unterscheidet sich:
| Modus | Ausführer | Typischer Einsatz |
|---|---|---|
| passive | Collector (Linux-VM im Kundennetz) | SNMP, Ping, SSH, HTTP gegen Geräte ohne eigenen Agent |
| agent | Agent (Go-Binary direkt auf der Zielmaschine) | CPU/RAM/Disk/Services auf Windows- und Linux-Servern |
| active | Aktiver Collector (Server prüft selbst) | Kein Collector im Kundennetz vorhanden oder gewünscht |
Mix pro Host ist normal, nicht die Ausnahme. Ein Host kann gleichzeitig Agent-Checks (lokale CPU-Last) und passive SNMP-Checks über einen Collector haben, oder SNMP-Checks, die mangels Collector auf active laufen. check_mode ist eine Eigenschaft des einzelnen Checks (host_services.check_mode), nicht des Hosts — deshalb lässt sich pro Check frei wählen, wer ihn ausführt, solange die Capabilities passen (siehe Profile & Checks → Capabilities filtern Check-Typen).
Fehlt für einen als „passive" angelegten Check ein Collector, fällt er automatisch auf active zurück, statt unausführbar zu bleiben — kein Check geht dadurch verloren.
flowchart LR
subgraph "Im Kundennetz"
A[Agent auf Servern] -->|HTTPS POST| EXIT[outbound 443]
C[Collector VM] -->|HTTPS POST| EXIT
end
subgraph "Vesana-Server"
EXIT --> R[Receiver]
R --> RS[(Redis Stream)]
RS --> W1[Worker 0]
RS --> W2[Worker 1]
RS --> W3[Worker N]
W1 --> DB[(Postgres + TimescaleDB)]
W2 --> DB
W3 --> DB
DB --> API[REST API]
API --> FE[React Frontend]
API --> M[Installierte Web-App / Browser]
end
Komponenten¶
Receiver¶
- FastAPI-Service, der Agent- und Collector-Pakete entgegennimmt
- Authentifiziert per
X-API-Key(Collector) oderX-Agent-Token(Agent) - Validiert das Schema, schreibt sofort in den Redis Stream — keine Logik, kein DB-Zugriff
- Ziel: möglichst kurze Latenz, möglichst hohe Durchsatzrate
Redis Stream¶
- Backpressure-fähige Eingangs-Queue (
XADD/XREADGROUP) - Mehrere Worker konsumieren parallel
- Bei vollem Stream lehnt der Receiver ab (
noeviction-Policy) — kein stilles Drop
Worker¶
- Liest Messages, holt Host-/Service-Kontext aus der DB
- Wendet Profile-Check-Effective-Config an, normalisiert Werte
- Schreibt Check-Ergebnisse in
check_results(Hypertable) - Aktualisiert
current_status(Hot-Table mitfillfactor=80) - Triggert Alert-Auswertung, Notification-Versand, AI-Analyse-Cache-Invalidierung
API¶
- FastAPI mit JWT-Auth, Tenant-Scope automatisch über ORM-Filter
- Endpoints: Hosts, Services, Profile, Discoveries, Alerts, Reports, Wiki, AI, Admin
- Background-Tasks: Downtime-Watcher, Dead-Collector-Watcher, Anomaly-Baselines, Auto-Purge, Tester-Phone-Home
- Distributed Locking via Redis — bei mehreren API-Replicas läuft jeder Watcher nur einmal
Frontend¶
- React 18 + TypeScript + Vite
- Themed via CSS-Variablen (20 Themes × dark/light)
- Lazy-Loaded ECharts für Charts, Lazy-Loaded ReactMarkdown für Wiki
Agent (Go)¶
- Single-Binary, statisch gelinkt (
CGO_ENABLED=0), ~6.5 MB - Holt Config alle 5 Minuten, führt Checks lokal aus
- Auto-Update beim Config-Refresh wenn Server eine neuere Version meldet
Collector (Go)¶
- Single-Binary, läuft im Kundennetz auf einer Linux-VM
- Führt Remote-Checks aus: SNMP, Ping, SSH, HTTP, Discovery (nmap)
- Holt Config alle 60 Sekunden, schickt Ergebnisse + Discovery-Resultate an Server
Aktiver Collector (Go)¶
- Dasselbe Collector-Binary, aber als systemd-Service (
vesana-active-collector) direkt auf der Vesana-Maschine - Führt
check_mode='active'-Checks tenant-übergreifend aus — server-global, max. eine Instanz pro Vesana-Installation - Sinnvoll, wenn kein Collector im Kundennetz betrieben werden soll oder ein passiver Check mangels Collector sonst gar nicht liefe
- Ist der Aktive Collector offline, springt ein Python-Hybrid-Fallback im Worker ein — Checks bleiben lauffähig, nur langsamer
Smartphone (installierbare Web-App)¶
- Keine native App mehr: Vesana wird als Web-App auf den Startbildschirm gelegt (Android, iPhone, iPad)
- Push nach dem Browser-Standard Web Push (VAPID) — jede Instanz erzeugt ihr Schlüsselpaar selbst, kein Google-/Apple-Konto nötig
- Tipp auf eine Push-Meldung → Host-Detail-Seite mit geöffnetem Check
Multi-Tenant-Isolation¶
Tenants sind die zentrale Trennlinie. Jede DB-Tabelle mit Kunden-Daten hat eine tenant_id-Spalte. Auf ORM-Ebene erzwingt apply_tenant_filter() (api/app/auth.py) die Filterung — wer eine Query ohne Tenant-Scope absetzt, kriegt einen Runtime-Error.
Super-Admins haben Tenant-Scope null und sehen alles. Normale Nutzer sind an einen Tenant gebunden, mit optionalem Cross-Tenant-Read in Custom-Roles.
flowchart TB
subgraph Super-Admin
SA[user.tenant_scope = null] --> ALLES[(alle Tenants)]
end
subgraph Tenant A
UA[user.tenant_id = A] --> A[(Hosts/Alerts A)]
end
subgraph Tenant B
UB[user.tenant_id = B] --> B[(Hosts/Alerts B)]
end
Sicherheits-Architektur¶
Acht Säulen:
1 Verschlüsselung sensibler Felder¶
shared/encryption.py bietet encrypt_field() / decrypt_field() (AES-256-GCM). Verschlüsselt werden u. a. SNMP-Communities, SSH-Passwörter. Schlüssel: FIELD_ENCRYPTION_KEY (Base64url, 32 Bytes). Der Server hält Plaintext nur kurz im RAM.
Details: Sicherheit → Verschlüsselung.
2 Token-basierte Authentifizierung¶
| Token | Format | Speicherung | Wer benutzt |
|---|---|---|---|
| User-JWT | RS256 | Browser/Mobile lokal | Endbenutzer-Login |
| Agent-Token | vesana_agent_ + 32 url-safe Base64 |
SHA256-Hash in agent_tokens.token_hash |
Agent zum Receiver |
| API-Key | Custom-Prefix + 32 Bytes | SHA256-Hash in api_keys.key_hash |
Collector zum Receiver |
Plaintext wird nie in der DB gespeichert — nur Hashes. Keys sind genau einmal sichtbar (beim Erzeugen).
3 Zwei-Faktor-Authentifizierung¶
Pro User wählbar: TOTP (Authenticator-App) oder WebAuthn (Hardware-Key/Passkey). E-Mail-Codes gibt es nicht mehr. Details: Sicherheit → Härtungs-Checkliste.
4 Rate-Limiting¶
Login-Endpoint und 2FA-Verify sind per IP auf 10 req/min gedeckelt, 2FA-Resend auf 3 req/min (slowapi). Zweck: Brute-Force gegen schwache Passwörter und 2FA-Codes verlangsamen.
5 RBAC — deny-by-default¶
Jeder API-Endpunkt verlangt eine explizite Permission (host.create, alert_rule.edit, …) — ohne passende Permission gibt es 403, nicht implizites Erlauben. Vier Basis-Rollen (Super-Admin, Admin, Operator, Viewer) plus Custom-Roles mit granularer Permission-Auswahl. tenant_access steuert, ob ein User nur seinen eigenen Tenant sieht oder mehrere/alle.
6 Script-Ausführung — Apply-Scope + Sandbox¶
Script-fähige Check-Typen (agent_script, custom, ssh_script, ssh_custom) können beliebigen Code ausführen — deshalb greift ein eigener Autorisierungs-Layer: der Apply-Scope pro User (nach Tenant, Tag oder einzelnem Host), deny-by-default, Super-Admin ausgenommen. Der Check-Executor selbst läuft in einer Sandbox mit eingeschränkten Capabilities.
Details: Sicherheit → Härtungs-Checkliste.
7 Container-Isolation¶
API-, Worker-, Receiver- und AI-Service-Container laufen als non-root. Einzige Ausnahme: der Updater-Container bleibt root, weil er den Docker-Socket beschreiben muss, um Updates auszuführen.
8 Distributed Locking¶
Mehrere API-Replicas? downtime_expiry_watcher, dead_collector_watcher etc. laufen nur einmal — Redis-Locks mit 55 s Timeout sorgen dafür.
Sub-Systeme¶
Profile + Checks¶
Zweistufiges Modell. Hosts haben ein Profil (z. B. „APC Smart-UPS"). Profile haben Profile-Checks (z. B. „Battery Voltage"). host_services sind Instanzen pro Host mit optionalen Overrides.
Details: Profile & Checks.
Aggregate (K-von-N)¶
Ein Aggregat ist ein eigenständiges Objekt (kein normaler Check), das den Status einer homogenen Gruppe redundanter Mitglieder (z. B. 2 Uplinks, 3 Netzteile) read-time gegen eine Schwelle K auswertet: gesund == N → OK, K ≤ gesund < N → WARNING („Redundanz angeknabbert, läuft noch"), gesund < K → CRITICAL („Funktion verloren"). Die WARNING-Stufe unterdrückt Downstream-Abhängigkeiten bewusst nicht — erst bei echtem CRITICAL greift die normale Inhibition.
Policies¶
Deklaratives Regelsystem: Match-Bedingungen (JsonLogic-Subset) + Actions, die automatisch Tags setzen oder Checks anlegen — Bulk-Konfiguration ohne SSH-Schlepperei. Ein Form-Builder und ein AI-Generator helfen beim Formulieren der Bedingungen.
Umgesetzte Action-Typen: add_check (Check automatisch anlegen), tag_assignment (Tag automatisch setzen), config_patch (Config-Override patchen). Weitere Action-Typen sind im Schema vorgesehen, aber noch nicht umgesetzt — das UI zeigt nur implementierte Typen an, das Backend lehnt Policies ab, die ausschließlich nicht-umgesetzte Actions enthalten.
Sicherheitsnetz: Dry-Run ist vor dem Speichern Pflicht, ein Circuit-Breaker stoppt den Sync bei ungewöhnlich vielen Löschungen oder Operationen, neue Policies wenden sich standardmäßig nicht rückwirkend auf Bestandshosts an (Adoption muss explizit gewählt werden). Policies, die Scripts ausrollen würden, sind unabhängig von der sonstigen Policy-Berechtigung Super-Admin-only (siehe Säule 6 oben).
Wiki + AI¶
Eigene Wissensbasis (Markdown, FTS, pgvector). AI greift via RAG ins Wiki, fällt auf Web-Suche zurück, kennzeichnet Quellen.
Auto-Discovery¶
Collector scannt Netzwerk per nmap. SNMP-sysOID matcht auf Profile. Bei Auto-Match wird das Profil als Vorschlag übernommen.
NSCA-Empfänger¶
Optionaler Receiver auf Port 5667. Nimmt Pakete von send_nsca-Clients an. Migrations-Pfad für Nagios-Bestände.
Performance-Modell¶
Auf Self-Hosting-Defaults (1 Worker, 256 MB shared_buffers): ~960 checks/s sustained, p95 ≤ 150 ms, 0 Errors über 30-Min-Soak. Skalierungs-Hebel: Administration → Skalierung.
Anschluss¶
- Status- und State-Modell — wie Check-Ergebnisse zu Status werden
- Profile & Checks — das wichtigste Konzept
- Glossar — wenn ein Begriff unklar ist