diff --git a/README.md b/README.md index 6b951c7..056f042 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,17 @@ Client ──► Backend:ProxyPort ──► WebSocket (Binary) ──► Agent - Mehrere gleichzeitige Verbindungen pro Tunnel moeglich - Tunnel bleiben offen wenn einzelne Sessions beendet werden -## Agent-Faehigkeiten (Status: Implementiert) +## Komponenten + +| Komponente | Beschreibung | Dokumentation | +|------------|-------------|---------------| +| **Backend** | REST API, WebSocket Hub, Tunnel Manager, PostgreSQL + TimescaleDB | [docs/BACKEND.md](docs/BACKEND.md) | +| **Agent** | Collectors, WebSocket Client, Command Handler, Tunnel Manager | [docs/AGENT.md](docs/AGENT.md) | +| **Frontend** | React + Vite + TailwindCSS Web-Frontend | [docs/FRONTEND.md](docs/FRONTEND.md) | +| **API** | Vollstaendige REST API mit allen Endpoints | [docs/API.md](docs/API.md) | +| **Firmware** | Multi-Plattform Firmware-Verwaltung und Update-Prozess | [docs/FIRMWARE.md](docs/FIRMWARE.md) | + +## Agent-Faehigkeiten ### Datensammlung (automatisch bei jedem Heartbeat, alle 60s) @@ -54,42 +64,49 @@ Client ──► Backend:ProxyPort ──► WebSocket (Binary) ──► Agent ### Remote-Commands (via WebSocket, on-demand) -| Command | API-Endpoint | Beschreibung | -|---------|-------------|-------------| -| `exec` | `POST /agents/{id}/exec` | Beliebigen Shell-Befehl ausfuehren | -| `backup` | `POST /agents/{id}/backup` | Config-Backup (`/conf/config.xml`) erstellen | -| `update_check` | `POST /agents/{id}/update-check` | Verfuegbare Updates pruefen | -| `update` | `POST /agents/{id}/update` | Normales Update (Core + Packages, opt. Reboot) | -| `major_update` | `POST /agents/{id}/major-update` | Major-Upgrade (2-Phasen: Base/Kernel → Reboot → Packages) | -| `reboot` | `POST /agents/{id}/reboot` | Reboot mit konfigurierbarer Verzoegerung | -| `wg_add_peer` | `POST /agents/{id}/wireguard/peers` | WireGuard-Peer anlegen (Keypair + Config) | -| `wg_list_peers` | `GET /agents/{id}/wireguard/peers` | Alle Peers einer WG-Instanz auflisten | -| `wg_delete_peer` | `DELETE /agents/{id}/wireguard/peers/{uuid}` | WireGuard-Peer loeschen | -| `tunnel_connect` | `POST /agents/{id}/tunnel` | TCP-Tunnel zu lokalem Dienst oeffnen | -| `tunnel_disconnect` | `DELETE /agents/{id}/tunnel/{tid}` | Tunnel schliessen | -| `agent_update` | `POST /agents/{id}/agent-update` | Agent-Binary remote aktualisieren (via WebSocket, Legacy) | +| Command | Beschreibung | +|---------|-------------| +| `exec` | Beliebigen Shell-Befehl ausfuehren | +| `backup` | Config-Backup (`/conf/config.xml`) erstellen | +| `update_check` | Verfuegbare Updates pruefen | +| `update` | Normales Update (Core + Packages, opt. Reboot) | +| `major_update` | Major-Upgrade (2-Phasen: Base/Kernel → Reboot → Packages) | +| `reboot` | Reboot mit konfigurierbarer Verzoegerung | +| `wg_add_peer` | WireGuard-Peer anlegen (Keypair + Config) | +| `wg_list_peers` | Alle Peers einer WG-Instanz auflisten | +| `wg_delete_peer` | WireGuard-Peer loeschen | +| `tunnel_connect` | TCP-Tunnel zu lokalem Dienst oeffnen | +| `tunnel_disconnect` | Tunnel schliessen | +| `agent_update` | Agent-Binary remote aktualisieren (Legacy) | -### Registrierte Agents +## Features (v1.0.3) -| Agent-ID | Name | IP | Rolle | -|----------|------|-----|-------| -| `6beb8dfd...` | OPN-PROD.intra.weidenhaupt.net | 192.168.85.1 | Produktion (READ-ONLY) | -| `e92e87a6...` | OPN-REP.intra.weidenhaupt.net | 192.168.85.33 | Test/Replikation | -| `1697d28e...` | OPN-TEST-UPDATE | 192.168.85.19 | Update-Tests | +### OPNsense Plugin WebGUI Fix +- **Config-Parsing**: Korrektes Parsen von `rmmagent[general][KEY]` Formular-Feldern (OPNsense MVC-Konvention) +- **Initialer config.xml Eintrag**: Automatisches Anlegen des `` Knotens beim ersten Speichern -## Komponenten +### Pre-Registration von Firewalls +- Firewalls vorab registrieren bevor der Agent installiert wird (`POST /api/v1/agents`) +- Automatisches Matching bei Agent-Registration nach Name wenn `hostname="(ausstehend)"` +- Frontend: "Firewall hinzufuegen" Dialog mit Installationsanleitung und Copy-Buttons -### Agent (FreeBSD/OPNsense) -- **Collectors**: Hardware, CPU, Memory, Disk, Network, Services, WireGuard, DHCP (KEA/ISC/dnsmasq), Routing, Gateways, Zertifikate, Plugins, Updates -- **WebSocket Client**: Persistente Verbindung zum Backend, automatisches Reconnect mit Backoff -- **Command Handler**: Remote-Befehlsausfuehrung, Tunnel-Connect/Disconnect -- **Tunnel Manager**: Session-basierte TCP-Verbindungen zu lokalen Diensten +### Service-Filter +- Boot/Init-Scripts (`bgfsck`, `cleanvar`, `dmesg`, etc.) werden gefiltert — nur echte OPNsense-Dienste +- `pluginctl` mit vollem Pfad `/usr/local/sbin/pluginctl` -### Backend (Linux) -- **REST API**: Agent-Registrierung, Heartbeat, Systemdaten, Tunnel-Management -- **WebSocket Hub**: Verwaltet Agent-Verbindungen, routet Commands und Binary-Messages -- **Tunnel Manager**: Proxy-Listener, Session-Tracking, Ready-Handshake -- **PostgreSQL + TimescaleDB**: Relationale Daten + Time-Series Metriken +### OPNsense Business Edition Lizenz-Anzeige +- Product Name, Subscription Key, Ablaufdatum im Uebersicht-Tab +- Restlaufzeit mit visuellem Farbbalken (gruen/gelb/rot) + +### Firmware Management +- Multi-Platform Upload (FreeBSD, Linux, Windows) +- Agent-Update per Button (einzeln oder alle) +- Siehe [docs/FIRMWARE.md](docs/FIRMWARE.md) + +### Frontend +- Firewall loeschen (Papierkorb-Icon im AgentPanel) +- Agent-Tab mit Version, Update-Button und Remote-Befehlen +- Siehe [docs/FRONTEND.md](docs/FRONTEND.md) ## Voraussetzungen @@ -97,724 +114,15 @@ Client ──► Backend:ProxyPort ──► WebSocket (Binary) ──► Agent - **Backend-Server**: Linux (Debian 12+), PostgreSQL 17+, TimescaleDB 2.x - **Agent-Ziel**: OPNsense / FreeBSD (amd64) -## Installation (Backend) - -### 1. PostgreSQL + TimescaleDB installieren +## Schnellstart ```bash -# Debian 12+ (Bookworm/Trixie) -apt install -y postgresql postgresql-client - -# TimescaleDB Repository hinzufuegen -echo "deb https://packagecloud.io/timescale/timescaledb/debian/ bookworm main" \ - > /etc/apt/sources.list.d/timescaledb.list -curl -L https://packagecloud.io/timescale/timescaledb/gpgkey | gpg --dearmor \ - > /etc/apt/trusted.gpg.d/timescaledb.gpg -apt update - -# TimescaleDB passend zur PG-Version installieren (z.B. PG 17) -apt install -y timescaledb-2-postgresql-17 - -# TimescaleDB in postgresql.conf aktivieren -echo "shared_preload_libraries = 'timescaledb'" >> /etc/postgresql/17/main/conf.d/timescaledb.conf -systemctl restart postgresql +make all # Backend + Agent + Updater bauen +make certs # TLS-Zertifikate generieren +make deploy-backend # Backend deployen ``` -### 2. Datenbank und User anlegen - -```bash -sudo -u postgres psql < /etc/systemd/system/rmm-backend.service << EOF -[Unit] -Description=RMM Backend -After=network.target postgresql.service - -[Service] -Type=simple -WorkingDirectory=/opt/rmm -ExecStart=/opt/rmm/rmm-backend /opt/rmm/config.yaml -Restart=always -RestartSec=5 - -[Install] -WantedBy=multi-user.target -EOF' - -ssh root@BACKEND_IP "systemctl daemon-reload && systemctl enable rmm-backend && systemctl start rmm-backend" -``` - -Oder per Makefile: `make deploy-backend` - -### 7. Starten und verifizieren - -```bash -# Status pruefen -systemctl status rmm-backend - -# Log pruefen -journalctl -u rmm-backend -f - -# API testen -curl -sk -H "X-API-Key: DEIN_API_KEY" https://BACKEND_IP:8443/api/v1/agents -``` - -Beim ersten Start: -- Tabellen `agents`, `system_data`, `config_backups`, `agent_events` werden automatisch angelegt -- Hypertable `metrics` wird erstellt (TimescaleDB) -- Retention Policy (90 Tage) und Compression Policy (nach 7 Tagen) werden automatisch gesetzt - -### 8. Datenbank-Schema (automatisch) - -Das Backend erstellt folgendes Schema bei erstem Start: - -| Tabelle | Typ | Beschreibung | -|---------|-----|-------------| -| `agents` | Relational | Agent-Registry (ID, Name, Hostname, IP, Version, Heartbeat, customer_id, update_requested) | -| `system_data` | Relational | Letzte Systemdaten pro Agent (JSONB) | -| `config_backups` | Relational | OPNsense Config-Backups (dedupliziert per SHA256) | -| `agent_events` | Relational | Online/Offline/Connected Events | -| `customers` | Relational | Kundenstammdaten (Nummer, Name) | -| `users` | Relational | Benutzer (Username, bcrypt-Hash, Display-Name) | -| `agent_firmware` | Relational | Agent-Binaries pro Plattform+Version (BYTEA, SHA256) | -| `metrics` | TimescaleDB Hypertable | Time-Series Metriken (CPU, RAM, Disk, Network, Gateway) | - -TimescaleDB Policies: -- **Retention**: Rohdaten werden nach 90 Tagen automatisch geloescht -- **Compression**: Daten aelter als 7 Tage werden komprimiert (segmentby: agent_id+metric) - -## Installation (Agent / OPNsense) - -Der Agent wird als OPNsense-Plugin installiert — mit WebGUI-Konfiguration unter **Services > RMM Agent**. - -### 1. Agent bauen - -```bash -make agent # Erzeugt build/rmm-agent (freebsd/amd64) -``` - -### 2. Plugin installieren - -```bash -# Binary + Installer auf die Firewall kopieren -scp build/rmm-agent root@OPNSENSE:/tmp/ -scp opnsense-plugin/install.sh root@OPNSENSE:/tmp/ - -# Installer ausfuehren -ssh root@OPNSENSE '/bin/sh /tmp/install.sh' -``` - -Der Installer richtet alles ein: -- Binary nach `/usr/local/rmm/rmm-agent` -- rc.d Service (`/usr/local/etc/rc.d/rmm_agent`) -- OPNsense MVC Plugin (Model, Controller, View) -- configd Actions (start/stop/restart/status/reconfigure) -- Plugin-Hook fuer Service-Integration -- Setup-Script das Config aus dem Model generiert - -### 3. WebGUI konfigurieren - -1. OPNsense WebGUI oeffnen -2. **Services > RMM Agent** -3. Felder ausfuellen: - - **Aktiviert**: Ankreuzen - - **Backend URL**: `https://BACKEND_IP:8443` - - **API Key**: Backend API-Key eintragen - - **Agent Name**: Optional (Standard: Hostname) - - **Heartbeat Intervall**: 60 (Sekunden) - - **Self-Signed Zertifikate**: Ankreuzen bei self-signed Backend-Certs -4. **Speichern & Anwenden** klicken - -Der Agent startet automatisch und meldet sich am Backend an. - -### 4. Verifizieren - -```bash -# Status in der WebGUI: Badge zeigt "Running" - -# Oder per SSH: -ssh root@OPNSENSE 'service rmm_agent status' - -# Auf dem Backend: Agent sollte erscheinen -curl -sk -H "X-API-Key: DEIN_API_KEY" https://BACKEND_IP:8443/api/v1/agents -``` - -### Agent-Update (via Updater — empfohlen) - -Der **rmm-updater** ist ein separater Daemon, der auf jeder Firewall neben dem Agent laeuft. -Er prueft alle 60 Sekunden ob ein Update ansteht und fuehrt es automatisch durch. - -**Flow:** -1. Neue Agent-Binary im Frontend hochladen (Firmware-Seite) -2. Update-Button bei einzelnem Agent oder "Alle updaten" klicken -3. Updater erkennt den Flag, laedt die Binary vom Backend, stoppt Agent, ersetzt Binary, startet Agent -4. Flag wird automatisch zurueckgesetzt - -**Technische Details:** -- Separates Go-Binary (`rmm-updater`), laeuft als `rmm_updater` rc.d Service -- Liest die gleiche `config.yaml` wie der Agent (Backend-URL, API-Key) -- Download ueber `GET /api/v1/firmware/download?platform=freebsd` -- SHA256-Verifizierung vor Ersetzung -- Automatisches Rollback bei fehlgeschlagenem Agent-Start -- Backup der alten Binary als `.bak` waehrend des Updates -- Logs: `/var/log/rmm-updater.log` - -**Manuelles Update (Fallback):** - -```bash -make agent -scp build/rmm-agent root@OPNSENSE:/tmp/ -ssh root@OPNSENSE '/bin/sh -c "service rmm_agent stop; cp /tmp/rmm-agent /usr/local/rmm/rmm-agent; chmod +x /usr/local/rmm/rmm-agent; service rmm_agent start"' -``` - -Oder Plugin komplett neu installieren (`install.sh` ist idempotent — installiert Agent + Updater). - -### Hinweise - -- **Agent-ID** wird persistent in `/usr/local/rmm/agent_id` gespeichert — ueberlebt Neuinstallationen -- **Config** wird bei "Speichern & Anwenden" aus dem OPNsense-Model nach `/usr/local/rmm/config.yaml` generiert -- **Logs**: `/var/log/rmm-agent.log` -- **PID-File**: `/var/run/rmm_agent.pid` - -## API - -### Agent-Management - -| Methode | Endpoint | Beschreibung | -|---------|----------|-------------| -| POST | `/api/v1/agent/register` | Agent registrieren (mit optionaler `agent_id`) | -| POST | `/api/v1/agent/heartbeat` | Systemdaten senden | -| POST | `/api/v1/agents` | Firewall pre-registrieren (`{name, customer_id?}`) | -| GET | `/api/v1/agents` | Alle Agents auflisten | -| GET | `/api/v1/agents/{id}` | Agent + Systemdaten abrufen | -| GET | `/api/v1/agents/{id}/system` | Nur Systemdaten | -| DELETE | `/api/v1/agents/{id}` | Agent loeschen | - -### Agent-Status - -Status wird automatisch aus `last_heartbeat` berechnet (kein DB-Feld): - -| Status | Bedingung | -|--------|-----------| -| `online` | Heartbeat < 2 Minuten | -| `stale` | Heartbeat < 5 Minuten | -| `offline` | Heartbeat > 5 Minuten | -| `unknown` | Kein Heartbeat vorhanden | - -`GET /agents` liefert ein `status` Feld pro Agent, `GET /agents/{id}` ebenfalls. - -### Authentifizierung - -Das Backend unterstuetzt zwei Auth-Methoden (CombinedAuth Middleware): -- **API-Key** (Header `X-API-Key`): Fuer Agents und automatisierte Zugriffe -- **JWT Bearer Token** (Header `Authorization: Bearer `): Fuer Frontend-Benutzer - -| Methode | Endpoint | Beschreibung | -|---------|----------|-------------| -| POST | `/api/v1/auth/login` | Login (username + password → JWT Token, 8h Ablauf) | -| GET | `/api/v1/auth/me` | Eigene Benutzerdaten | - -Default-Admin wird automatisch beim ersten Start erstellt: `admin` / `Start!123` (min. 6 Zeichen). - -### Kunden (Customers) - -| Methode | Endpoint | Beschreibung | -|---------|----------|-------------| -| GET | `/api/v1/customers` | Alle Kunden auflisten | -| POST | `/api/v1/customers` | Neuen Kunden anlegen (`{number, name}`) | -| GET | `/api/v1/customers/{id}` | Einzelnen Kunden abrufen | -| PUT | `/api/v1/customers/{id}` | Kunden aktualisieren | -| DELETE | `/api/v1/customers/{id}` | Kunden loeschen | -| GET | `/api/v1/customers/{id}/agents` | Agents eines Kunden | -| PUT | `/api/v1/agents/{id}/customer` | Agent einem Kunden zuordnen | -| DELETE | `/api/v1/agents/{id}/customer` | Kundenzuordnung entfernen | - -### Benutzer (Users) - -| Methode | Endpoint | Beschreibung | -|---------|----------|-------------| -| GET | `/api/v1/users` | Alle Benutzer auflisten | -| POST | `/api/v1/users` | Neuen Benutzer anlegen | -| PUT | `/api/v1/users/{id}/password` | Passwort aendern (min. 6 Zeichen) | -| DELETE | `/api/v1/users/{id}` | Benutzer loeschen | - -### Firmware / Agent-Update - -Multi-Plattform Firmware-Verwaltung (freebsd, linux, windows): - -| Methode | Endpoint | Beschreibung | -|---------|----------|-------------| -| GET | `/api/v1/firmware` | Alle Firmware-Versionen (pro Plattform) | -| GET | `/api/v1/firmware?platform=freebsd` | Firmware einer Plattform | -| POST | `/api/v1/firmware/upload?version=X&platform=Y` | Binary hochladen (Body = Raw Binary) | -| GET | `/api/v1/firmware/download?platform=Y` | Binary herunterladen (fuer Updater) | -| POST | `/api/v1/agents/{id}/request-update` | Update-Flag setzen (Updater fuehrt aus) | -| DELETE | `/api/v1/agents/{id}/request-update` | Update-Flag zuruecksetzen | -| POST | `/api/v1/agents/request-update-all` | Update-Flag fuer alle Agents setzen | -| POST | `/api/v1/agents/{id}/agent-update` | Legacy: Binary direkt via WebSocket pushen | - -**Firmware-Upload Beispiel:** -```bash -# FreeBSD Agent hochladen -curl -sk -X POST "https://192.168.85.13:8443/api/v1/firmware/upload?version=1.0.2&platform=freebsd" \ - -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \ - --data-binary @build/rmm-agent - -# Linux Agent hochladen -curl -sk -X POST "https://192.168.85.13:8443/api/v1/firmware/upload?version=1.0.2&platform=linux" \ - -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \ - --data-binary @build/rmm-agent-linux - -# Update fuer einzelnen Agent anfordern -curl -sk -X POST "https://192.168.85.13:8443/api/v1/agents/e92e87a6.../request-update" \ - -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" - -# Update fuer alle Agents anfordern -curl -sk -X POST "https://192.168.85.13:8443/api/v1/agents/request-update-all" \ - -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" -``` - -### Agent-Events - -| Methode | Endpoint | Beschreibung | -|---------|----------|-------------| -| GET | `/api/v1/agents/events` | Alle Events (`?limit=N&type=X`) | -| GET | `/api/v1/agents/{id}/events` | Events eines Agents (`?limit=N&type=X`) | - -Event-Typen: `online`, `offline`, `stale`, `connected`, `disconnected` - -Events werden automatisch geschrieben bei: -- WebSocket Connect/Disconnect (`connected`/`disconnected`) -- Inaktivitaets-Monitor erkennt Statuswechsel (`online`/`stale`/`offline`) - -```bash -# Alle Events (letzte 10) -curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \ - "https://192.168.85.13:8443/api/v1/agents/events?limit=10" - -# Nur Offline-Events eines Agents -curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \ - "https://192.168.85.13:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/events?type=offline" -``` - -### WebSocket - -| Methode | Endpoint | Beschreibung | -|---------|----------|-------------| -| GET | `/api/v1/agent/ws?agent_id=X&api_key=X` | WebSocket-Verbindung (Agent) | -| GET | `/api/v1/hub/status` | Hub-Status (connected agents, aktive Tunnel) | - -### Updates & Reboot - -| Methode | Endpoint | Beschreibung | -|---------|----------|-------------| -| POST | `/api/v1/agents/{id}/update-check` | Verfuegbare Updates pruefen | -| POST | `/api/v1/agents/{id}/update` | Normales Update (Core + Packages) | -| POST | `/api/v1/agents/{id}/major-update` | Major-Upgrade auf Zielversion | -| POST | `/api/v1/agents/{id}/reboot` | Reboot ausfuehren | - -### Metriken (TimescaleDB) - -| Methode | Endpoint | Beschreibung | -|---------|----------|-------------| -| GET | `/api/v1/agents/{id}/metrics` | Rohe Metriken abfragen (`?metric=X&from=&to=&limit=N`) | -| GET | `/api/v1/agents/{id}/metrics/summary` | Aggregierte Metriken (`?metric=X&bucket=5+minutes&from=&to=`) | - -Metriken werden automatisch bei jedem Heartbeat geschrieben (alle 60s): -`cpu_usage`, `memory_used_percent`, `memory_used_bytes`, `memory_total_bytes`, -`uptime_seconds`, `disk_used_percent`, `disk_used_bytes`, `interface_rx_bytes`, -`interface_tx_bytes`, `gateway_rtt_ms`, `gateway_loss_percent` - -Retention: 90 Tage (Raw), Compression nach 7 Tagen. - -### Config-Backup - -| Methode | Endpoint | Beschreibung | -|---------|----------|-------------| -| POST | `/api/v1/agents/{id}/backup` | Backup jetzt ausloesen (via WebSocket) | -| GET | `/api/v1/agents/{id}/backups` | Alle Backups auflisten (`?limit=N`) | -| GET | `/api/v1/agents/{id}/backups/{id\|latest}` | Backup herunterladen (`?format=xml` fuer Raw-XML) | -| DELETE | `/api/v1/agents/{id}/backups/{id}` | Einzelnes Backup loeschen | -| GET | `/api/v1/agents/{id}/backups/diff?a={id}&b={id}` | Zeilenweises Diff zwischen zwei Backups | - -Backups werden dedupliziert: gleicher SHA256-Hash = kein neuer Eintrag. -Config-XML wird Base64-kodiert vom Agent zum Backend uebertragen und als Klartext in PostgreSQL gespeichert. - -### Tunnel-Management - -| Methode | Endpoint | Beschreibung | -|---------|----------|-------------| -| POST | `/api/v1/agents/{id}/tunnel` | Tunnel oeffnen | -| GET | `/api/v1/agents/{id}/tunnels` | Aktive Tunnel auflisten | -| DELETE | `/api/v1/agents/{id}/tunnel/{tid}` | Tunnel schliessen | -| POST | `/api/v1/agents/{id}/exec` | Remote-Command ausfuehren | - -### Tunnel-Beispiele - -```bash -# SSH-Tunnel zur OPNsense -curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" -X POST \ - https://192.168.85.13:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/tunnel \ - -d '{"target_host":"127.0.0.1","target_port":22}' - -# Response: {"tunnel_id":"xxx","proxy_port":10000,...} -# Verbinden: -ssh -p 10000 root@192.168.85.13 - -# WebGUI-Tunnel (OPNsense auf Port 4444) -curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" -X POST \ - https://192.168.85.13:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/tunnel \ - -d '{"target_host":"127.0.0.1","target_port":4444}' - -# Response: {"tunnel_id":"xxx","proxy_port":10001,...} -# Im Browser: https://192.168.85.13:10001/ - -# Aktive Tunnel auflisten -curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \ - https://192.168.85.13:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/tunnels - -# Tunnel schliessen -curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" -X DELETE \ - https://192.168.85.13:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/tunnel/TUNNEL_ID -``` - -### Zugangsdaten - -``` -Backend: https://192.168.85.13:8443 -API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9 - -Agent-IDs: - 6beb8dfd38ecf03eab6c0f21b4ac7bee OPN-PROD.intra.weidenhaupt.net (192.168.85.1, READ-ONLY) - e92e87a684b20db15d8d2344583c5887 OPN-REP.intra.weidenhaupt.net (192.168.85.33) - 1697d28e57bc126534afc282b5de8ee0 OPN-TEST-UPDATE (192.168.85.19) -``` - -### Agent-Beispiele - -```bash -# Alle Agents auflisten (ID, Name, IP, Version, letzter Heartbeat) -curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \ - https://192.168.85.13:8443/api/v1/agents - -# Einzelner Agent mit Systemdaten -curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \ - https://192.168.85.13:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887 - -# Nur Systemdaten (Hardware, CPU, RAM, Disks, Services, etc.) -curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \ - https://192.168.85.13:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/system - -# Agent loeschen -curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" -X DELETE \ - https://192.168.85.13:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887 - -# Hub-Status (verbundene Agents, aktive Tunnel) -curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \ - https://192.168.85.13:8443/api/v1/hub/status - -# Remote-Command ausfuehren -curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" -X POST \ - https://192.168.85.13:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/exec \ - -d '{"command":"uptime","timeout":30}' -``` - -### WireGuard-Peer Management - -| Methode | Endpoint | Beschreibung | -|---------|----------|-------------| -| POST | `/api/v1/agents/{id}/wireguard/peers` | Neuen Peer anlegen | -| GET | `/api/v1/agents/{id}/wireguard/peers` | Alle Peers auflisten (`?server_name=X`) | -| DELETE | `/api/v1/agents/{id}/wireguard/peers/{uuid}` | Peer loeschen | - -**Peer anlegen — Parameter:** - -| Parameter | Pflicht | Default | Beschreibung | -|-----------|---------|---------|-------------| -| `name` | Ja | — | Peer-Name (z.B. "VPN_MUELLER") | -| `allowed_ips` | Nein | `0.0.0.0/0` | AllowedIPs fuer Client-Config | -| `dns` | Nein | — | DNS-Server fuer Client-Config | -| `server_name` | Nein | `ALWAYSON_VPN` | Name der WG-Server-Instanz | -| `endpoint` | Nein | WAN-IP:Port | Oeffentlicher Endpoint (Auto-Detect ueber Default-Route) | - -**Ablauf beim Anlegen:** -1. Keypair wird auf der Firewall generiert (`wg genkey`/`wg pubkey`) -2. Naechste freie IP aus dem Tunnel-Subnetz wird automatisch vergeben -3. Peer wird in `config.xml` eingetragen und dem Server zugewiesen -4. `configctl wireguard configure` laedt die Aenderung -5. Response enthaelt die komplette Client-Config (ready for import) - -**Beispiele:** - -```bash -# Peer anlegen (erster Peer bekommt .2, zweiter .3, etc.) -curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" -X POST \ - https://192.168.85.13:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/wireguard/peers \ - -d '{"name":"VPN_MUELLER","allowed_ips":"0.0.0.0/0","dns":"10.172.100.210"}' - -# Response: -# { -# "status": "ok", -# "data": { -# "peer_uuid": "abc123...", -# "name": "VPN_MUELLER", -# "client_ip": "10.33.144.2", -# "endpoint": "79.238.149.26:8080", -# "client_config": "[Interface]\nPrivateKey = ...\nAddress = 10.33.144.2/32\n..." -# } -# } - -# Zweiten Peer anlegen (bekommt automatisch .3) -curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" -X POST \ - https://192.168.85.13:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/wireguard/peers \ - -d '{"name":"VPN_SCHMIDT","allowed_ips":"0.0.0.0/0","dns":"10.172.100.210"}' - -# Peer mit eigenem Endpoint (z.B. DynDNS) -curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" -X POST \ - https://192.168.85.13:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/wireguard/peers \ - -d '{"name":"VPN_EXTERN","allowed_ips":"0.0.0.0/0","endpoint":"vpn.kunde.de:8080"}' - -# Alle Peers auflisten -curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \ - https://192.168.85.13:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/wireguard/peers - -# Peers einer bestimmten Instanz auflisten -curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \ - "https://192.168.85.13:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/wireguard/peers?server_name=ALWAYSON_VPN" - -# Peer loeschen (UUID aus der List-Response) -curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" -X DELETE \ - https://192.168.85.13:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/wireguard/peers/89c10e2d-148e-11f1-a7af-7c5a1c6c7b73 -``` - -### Metriken-Beispiele - -```bash -# CPU-Auslastung der letzten 24h -curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \ - "https://192.168.85.13:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/metrics?metric=cpu_usage" - -# RAM-Nutzung mit Zeitraum -curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \ - "https://192.168.85.13:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/metrics?metric=memory_used_percent&from=2026-02-28T00:00:00Z&to=2026-02-28T23:59:59Z" - -# 5-Minuten-Durchschnitte der CPU -curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \ - "https://192.168.85.13:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/metrics/summary?metric=cpu_usage&bucket=5+minutes" - -# Stuendliche RAM-Zusammenfassung -curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \ - "https://192.168.85.13:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/metrics/summary?metric=memory_used_percent&bucket=1+hour" - -# Alle Metriken eines Agents (alle Typen, letzte 100) -curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \ - "https://192.168.85.13:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/metrics?limit=100" -``` - -### Backup-Beispiele - -```bash -# Backup ausloesen (Produktion .1) -curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" -X POST \ - https://192.168.85.13:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/backup - -# Backup ausloesen (Test .33) -curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" -X POST \ - https://192.168.85.13:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/backup - -# Alle Backups auflisten -curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \ - https://192.168.85.13:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/backups - -# Neuestes Backup als XML herunterladen -curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \ - "https://192.168.85.13:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/backups/latest?format=xml" \ - -o config-backup.xml - -# Diff zwischen Backup 1 und 3 -curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \ - "https://192.168.85.13:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/backups/diff?a=1&b=3" -``` - -### Update-Beispiele - -```bash -# Verfuegbare Updates pruefen -curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" -X POST \ - https://192.168.85.13:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/update-check - -# Normales Update (ohne Reboot) -curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" -X POST \ - https://192.168.85.13:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/update - -# Normales Update mit Reboot -curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" -X POST \ - https://192.168.85.13:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/update \ - -d '{"reboot":true}' - -# Major-Upgrade auf Version 26.7 -curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" -X POST \ - https://192.168.85.13:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/major-update \ - -d '{"version":"26.7","reboot":true}' - -# Reboot (5s Verzoegerung default) -curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" -X POST \ - https://192.168.85.13:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/reboot -``` - -### Update-Ablauf - -**Normales Update** (Patches innerhalb der gleichen Version): -1. `opnsense-update` — Core-Update herunterladen -2. `pkg upgrade -y` — Paket-Updates installieren -3. Nachpruefung: `opnsense-update -c` — Exit 1 = Reboot noetig - -Response enthaelt `reboot_required: true/false` fuer das Frontend. - -**Major-Upgrade** (z.B. 25.7 → 26.1): -1. `opnsense-update -r -bkp` — Repository wechseln + Base + Kernel + Packages herunterladen -2. `pkg-static update -f` — Repository-Katalog forciert aktualisieren -3. `pkg-static upgrade -y` — Alle Pakete auf neue Version installieren -4. **Reboot erforderlich** (immer bei Major-Upgrade) - -Major-Upgrades setzen `reboot_required: true` und `reboot` ist standardmaessig aktiviert. - -### WebSocket Commands (Backend → Agent) - -```json -// Remote-Befehl ausfuehren -{"type":"command","id":"cmd1","command":"exec","params":{"command":"uptime","timeout":30}} - -// Update-Check (liefert core_update_available, pending_packages, reboot_required) -{"type":"command","id":"cmd2","command":"update_check"} - -// Normales Update (reboot optional) -{"type":"command","id":"cmd3","command":"update","params":{"reboot":false}} - -// Major-Update (reboot default true) -{"type":"command","id":"cmd4","command":"major_update","params":{"version":"26.1","reboot":true}} - -// Reboot -{"type":"command","id":"cmd5","command":"reboot","params":{"delay":5}} - -// Config-Backup (liest /conf/config.xml, liefert Base64 + SHA256 Hash) -{"type":"command","id":"cmd8","command":"backup","params":{}} - -// Tunnel-Session oeffnen (automatisch vom Backend gesendet) -{"type":"command","id":"cmd6","command":"tunnel_connect","params":{"session_id":"xxx","tunnel_id":"xxx","target_host":"127.0.0.1","target_port":22}} - -// Tunnel-Session schliessen -{"type":"command","id":"cmd7","command":"tunnel_disconnect","params":{"session_id":"xxx"}} -``` - -### Binary WebSocket Messages (Tunnel-Daten) - -Format: `[session_id_length:1][session_id][tcp_payload]` - -Tunnel-Daten werden als Binary WebSocket Messages uebertragen (kein Base64-Overhead). - -## Frontend - -React + Vite + TailwindCSS Web-Frontend, deployed als statische Dateien auf Nginx. - -- **Server**: 192.168.85.20 (Debian 13, Nginx) -- **Tech**: React 18, Vite, TailwindCSS, Recharts, Zustand, lucide-react -- **Theme**: Dark mit Orange-Akzent, komplett deutsch -- **Auth**: JWT Login (8h Token) - -### Seiten - -| Seite | Beschreibung | -|-------|-------------| -| Dashboard | Uebersicht aller Firewalls, Status-Kacheln, AgentPanel per Klick | -| Firewalls | Suchbare Tabelle, AgentPanel mit Tabs (Uebersicht, Interfaces, Dienste, Tunnel, VPN, WireGuard, Routen, DHCP, Zertifikate, Backups, Agent); Firewall hinzufuegen/loeschen | -| Tunnel | Globale Tunnel-Uebersicht ueber alle Firewalls | -| Firmware | Multi-Plattform Firmware-Upload, Agent-Update-Trigger | -| Kunden | CRUD Kundenverwaltung | -| Einstellungen | Benutzerverwaltung, Passworte aendern | - -### Build & Deploy - -```bash -cd frontend -npm run build # ~330 KB JS, ~32 KB CSS -ssh root@192.168.85.20 'rm -rf /var/www/html/assets/*' # Alte Hashes loeschen! -scp -r dist/* root@192.168.85.20:/var/www/html/ -``` - -**Wichtig:** Vor Deploy immer `assets/` loeschen — Vite generiert Hash-basierte Dateinamen, alte Dateien bleiben sonst auf dem Server und Browser-Cache liefert 404. +Agent auf OPNsense installieren → siehe [docs/AGENT.md](docs/AGENT.md) ## Dateistruktur @@ -822,87 +130,33 @@ scp -r dist/* root@192.168.85.20:/var/www/html/ rmm/ ├── Makefile ├── README.md -├── agent/ -│ ├── main.go # Entry, Registration, Heartbeat-Loop, WS-Start -│ ├── config/ -│ │ └── config.go # YAML Config Loader -│ ├── client/ -│ │ └── client.go # HTTP Client (Register, Heartbeat) -│ ├── collector/ -│ │ ├── hardware.go # Hersteller, Modell, BIOS -│ │ ├── cpu.go # CPU-Modell, Cores, Usage -│ │ ├── memory.go # RAM total/used/free -│ │ ├── disk.go # ZFS Datasets, Belegung -│ │ ├── network.go # Interfaces, IPs, Status -│ │ ├── services.go # Laufende Dienste -│ │ ├── wireguard.go # WG-Tunnel, Peers, Transfer -│ │ ├── dhcp.go # KEA/ISC/dnsmasq Leases -│ │ ├── opnsense.go # OPN-Version, FreeBSD, Hostname, Uptime -│ │ ├── routing.go # Routing-Tabelle (netstat -rn) -│ │ ├── gateways.go # Gateway-Status (configctl) -│ │ ├── certificates.go # Zertifikate + CAs (config.xml + PEM) -│ │ ├── plugins.go # Installierte Plugins (pkg info) -│ │ ├── updates.go # Pending Updates (core + packages) -│ │ └── cron.go # Cron-Jobs (System-Crontab + OPNsense config.xml) -│ └── ws/ -│ ├── client.go # WebSocket Client, Reconnect, Ping/Pong -│ ├── handler.go # Command Handler (exec, backup, tunnel_connect/disconnect) -│ ├── wireguard.go # WireGuard Peer Management (add/delete/list) -│ └── tunnel.go # Session-basierter Tunnel Manager -├── backend/ -│ ├── main.go # Entry, TLS, HTTP Server -│ ├── config/ -│ │ └── config.go # YAML Config Loader -│ ├── db/ -│ │ └── postgres.go # PostgreSQL + TimescaleDB (Agents, Backups, Metriken) +├── docs/ # Detail-Dokumentation +│ ├── API.md # Vollstaendige API-Referenz +│ ├── AGENT.md # Agent + Updater + OPNsense Plugin +│ ├── BACKEND.md # Backend Installation + Konfiguration +│ ├── FRONTEND.md # Frontend Build + Deploy +│ └── FIRMWARE.md # Firmware-Management + Update-Prozess +├── agent/ # Agent-Quellcode (FreeBSD/OPNsense) +│ ├── main.go +│ ├── config/config.go +│ ├── client/client.go +│ ├── collector/ # Hardware, CPU, Memory, Disk, Network, Services, ... +│ └── ws/ # WebSocket Client, Handler, Tunnel, WireGuard +├── backend/ # Backend-Quellcode (Linux) +│ ├── main.go +│ ├── config/config.go +│ ├── db/postgres.go │ ├── models/ -│ │ ├── agent.go # Agent, Register/Heartbeat Structs -│ │ └── system.go # SystemData, alle Collector-Structs -│ ├── monitor/ -│ │ └── monitor.go # Inaktivitaets-Monitor (prueft Heartbeat, schreibt Events) -│ ├── api/ -│ │ ├── handlers.go # REST API Handler (inkl. Agent-Status + Events) -│ │ ├── tunnel_proxy.go # Tunnel + Exec + Update REST Endpoints -│ │ ├── backup.go # Config-Backup Endpoints (trigger, list, download, diff) -│ │ ├── wireguard.go # WireGuard Peer API Endpoints -│ │ ├── firmware.go # Firmware Upload/Download/Info, Update-Request -│ │ ├── auth.go # Login, JWT Token, /me Endpoint -│ │ ├── customers.go # Kunden CRUD + Agent-Zuordnung -│ │ ├── users.go # Benutzer CRUD + Passwort-Aenderung -│ │ ├── metrics.go # Metriken-Abfrage Endpoints (raw + summary) -│ │ └── middleware.go # CombinedAuth (API-Key OR JWT), CORS, Logging -│ └── ws/ -│ ├── handler.go # WebSocket Upgrade, Connection R/W Pumps -│ ├── hub.go # Agent-Registry, Message Routing -│ └── tunnel.go # Session-basierter Tunnel + Proxy Manager -├── updater/ -│ ├── main.go # Separater Update-Daemon (pollt Firmware, ersetzt Agent-Binary) -│ └── go.mod -├── frontend/ -│ ├── src/ -│ │ ├── App.jsx # Router + ProtectedRoute -│ │ ├── api/client.js # API Client (auth, agents, firmware, tunnels, etc.) -│ │ ├── stores/auth.js # Zustand Auth Store (JWT Token) -│ │ ├── layouts/AppLayout.jsx # Sidebar + Outlet -│ │ ├── components/ -│ │ │ ├── AgentPanel.jsx # Side Panel mit Tabs (Uebersicht bis Agent) -│ │ │ └── StatusBadge.jsx # Online/Offline/Stale Badge -│ │ └── pages/ -│ │ ├── Dashboard.jsx # Status-Kacheln + Agent-Liste -│ │ ├── Agents.jsx # Firewall-Tabelle -│ │ ├── AgentDetail.jsx # Detail-Ansicht (full page) -│ │ ├── Tunnels.jsx # Globale Tunnel-Uebersicht -│ │ ├── Firmware.jsx # Multi-Plattform Firmware + Update-Trigger -│ │ ├── Customers.jsx # Kunden CRUD -│ │ ├── SettingsPage.jsx # User-Management -│ │ └── Login.jsx # JWT Login -│ ├── vite.config.js -│ └── package.json -├── opnsense-plugin/ -│ ├── install.sh # Self-contained Installer (Agent + Updater + MVC Plugin) -│ ├── build.sh -│ └── src/ # MVC Model, Controllers, Views, configd, rc.d -└── build/ # Kompilierte Binaries (rmm-backend, rmm-agent, rmm-updater) +│ ├── monitor/monitor.go +│ ├── api/ # REST Handler, Auth, Middleware +│ └── ws/ # WebSocket Hub, Tunnel Manager +├── updater/main.go # Separater Update-Daemon +├── frontend/ # React + Vite + TailwindCSS +│ └── src/ +├── opnsense-plugin/ # OPNsense MVC Plugin + Installer +│ ├── install.sh +│ └── src/ +└── build/ # Kompilierte Binaries ``` ## Technische Details @@ -915,65 +169,18 @@ rmm/ - **Persistente Agent-ID**: Ueberlebt Agent- und Backend-Neustarts - **FreeBSD-kompatibel**: Volle Pfade (/usr/bin/netstat etc.), daemon statt nohup -## Neue Features (v1.0.3) +## Zugangsdaten -### OPNsense Plugin WebGUI Fix +``` +Backend: https://192.168.85.13:8443 +API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9 +Frontend: http://192.168.85.20 (admin / Start!123) -Der `SettingsController` wurde gefixt: -- **Config-Parsing**: Korrektes Parsen von `rmmagent[general][KEY]` Formular-Feldern (OPNsense MVC-Konvention) -- **Initialer config.xml Eintrag**: Beim ersten Speichern wird automatisch der `` Knoten in der `config.xml` angelegt, sodass die WebGUI-Konfiguration sofort funktioniert - -### Pre-Registration von Firewalls - -Firewalls koennen vorab im System registriert werden, bevor der Agent installiert wird: - -- **API**: `POST /api/v1/agents` mit `name` (Pflicht) und optionalem `customer_id` -- Der Agent wird mit `hostname="(ausstehend)"` angelegt -- Bei der eigentlichen Agent-Registration (`POST /api/v1/agent/register`) wird automatisch nach Name gematcht -- **DB-Funktion**: `GetAgentByName` fuer das automatische Pre-Registration Matching -- **Frontend**: "Firewall hinzufuegen" Dialog mit Installationsanleitung und Copy-Buttons fuer die Befehle - -### Firewall loeschen - -- Firewalls koennen direkt im Frontend ueber das Papierkorb-Icon im AgentPanel geloescht werden -- Loescht den Agent und alle zugehoerigen Daten (Systemdaten, Events, Backups, Metriken) - -### Service-Filter - -Boot- und Init-Scripts werden nicht mehr in der Dienste-Liste angezeigt: -- **Gefiltert**: `bgfsck`, `cleanvar`, `dmesg`, `hostid`, `ldconfig`, `motd`, `newsyslog`, `ntpd`, `resolv`, `syslogd`, `var` und andere System-Boot-Scripts -- **Angezeigt**: Nur echte OPNsense-Dienste (OpenVPN, Unbound, DHCPd, WireGuard, etc.) -- `pluginctl` wird mit vollem Pfad `/usr/local/sbin/pluginctl` aufgerufen (FreeBSD-Kompatibilitaet) - -### OPNsense Business Edition Lizenz-Anzeige - -Im Frontend im **Uebersicht-Tab** des AgentPanel wird die Lizenzinformation angezeigt: -- **Product Name**: z.B. "OPNsense Business Edition" -- **Subscription Key**: Lizenzschluessel -- **Ablaufdatum**: Wann die Lizenz ablaeuft -- **Restlaufzeit**: Visueller Farbbalken (gruen/gelb/rot je nach verbleibender Zeit) - -### Firmware Management (Frontend) - -Die **Firmware-Seite** im Frontend bietet: -- **Multi-Platform Upload**: Agent-Binaries fuer FreeBSD, Linux und Windows hochladen -- **Versions-Uebersicht**: Alle hochgeladenen Firmware-Versionen pro Plattform mit SHA256-Hash und Groesse -- **Agent-Update-Buttons**: Update fuer einzelne Agents oder "Alle updaten" mit einem Klick - -### Frontend Agent-Tab - -Der **Agent-Tab** im AgentPanel zeigt: -- **Agent-Info**: Version, Agent-ID, Plattform, Uptime -- **Update-Button**: Direktes Agent-Update anfordern -- **Befehle**: Remote-Shell-Befehle direkt aus dem Frontend ausfuehren - -## Hinweise - -- Backend braucht **kein root** — laeuft als normaler User auf Port 8443 -- Agent braucht **root** auf OPNsense (fuer Hardware-/Service-Daten) -- OPNsense WebGUI typischerweise auf **Port 4444** (nicht 443) -- FreeBSD csh hat kein `$()` — Agent verwendet `/bin/sh -c` fuer Commands -- Beim Backend-Deploy: **alte Prozesse killen** bevor neuer startet (sonst "bind: address already in use") +Agent-IDs: + 6beb8dfd38ecf03eab6c0f21b4ac7bee OPN-PROD.intra.weidenhaupt.net (192.168.85.1, READ-ONLY) + e92e87a684b20db15d8d2344583c5887 OPN-REP.intra.weidenhaupt.net (192.168.85.33) + 1697d28e57bc126534afc282b5de8ee0 OPN-TEST-UPDATE (192.168.85.19) +``` ## Lizenz diff --git a/docs/AGENT.md b/docs/AGENT.md new file mode 100644 index 0000000..8c94d66 --- /dev/null +++ b/docs/AGENT.md @@ -0,0 +1,124 @@ +# Agent — Installation & Konfiguration + +Der RMM-Agent laeuft auf OPNsense (FreeBSD) und wird als OPNsense-Plugin mit WebGUI-Konfiguration installiert. + +## Komponenten + +- **Collectors**: Hardware, CPU, Memory, Disk, Network, Services, WireGuard, DHCP, Routing, Gateways, Zertifikate, Plugins, Updates, Cron +- **WebSocket Client**: Persistente Verbindung zum Backend, automatisches Reconnect mit Backoff +- **Command Handler**: Remote-Befehlsausfuehrung, Tunnel-Connect/Disconnect +- **Tunnel Manager**: Session-basierte TCP-Verbindungen zu lokalen Diensten + +## 1. Agent bauen + +```bash +make agent # Erzeugt build/rmm-agent (freebsd/amd64) +``` + +## 2. Plugin installieren + +```bash +# Binary + Installer auf die Firewall kopieren +scp build/rmm-agent root@OPNSENSE:/tmp/ +scp opnsense-plugin/install.sh root@OPNSENSE:/tmp/ + +# Installer ausfuehren +ssh root@OPNSENSE '/bin/sh /tmp/install.sh' +``` + +Der Installer richtet alles ein: +- Binary nach `/usr/local/rmm/rmm-agent` +- rc.d Service (`/usr/local/etc/rc.d/rmm_agent`) +- OPNsense MVC Plugin (Model, Controller, View) +- configd Actions (start/stop/restart/status/reconfigure) +- Plugin-Hook fuer Service-Integration +- Setup-Script das Config aus dem Model generiert + +## 3. WebGUI konfigurieren + +1. OPNsense WebGUI oeffnen +2. **Services > RMM Agent** +3. Felder ausfuellen: + - **Aktiviert**: Ankreuzen + - **Backend URL**: `https://BACKEND_IP:8443` + - **API Key**: Backend API-Key eintragen + - **Agent Name**: Optional (Standard: Hostname) + - **Heartbeat Intervall**: 60 (Sekunden) + - **Self-Signed Zertifikate**: Ankreuzen bei self-signed Backend-Certs +4. **Speichern & Anwenden** klicken + +Der Agent startet automatisch und meldet sich am Backend an. + +### OPNsense Plugin WebGUI Fix (v1.0.3) + +Der `SettingsController` wurde gefixt: +- **Config-Parsing**: Korrektes Parsen von `rmmagent[general][KEY]` Formular-Feldern (OPNsense MVC-Konvention) +- **Initialer config.xml Eintrag**: Beim ersten Speichern wird automatisch der `` Knoten in der `config.xml` angelegt + +## 4. Verifizieren + +```bash +# Status in der WebGUI: Badge zeigt "Running" + +# Oder per SSH: +ssh root@OPNSENSE 'service rmm_agent status' + +# Auf dem Backend: Agent sollte erscheinen +curl -sk -H "X-API-Key: DEIN_API_KEY" https://BACKEND_IP:8443/api/v1/agents +``` + +## Pre-Registration + +Firewalls koennen vorab im System registriert werden, bevor der Agent installiert wird: + +1. Im Frontend auf "Firewall hinzufuegen" klicken (oder `POST /api/v1/agents`) +2. Name und optionalen Kunden angeben +3. Agent wird mit `hostname="(ausstehend)"` angelegt +4. Bei der eigentlichen Agent-Registration wird automatisch nach Name gematcht (`GetAgentByName`) +5. Der pre-registrierte Eintrag wird mit den echten Agent-Daten aktualisiert + +## Agent-Update (via Updater — empfohlen) + +Der **rmm-updater** ist ein separater Daemon, der auf jeder Firewall neben dem Agent laeuft. +Er prueft alle 60 Sekunden ob ein Update ansteht und fuehrt es automatisch durch. + +**Flow:** +1. Neue Agent-Binary im Frontend hochladen (Firmware-Seite) +2. Update-Button bei einzelnem Agent oder "Alle updaten" klicken +3. Updater erkennt den Flag, laedt die Binary vom Backend, stoppt Agent, ersetzt Binary, startet Agent +4. Flag wird automatisch zurueckgesetzt + +**Technische Details:** +- Separates Go-Binary (`rmm-updater`), laeuft als `rmm_updater` rc.d Service +- Liest die gleiche `config.yaml` wie der Agent (Backend-URL, API-Key) +- Download ueber `GET /api/v1/firmware/download?platform=freebsd` +- SHA256-Verifizierung vor Ersetzung +- Automatisches Rollback bei fehlgeschlagenem Agent-Start +- Backup der alten Binary als `.bak` waehrend des Updates +- Logs: `/var/log/rmm-updater.log` + +**Manuelles Update (Fallback):** + +```bash +make agent +scp build/rmm-agent root@OPNSENSE:/tmp/ +ssh root@OPNSENSE '/bin/sh -c "service rmm_agent stop; cp /tmp/rmm-agent /usr/local/rmm/rmm-agent; chmod +x /usr/local/rmm/rmm-agent; service rmm_agent start"' +``` + +Oder Plugin komplett neu installieren (`install.sh` ist idempotent — installiert Agent + Updater). + +## Service-Filter (v1.0.3) + +Boot- und Init-Scripts werden nicht mehr in der Dienste-Liste angezeigt: +- **Gefiltert**: `bgfsck`, `cleanvar`, `dmesg`, `hostid`, `ldconfig`, `motd`, `newsyslog`, `ntpd`, `resolv`, `syslogd`, `var` und andere System-Boot-Scripts +- **Angezeigt**: Nur echte OPNsense-Dienste (OpenVPN, Unbound, DHCPd, WireGuard, etc.) +- `pluginctl` wird mit vollem Pfad `/usr/local/sbin/pluginctl` aufgerufen (FreeBSD-Kompatibilitaet) + +## Hinweise + +- **Agent-ID** wird persistent in `/usr/local/rmm/agent_id` gespeichert — ueberlebt Neuinstallationen +- **Config** wird bei "Speichern & Anwenden" aus dem OPNsense-Model nach `/usr/local/rmm/config.yaml` generiert +- **Logs**: `/var/log/rmm-agent.log` +- **PID-File**: `/var/run/rmm_agent.pid` +- Agent braucht **root** auf OPNsense (fuer Hardware-/Service-Daten) +- OPNsense WebGUI typischerweise auf **Port 4444** (nicht 443) diff --git a/docs/API.md b/docs/API.md new file mode 100644 index 0000000..833262b --- /dev/null +++ b/docs/API.md @@ -0,0 +1,351 @@ +# API-Referenz + +Vollstaendige REST API Dokumentation mit allen Endpoints und Beispielen. + +**Base-URL**: `https://192.168.85.13:8443/api/v1` + +## Authentifizierung + +Zwei Auth-Methoden (CombinedAuth Middleware): +- **API-Key** (Header `X-API-Key`): Fuer Agents und automatisierte Zugriffe +- **JWT Bearer Token** (Header `Authorization: Bearer `): Fuer Frontend-Benutzer + +| Methode | Endpoint | Beschreibung | +|---------|----------|-------------| +| POST | `/auth/login` | Login (username + password → JWT Token, 8h Ablauf) | +| GET | `/auth/me` | Eigene Benutzerdaten | + +Default-Admin: `admin` / `Start!123` (min. 6 Zeichen). + +--- + +## Agent-Management + +| Methode | Endpoint | Beschreibung | +|---------|----------|-------------| +| POST | `/agent/register` | Agent registrieren (mit optionaler `agent_id`) | +| POST | `/agent/heartbeat` | Systemdaten senden | +| POST | `/agents` | Firewall pre-registrieren (`{name, customer_id?}`) | +| GET | `/agents` | Alle Agents auflisten | +| GET | `/agents/{id}` | Agent + Systemdaten abrufen | +| GET | `/agents/{id}/system` | Nur Systemdaten | +| DELETE | `/agents/{id}` | Agent loeschen | + +### Agent-Status + +Status wird automatisch aus `last_heartbeat` berechnet: + +| Status | Bedingung | +|--------|-----------| +| `online` | Heartbeat < 2 Minuten | +| `stale` | Heartbeat < 5 Minuten | +| `offline` | Heartbeat > 5 Minuten | +| `unknown` | Kein Heartbeat vorhanden | + +### Pre-Registration + +`POST /agents` mit `{"name": "FW-NAME", "customer_id": 1}` — legt Agent mit `hostname="(ausstehend)"` an. +Bei Agent-Registration wird automatisch nach Name gematcht (`GetAgentByName`). + +### Beispiele + +```bash +# Alle Agents auflisten +curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \ + https://192.168.85.13:8443/api/v1/agents + +# Einzelner Agent mit Systemdaten +curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \ + https://192.168.85.13:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887 + +# Nur Systemdaten +curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \ + https://192.168.85.13:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/system + +# Agent loeschen +curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" -X DELETE \ + https://192.168.85.13:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887 + +# Hub-Status (verbundene Agents, aktive Tunnel) +curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \ + https://192.168.85.13:8443/api/v1/hub/status + +# Remote-Command ausfuehren +curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" -X POST \ + https://192.168.85.13:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/exec \ + -d '{"command":"uptime","timeout":30}' +``` + +--- + +## Agent-Events + +| Methode | Endpoint | Beschreibung | +|---------|----------|-------------| +| GET | `/agents/events` | Alle Events (`?limit=N&type=X`) | +| GET | `/agents/{id}/events` | Events eines Agents (`?limit=N&type=X`) | + +Event-Typen: `online`, `offline`, `stale`, `connected`, `disconnected` + +```bash +# Alle Events (letzte 10) +curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \ + "https://192.168.85.13:8443/api/v1/agents/events?limit=10" + +# Nur Offline-Events eines Agents +curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \ + "https://192.168.85.13:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/events?type=offline" +``` + +--- + +## Kunden (Customers) + +| Methode | Endpoint | Beschreibung | +|---------|----------|-------------| +| GET | `/customers` | Alle Kunden auflisten | +| POST | `/customers` | Neuen Kunden anlegen (`{number, name}`) | +| GET | `/customers/{id}` | Einzelnen Kunden abrufen | +| PUT | `/customers/{id}` | Kunden aktualisieren | +| DELETE | `/customers/{id}` | Kunden loeschen | +| GET | `/customers/{id}/agents` | Agents eines Kunden | +| PUT | `/agents/{id}/customer` | Agent einem Kunden zuordnen | +| DELETE | `/agents/{id}/customer` | Kundenzuordnung entfernen | + +--- + +## Benutzer (Users) + +| Methode | Endpoint | Beschreibung | +|---------|----------|-------------| +| GET | `/users` | Alle Benutzer auflisten | +| POST | `/users` | Neuen Benutzer anlegen | +| PUT | `/users/{id}/password` | Passwort aendern (min. 6 Zeichen) | +| DELETE | `/users/{id}` | Benutzer loeschen | + +--- + +## Metriken (TimescaleDB) + +| Methode | Endpoint | Beschreibung | +|---------|----------|-------------| +| GET | `/agents/{id}/metrics` | Rohe Metriken (`?metric=X&from=&to=&limit=N`) | +| GET | `/agents/{id}/metrics/summary` | Aggregierte Metriken (`?metric=X&bucket=5+minutes&from=&to=`) | + +Verfuegbare Metriken: `cpu_usage`, `memory_used_percent`, `memory_used_bytes`, `memory_total_bytes`, +`uptime_seconds`, `disk_used_percent`, `disk_used_bytes`, `interface_rx_bytes`, +`interface_tx_bytes`, `gateway_rtt_ms`, `gateway_loss_percent` + +Retention: 90 Tage (Raw), Compression nach 7 Tagen. + +### Beispiele + +```bash +# CPU-Auslastung der letzten 24h +curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \ + "https://192.168.85.13:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/metrics?metric=cpu_usage" + +# RAM-Nutzung mit Zeitraum +curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \ + "https://192.168.85.13:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/metrics?metric=memory_used_percent&from=2026-02-28T00:00:00Z&to=2026-02-28T23:59:59Z" + +# 5-Minuten-Durchschnitte der CPU +curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \ + "https://192.168.85.13:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/metrics/summary?metric=cpu_usage&bucket=5+minutes" + +# Stuendliche RAM-Zusammenfassung +curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \ + "https://192.168.85.13:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/metrics/summary?metric=memory_used_percent&bucket=1+hour" +``` + +--- + +## Config-Backup + +| Methode | Endpoint | Beschreibung | +|---------|----------|-------------| +| POST | `/agents/{id}/backup` | Backup jetzt ausloesen (via WebSocket) | +| GET | `/agents/{id}/backups` | Alle Backups auflisten (`?limit=N`) | +| GET | `/agents/{id}/backups/{id\|latest}` | Backup herunterladen (`?format=xml` fuer Raw-XML) | +| DELETE | `/agents/{id}/backups/{id}` | Einzelnes Backup loeschen | +| GET | `/agents/{id}/backups/diff?a={id}&b={id}` | Zeilenweises Diff zwischen zwei Backups | + +Backups werden dedupliziert: gleicher SHA256-Hash = kein neuer Eintrag. + +### Beispiele + +```bash +# Backup ausloesen +curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" -X POST \ + https://192.168.85.13:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/backup + +# Alle Backups auflisten +curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \ + https://192.168.85.13:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/backups + +# Neuestes Backup als XML herunterladen +curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \ + "https://192.168.85.13:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/backups/latest?format=xml" \ + -o config-backup.xml + +# Diff zwischen Backup 1 und 3 +curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \ + "https://192.168.85.13:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/backups/diff?a=1&b=3" +``` + +--- + +## Tunnel-Management + +| Methode | Endpoint | Beschreibung | +|---------|----------|-------------| +| POST | `/agents/{id}/tunnel` | Tunnel oeffnen | +| GET | `/agents/{id}/tunnels` | Aktive Tunnel auflisten | +| DELETE | `/agents/{id}/tunnel/{tid}` | Tunnel schliessen | +| POST | `/agents/{id}/exec` | Remote-Command ausfuehren | + +### Beispiele + +```bash +# SSH-Tunnel zur OPNsense +curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" -X POST \ + https://192.168.85.13:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/tunnel \ + -d '{"target_host":"127.0.0.1","target_port":22}' +# Response: {"tunnel_id":"xxx","proxy_port":10000,...} +# Verbinden: ssh -p 10000 root@192.168.85.13 + +# WebGUI-Tunnel (OPNsense auf Port 4444) +curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" -X POST \ + https://192.168.85.13:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/tunnel \ + -d '{"target_host":"127.0.0.1","target_port":4444}' +# Im Browser: https://192.168.85.13:10001/ + +# Aktive Tunnel auflisten +curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \ + https://192.168.85.13:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/tunnels + +# Tunnel schliessen +curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" -X DELETE \ + https://192.168.85.13:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/tunnel/TUNNEL_ID +``` + +--- + +## Updates & Reboot + +Siehe [FIRMWARE.md](FIRMWARE.md) fuer den vollstaendigen Update-Prozess. + +| Methode | Endpoint | Beschreibung | +|---------|----------|-------------| +| POST | `/agents/{id}/update-check` | Verfuegbare Updates pruefen | +| POST | `/agents/{id}/update` | Normales Update (Core + Packages) | +| POST | `/agents/{id}/major-update` | Major-Upgrade auf Zielversion | +| POST | `/agents/{id}/reboot` | Reboot ausfuehren | + +--- + +## Firmware / Agent-Update + +Siehe [FIRMWARE.md](FIRMWARE.md) fuer Details. + +| Methode | Endpoint | Beschreibung | +|---------|----------|-------------| +| GET | `/firmware` | Alle Firmware-Versionen | +| POST | `/firmware/upload?version=X&platform=Y` | Binary hochladen | +| GET | `/firmware/download?platform=Y` | Binary herunterladen | +| POST | `/agents/{id}/request-update` | Update-Flag setzen | +| DELETE | `/agents/{id}/request-update` | Update-Flag zuruecksetzen | +| POST | `/agents/request-update-all` | Alle Agents updaten | + +--- + +## WireGuard-Peer Management + +| Methode | Endpoint | Beschreibung | +|---------|----------|-------------| +| POST | `/agents/{id}/wireguard/peers` | Neuen Peer anlegen | +| GET | `/agents/{id}/wireguard/peers` | Alle Peers auflisten (`?server_name=X`) | +| DELETE | `/agents/{id}/wireguard/peers/{uuid}` | Peer loeschen | + +### Peer anlegen — Parameter + +| Parameter | Pflicht | Default | Beschreibung | +|-----------|---------|---------|-------------| +| `name` | Ja | — | Peer-Name (z.B. "VPN_MUELLER") | +| `allowed_ips` | Nein | `0.0.0.0/0` | AllowedIPs fuer Client-Config | +| `dns` | Nein | — | DNS-Server fuer Client-Config | +| `server_name` | Nein | `ALWAYSON_VPN` | Name der WG-Server-Instanz | +| `endpoint` | Nein | WAN-IP:Port | Oeffentlicher Endpoint (Auto-Detect) | + +### Ablauf beim Anlegen + +1. Keypair wird auf der Firewall generiert (`wg genkey`/`wg pubkey`) +2. Naechste freie IP aus dem Tunnel-Subnetz wird automatisch vergeben +3. Peer wird in `config.xml` eingetragen und dem Server zugewiesen +4. `configctl wireguard configure` laedt die Aenderung +5. Response enthaelt die komplette Client-Config (ready for import) + +### Beispiele + +```bash +# Peer anlegen +curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" -X POST \ + https://192.168.85.13:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/wireguard/peers \ + -d '{"name":"VPN_MUELLER","allowed_ips":"0.0.0.0/0","dns":"10.172.100.210"}' + +# Peer mit eigenem Endpoint +curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" -X POST \ + https://192.168.85.13:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/wireguard/peers \ + -d '{"name":"VPN_EXTERN","allowed_ips":"0.0.0.0/0","endpoint":"vpn.kunde.de:8080"}' + +# Alle Peers auflisten +curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \ + https://192.168.85.13:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/wireguard/peers + +# Peer loeschen +curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" -X DELETE \ + https://192.168.85.13:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/wireguard/peers/89c10e2d-148e-11f1-a7af-7c5a1c6c7b73 +``` + +--- + +## WebSocket + +| Methode | Endpoint | Beschreibung | +|---------|----------|-------------| +| GET | `/agent/ws?agent_id=X&api_key=X` | WebSocket-Verbindung (Agent) | +| GET | `/hub/status` | Hub-Status (connected agents, aktive Tunnel) | + +### WebSocket Commands (Backend → Agent) + +```json +// Remote-Befehl ausfuehren +{"type":"command","id":"cmd1","command":"exec","params":{"command":"uptime","timeout":30}} + +// Update-Check +{"type":"command","id":"cmd2","command":"update_check"} + +// Normales Update +{"type":"command","id":"cmd3","command":"update","params":{"reboot":false}} + +// Major-Update +{"type":"command","id":"cmd4","command":"major_update","params":{"version":"26.1","reboot":true}} + +// Reboot +{"type":"command","id":"cmd5","command":"reboot","params":{"delay":5}} + +// Config-Backup +{"type":"command","id":"cmd8","command":"backup","params":{}} + +// Tunnel-Session oeffnen +{"type":"command","id":"cmd6","command":"tunnel_connect","params":{"session_id":"xxx","tunnel_id":"xxx","target_host":"127.0.0.1","target_port":22}} + +// Tunnel-Session schliessen +{"type":"command","id":"cmd7","command":"tunnel_disconnect","params":{"session_id":"xxx"}} +``` + +### Binary WebSocket Messages (Tunnel-Daten) + +Format: `[session_id_length:1][session_id][tcp_payload]` + +Tunnel-Daten werden als Binary WebSocket Messages uebertragen (kein Base64-Overhead). diff --git a/docs/BACKEND.md b/docs/BACKEND.md new file mode 100644 index 0000000..6ba88e5 --- /dev/null +++ b/docs/BACKEND.md @@ -0,0 +1,176 @@ +# Backend — Installation & Konfiguration + +Das RMM-Backend laeuft auf Linux (Debian 12+) und stellt die REST API, den WebSocket Hub und den Tunnel Manager bereit. + +## Komponenten + +- **REST API**: Agent-Registrierung, Heartbeat, Systemdaten, Tunnel-Management +- **WebSocket Hub**: Verwaltet Agent-Verbindungen, routet Commands und Binary-Messages +- **Tunnel Manager**: Proxy-Listener, Session-Tracking, Ready-Handshake +- **PostgreSQL + TimescaleDB**: Relationale Daten + Time-Series Metriken + +## 1. PostgreSQL + TimescaleDB installieren + +```bash +# Debian 12+ (Bookworm/Trixie) +apt install -y postgresql postgresql-client + +# TimescaleDB Repository hinzufuegen +echo "deb https://packagecloud.io/timescale/timescaledb/debian/ bookworm main" \ + > /etc/apt/sources.list.d/timescaledb.list +curl -L https://packagecloud.io/timescale/timescaledb/gpgkey | gpg --dearmor \ + > /etc/apt/trusted.gpg.d/timescaledb.gpg +apt update + +# TimescaleDB passend zur PG-Version installieren (z.B. PG 17) +apt install -y timescaledb-2-postgresql-17 + +# TimescaleDB in postgresql.conf aktivieren +echo "shared_preload_libraries = 'timescaledb'" >> /etc/postgresql/17/main/conf.d/timescaledb.conf +systemctl restart postgresql +``` + +## 2. Datenbank und User anlegen + +```bash +sudo -u postgres psql < /etc/systemd/system/rmm-backend.service << EOF +[Unit] +Description=RMM Backend +After=network.target postgresql.service + +[Service] +Type=simple +WorkingDirectory=/opt/rmm +ExecStart=/opt/rmm/rmm-backend /opt/rmm/config.yaml +Restart=always +RestartSec=5 + +[Install] +WantedBy=multi-user.target +EOF' + +ssh root@BACKEND_IP "systemctl daemon-reload && systemctl enable rmm-backend && systemctl start rmm-backend" +``` + +Oder per Makefile: `make deploy-backend` + +## 7. Starten und verifizieren + +```bash +# Status pruefen +systemctl status rmm-backend + +# Log pruefen +journalctl -u rmm-backend -f + +# API testen +curl -sk -H "X-API-Key: DEIN_API_KEY" https://BACKEND_IP:8443/api/v1/agents +``` + +Beim ersten Start: +- Tabellen werden automatisch angelegt +- Hypertable `metrics` wird erstellt (TimescaleDB) +- Retention Policy (90 Tage) und Compression Policy (nach 7 Tagen) werden automatisch gesetzt +- Default-Admin `admin` / `Start!123` wird erstellt + +## Datenbank-Schema (automatisch) + +| Tabelle | Typ | Beschreibung | +|---------|-----|-------------| +| `agents` | Relational | Agent-Registry (ID, Name, Hostname, IP, Version, Heartbeat, customer_id, update_requested) | +| `system_data` | Relational | Letzte Systemdaten pro Agent (JSONB) | +| `config_backups` | Relational | OPNsense Config-Backups (dedupliziert per SHA256) | +| `agent_events` | Relational | Online/Offline/Connected Events | +| `customers` | Relational | Kundenstammdaten (Nummer, Name) | +| `users` | Relational | Benutzer (Username, bcrypt-Hash, Display-Name) | +| `agent_firmware` | Relational | Agent-Binaries pro Plattform+Version (BYTEA, SHA256) | +| `metrics` | TimescaleDB Hypertable | Time-Series Metriken (CPU, RAM, Disk, Network, Gateway) | + +### TimescaleDB Policies + +- **Retention**: Rohdaten werden nach 90 Tagen automatisch geloescht +- **Compression**: Daten aelter als 7 Tage werden komprimiert (segmentby: agent_id+metric) + +### DB-Funktionen + +- `GetAgentByName`: Sucht Agent nach Name — verwendet fuer Pre-Registration Matching bei Agent-Registrierung + +## Hinweise + +- Backend braucht **kein root** — laeuft als normaler User auf Port 8443 +- Beim Deploy: **alte Prozesse killen** bevor neuer startet (sonst "bind: address already in use") +- FreeBSD csh hat kein `$()` — Agent verwendet `/bin/sh -c` fuer Commands diff --git a/docs/FIRMWARE.md b/docs/FIRMWARE.md new file mode 100644 index 0000000..19c0a72 --- /dev/null +++ b/docs/FIRMWARE.md @@ -0,0 +1,121 @@ +# Firmware-Management & Update-Prozess + +Multi-Plattform Firmware-Verwaltung fuer Agent-Binaries und OPNsense-Updates. + +## Agent-Firmware (Binary-Updates) + +### Ueberblick + +Der Update-Prozess fuer Agent-Binaries nutzt den **rmm-updater** Daemon: + +1. Neue Agent-Binary im Frontend hochladen (Firmware-Seite) oder per API +2. Update-Flag bei einzelnem Agent oder "Alle updaten" setzen +3. Updater auf der Firewall erkennt den Flag (pollt alle 60s) +4. Binary wird vom Backend heruntergeladen und SHA256-verifiziert +5. Agent wird gestoppt, Binary ersetzt, Agent gestartet +6. Flag wird automatisch zurueckgesetzt + +### Unterstuetzte Plattformen + +| Plattform | Binary | Ziel | +|-----------|--------|------| +| `freebsd` | `rmm-agent` | OPNsense Firewalls (amd64) | +| `linux` | `rmm-agent-linux` | Linux-basierte Agents | +| `windows` | `rmm-agent.exe` | Windows-basierte Agents | + +### API-Endpoints + +| Methode | Endpoint | Beschreibung | +|---------|----------|-------------| +| GET | `/api/v1/firmware` | Alle Firmware-Versionen (pro Plattform) | +| GET | `/api/v1/firmware?platform=freebsd` | Firmware einer Plattform | +| POST | `/api/v1/firmware/upload?version=X&platform=Y` | Binary hochladen (Body = Raw Binary) | +| GET | `/api/v1/firmware/download?platform=Y` | Binary herunterladen (fuer Updater) | +| POST | `/api/v1/agents/{id}/request-update` | Update-Flag setzen | +| DELETE | `/api/v1/agents/{id}/request-update` | Update-Flag zuruecksetzen | +| POST | `/api/v1/agents/request-update-all` | Update-Flag fuer alle Agents setzen | +| POST | `/api/v1/agents/{id}/agent-update` | Legacy: Binary direkt via WebSocket pushen | + +### Beispiele + +```bash +# FreeBSD Agent hochladen +curl -sk -X POST "https://192.168.85.13:8443/api/v1/firmware/upload?version=1.0.3&platform=freebsd" \ + -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \ + --data-binary @build/rmm-agent + +# Linux Agent hochladen +curl -sk -X POST "https://192.168.85.13:8443/api/v1/firmware/upload?version=1.0.3&platform=linux" \ + -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \ + --data-binary @build/rmm-agent-linux + +# Update fuer einzelnen Agent anfordern +curl -sk -X POST "https://192.168.85.13:8443/api/v1/agents/e92e87a6.../request-update" \ + -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" + +# Update fuer alle Agents anfordern +curl -sk -X POST "https://192.168.85.13:8443/api/v1/agents/request-update-all" \ + -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" +``` + +### Updater — Technische Details + +- Separates Go-Binary (`rmm-updater`), laeuft als `rmm_updater` rc.d Service +- Liest die gleiche `config.yaml` wie der Agent (Backend-URL, API-Key) +- Download ueber `GET /api/v1/firmware/download?platform=freebsd` +- SHA256-Verifizierung vor Ersetzung +- Automatisches Rollback bei fehlgeschlagenem Agent-Start +- Backup der alten Binary als `.bak` waehrend des Updates +- Logs: `/var/log/rmm-updater.log` + +## OPNsense-Updates (Core + Packages) + +### Normales Update + +Patches innerhalb der gleichen Version: + +1. `opnsense-update` — Core-Update herunterladen +2. `pkg upgrade -y` — Paket-Updates installieren +3. Nachpruefung: `opnsense-update -c` — Exit 1 = Reboot noetig + +Response enthaelt `reboot_required: true/false` fuer das Frontend. + +### Major-Upgrade + +z.B. 25.7 → 26.1: + +1. `opnsense-update -r -bkp` — Repository wechseln + Base + Kernel + Packages herunterladen +2. `pkg-static update -f` — Repository-Katalog forciert aktualisieren +3. `pkg-static upgrade -y` — Alle Pakete auf neue Version installieren +4. **Reboot erforderlich** (immer bei Major-Upgrade) + +### API-Endpoints + +| Methode | Endpoint | Beschreibung | +|---------|----------|-------------| +| POST | `/api/v1/agents/{id}/update-check` | Verfuegbare Updates pruefen | +| POST | `/api/v1/agents/{id}/update` | Normales Update (Core + Packages) | +| POST | `/api/v1/agents/{id}/major-update` | Major-Upgrade auf Zielversion | +| POST | `/api/v1/agents/{id}/reboot` | Reboot ausfuehren | + +### Beispiele + +```bash +# Verfuegbare Updates pruefen +curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" -X POST \ + https://192.168.85.13:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/update-check + +# Normales Update mit Reboot +curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" -X POST \ + https://192.168.85.13:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/update \ + -d '{"reboot":true}' + +# Major-Upgrade auf Version 26.7 +curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" -X POST \ + https://192.168.85.13:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/major-update \ + -d '{"version":"26.7","reboot":true}' + +# Reboot (5s Verzoegerung default) +curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" -X POST \ + https://192.168.85.13:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/reboot +``` diff --git a/docs/FRONTEND.md b/docs/FRONTEND.md new file mode 100644 index 0000000..a22b80b --- /dev/null +++ b/docs/FRONTEND.md @@ -0,0 +1,86 @@ +# Frontend — Build & Deploy + +React + Vite + TailwindCSS Web-Frontend, deployed als statische Dateien auf Nginx. + +## Eckdaten + +- **Server**: 192.168.85.20 (Debian 13, Nginx) +- **Tech**: React 18, Vite, TailwindCSS, Recharts, Zustand, lucide-react +- **Theme**: Dark mit Orange-Akzent, komplett deutsch +- **Auth**: JWT Login (8h Token) +- **Default-Login**: `admin` / `Start!123` + +## Seiten + +| Seite | Beschreibung | +|-------|-------------| +| Dashboard | Uebersicht aller Firewalls, Status-Kacheln, AgentPanel per Klick | +| Firewalls | Suchbare Tabelle, AgentPanel mit Tabs (Uebersicht, Interfaces, Dienste, Tunnel, VPN, WireGuard, Routen, DHCP, Zertifikate, Backups, Agent); Firewall hinzufuegen/loeschen | +| Tunnel | Globale Tunnel-Uebersicht ueber alle Firewalls | +| Firmware | Multi-Plattform Firmware-Upload, Agent-Update-Trigger | +| Kunden | CRUD Kundenverwaltung | +| Einstellungen | Benutzerverwaltung, Passworte aendern | + +## Features (v1.0.3) + +### Firewall hinzufuegen / Pre-Registration +- Dialog mit Name + optionalem Kunden +- Zeigt Installationsanleitung mit Copy-Buttons fuer die Shell-Befehle +- Agent wird mit `hostname="(ausstehend)"` angelegt, automatisches Matching bei Registration + +### Firewall loeschen +- Papierkorb-Icon im AgentPanel +- Loescht Agent und alle zugehoerigen Daten (Systemdaten, Events, Backups, Metriken) + +### OPNsense Business Edition Lizenz-Anzeige +Im **Uebersicht-Tab** des AgentPanel: +- Product Name (z.B. "OPNsense Business Edition") +- Subscription Key +- Ablaufdatum +- Restlaufzeit mit visuellem Farbbalken (gruen/gelb/rot je nach verbleibender Zeit) + +### Agent-Tab +- **Agent-Info**: Version, Agent-ID, Plattform, Uptime +- **Update-Button**: Direktes Agent-Update anfordern +- **Befehle**: Remote-Shell-Befehle direkt aus dem Frontend ausfuehren + +### Firmware-Seite +- Multi-Platform Upload (FreeBSD, Linux, Windows) +- Versions-Uebersicht pro Plattform mit SHA256-Hash und Groesse +- Agent-Update-Buttons (einzeln oder alle) + +## Build & Deploy + +```bash +cd frontend +npm run build # ~330 KB JS, ~32 KB CSS +ssh root@192.168.85.20 'rm -rf /var/www/html/assets/*' # Alte Hashes loeschen! +scp -r dist/* root@192.168.85.20:/var/www/html/ +``` + +**Wichtig:** Vor Deploy immer `assets/` loeschen — Vite generiert Hash-basierte Dateinamen, alte Dateien bleiben sonst auf dem Server und Browser-Cache liefert 404. + +## Dateistruktur + +``` +frontend/ +├── src/ +│ ├── App.jsx # Router + ProtectedRoute +│ ├── api/client.js # API Client (auth, agents, firmware, tunnels, etc.) +│ ├── stores/auth.js # Zustand Auth Store (JWT Token) +│ ├── layouts/AppLayout.jsx # Sidebar + Outlet +│ ├── components/ +│ │ ├── AgentPanel.jsx # Side Panel mit Tabs (Uebersicht bis Agent) +│ │ └── StatusBadge.jsx # Online/Offline/Stale Badge +│ └── pages/ +│ ├── Dashboard.jsx # Status-Kacheln + Agent-Liste +│ ├── Agents.jsx # Firewall-Tabelle +│ ├── AgentDetail.jsx # Detail-Ansicht (full page) +│ ├── Tunnels.jsx # Globale Tunnel-Uebersicht +│ ├── Firmware.jsx # Multi-Plattform Firmware + Update-Trigger +│ ├── Customers.jsx # Kunden CRUD +│ ├── SettingsPage.jsx # User-Management +│ └── Login.jsx # JWT Login +├── vite.config.js +└── package.json +```