Zum Inhalt

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.

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[Mobile App]
    end

Komponenten

Receiver

  • FastAPI-Service, der Agent- und Collector-Pakete entgegennimmt
  • Authentifiziert per X-API-Key (Collector) oder X-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 mit fillfactor=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

Mobile-App

  • React Native + Expo, Android-APK
  • Eigener API-Client, Push-Token-Registration via FCM
  • Tap auf Push → Deep-Link zur Host-Detail-Seite

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

Vier 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 Rate-Limiting

Login-Endpoint und 2FA-Verify sind per IP auf 10 req/min gedeckelt (slowapi). Zweck: Brute-Force gegen schwache Passwörter und 2FA-Codes verlangsamen.

4 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.

Policies (v2)

Deklaratives Regelsystem für „auf diese Hosts diese Configs". JsonLogic-Subset, Form-Builder, AI-Generator. Macht Bulk-Konfiguration ohne SSH-Schlepperei.

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