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 Check-Auswertung
- Ziel: möglichst kurze Latenz, möglichst hohe Durchsatzrate
Redis Stream¶
- Backpressure-fähige Eingangs-Queue (
XADD/XREADGROUP) - Mehrere Worker konsumieren parallel
- Im Normalbetrieb hält der Worker den Stream kurz. Stehen die Worker länger still (Absturz, Datenbank weg), ist der Stream bei rund 100.000 Einträgen gedeckelt — darüber fallen die ältesten Einträge weg, damit Redis nicht vollläuft. Redis selbst läuft mit
noeviction: ist der Speicher voll, schlagen Schreibzugriffe fehl, statt still Daten zu verdrängen
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, Anomalien & Prognosen (Normalbereiche, Bewertung, Prognosen), Auto-Purge, Instanz-Puls, Lizenz-Abholung
- Distributed Locking via Redis — bei mehreren API-Replicas läuft jeder Watcher nur einmal
Frontend¶
- React 18 + TypeScript + Vite
- Themed via CSS-Variablen (13 Themes plus ein eigenes Theme, je hell/dunkel)
- 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 (eigener Netzwerk-Scanner)
- 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; die API filtert jede Abfrage auf die Tenants, die der Aufrufer sehen darf.
Super-Admins sehen alles. Alle anderen Konten erhalten Rechte über Rollen-Zuweisungen: Rolle × Bereich, wobei der Bereich ein Tenant, eine Tenant-Gruppe oder „alle Tenants" ist. Zuweisungen gehen an Benutzer oder an Teams. Ein Konto kann so in verschiedenen Tenants verschiedene Rollen haben — z. B. Admin bei Kunde A, nur lesen bei Kunde B. Details: Rollen.
flowchart LR
U[Benutzer] --> Z1[Zuweisung: Admin @ Tenant A]
U --> T[Team]
T --> Z2[Zuweisung: Viewer @ Tenant-Gruppe Kunden]
Z1 --> A[(Tenant A)]
Z2 --> B[(Tenant B)]
Z2 --> C[(Tenant C)]
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 |
|---|---|---|---|
| Sitzungs-Token (JWT) | HS256 | HttpOnly-Cookie im Browser | Endbenutzer-Login |
| Agent-Token | vesana_agent_ + 32 Zufallsbytes (URL-sicher) |
SHA256-Hash in agent_tokens.token_hash |
Agent zum Receiver |
| API-Key | vesana_ + 32 Zufallsbytes (URL-sicher) |
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¶
Anmeldung, 2FA-Prüfung und Identitätsbestätigung sind per IP auf 10 Anfragen/min gedeckelt, Passwort-Änderung auf 5/min. Zweck: Brute-Force gegen schwache Passwörter und 2FA-Codes verlangsamen.
5 RBAC — deny-by-default¶
Jeder API-Endpunkt verlangt eine explizite Permission (hosts.create, alert_rules.edit, …) — ohne passende Permission gibt es 403, nicht implizites Erlauben. Vier mitgelieferte Rollen (Super Admin, Admin, Operator, Viewer) plus eigene Rollen mit granularer Permission-Auswahl. Welche Rolle in welchem Tenant gilt, bestimmen die Rollen-Zuweisungen (siehe Multi-Tenant-Isolation).
6 Script-Ausführung — Apply-Scope + Sandbox¶
Script-fähige Check-Typen (agent_script, agent_custom, plugin_local, ssh_script, ssh_custom, ssh_command, api_script) 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. Wer Scripts anlegt oder deren Inhalt ändert, bestätigt zusätzlich seine Identität — auch Super-Admins. 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 primäres Profil (z. B. „APC Smart-UPS"), optional weitere. 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.
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 das Netzwerk mit seinem eigenen Scanner (ARP, ICMP, TCP, Dienst-Erkennung). SNMP-sysOID matcht auf Profile. Bei Auto-Match wird das Profil als Vorschlag übernommen.
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