823 lines
28 KiB
Markdown
823 lines
28 KiB
Markdown
# 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 <<EOF
|
|
CREATE USER rmm WITH PASSWORD 'SICHERES_PASSWORT';
|
|
CREATE DATABASE rmm OWNER rmm;
|
|
\c rmm
|
|
CREATE EXTENSION IF NOT EXISTS timescaledb;
|
|
GRANT ALL ON SCHEMA public TO rmm;
|
|
EOF
|
|
```
|
|
|
|
Verbindung testen:
|
|
|
|
```bash
|
|
psql -h 127.0.0.1 -U rmm -d rmm -c "SELECT default_version FROM pg_available_extensions WHERE name='timescaledb';"
|
|
```
|
|
|
|
## 3. Build
|
|
|
|
```bash
|
|
make all # Backend (linux/amd64) + Agent (freebsd/amd64)
|
|
make backend # Nur Backend
|
|
make agent # Nur Agent
|
|
```
|
|
|
|
Binaries landen in `build/`. Kein CGO — reine Go-Compilation.
|
|
|
|
## 4. TLS-Zertifikate generieren
|
|
|
|
```bash
|
|
make certs
|
|
```
|
|
|
|
Oder manuell:
|
|
|
|
```bash
|
|
mkdir -p certs
|
|
openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:P-256 \
|
|
-keyout certs/server.key -out certs/server.crt \
|
|
-days 3650 -nodes \
|
|
-subj "/CN=rmm-backend/O=RMM" \
|
|
-addext "subjectAltName=IP:BACKEND_IP,IP:127.0.0.1,DNS:localhost"
|
|
```
|
|
|
|
## 5. Backend konfigurieren (`config.yaml`)
|
|
|
|
```yaml
|
|
listen_addr: ":8443"
|
|
tls_cert: "certs/server.crt"
|
|
tls_key: "certs/server.key"
|
|
api_keys:
|
|
- "SICHERER_API_KEY" # beliebig lang, wird in X-API-Key Header mitgegeben
|
|
jwt_secret: "LANGER_ZUFAELLIGER_STRING" # fuer Frontend-Login (JWT-Signierung)
|
|
|
|
database:
|
|
host: "127.0.0.1"
|
|
port: 5432
|
|
user: "rmm"
|
|
password: "SICHERES_PASSWORT"
|
|
dbname: "rmm"
|
|
sslmode: "disable" # "require" wenn PG ueber Netz
|
|
```
|
|
|
|
Zufälligen JWT-Secret generieren:
|
|
|
|
```bash
|
|
openssl rand -hex 32
|
|
```
|
|
|
|
Alternativ per Environment-Variablen: `RMM_LISTEN_ADDR`, `RMM_TLS_CERT`, `RMM_TLS_KEY`, `RMM_DB_HOST`, `RMM_DB_PASSWORD`.
|
|
|
|
## 6. Backend deployen und starten
|
|
|
|
```bash
|
|
# Verzeichnis anlegen
|
|
ssh root@BACKEND_IP "mkdir -p /opt/rmm/certs"
|
|
|
|
# Binary + Config + Certs kopieren
|
|
scp build/rmm-backend root@BACKEND_IP:/opt/rmm/rmm-backend
|
|
scp config.yaml root@BACKEND_IP:/opt/rmm/config.yaml
|
|
scp certs/server.* root@BACKEND_IP:/opt/rmm/certs/
|
|
|
|
# Systemd-Service einrichten (Vorlage liegt unter backend/rmm-backend.service)
|
|
scp backend/rmm-backend.service root@BACKEND_IP:/etc/systemd/system/rmm-backend.service
|
|
# WorkingDirectory und ExecStart ggf. an eigenen Pfad anpassen
|
|
|
|
ssh root@BACKEND_IP "systemctl daemon-reload && systemctl enable rmm-backend && systemctl start rmm-backend"
|
|
```
|
|
|
|
Die mitgelieferte Service-Datei (`backend/rmm-backend.service`) verwendet `/home/cynfo/rmm` als Arbeitsverzeichnis — bei abweichendem Pfad anpassen.
|
|
|
|
### Dienste auf dem Backend-Server
|
|
|
|
| Dienst | Zweck | Management |
|
|
|--------|-------|-----------|
|
|
| `postgresql` | Datenbank (PostgreSQL + TimescaleDB) | `systemctl start/stop/restart postgresql` |
|
|
| `rmm-backend` | REST API, WebSocket Hub, Tunnel Manager | `systemctl start/stop/restart rmm-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` / `YOUR_PASSWORD` wird erstellt
|
|
|
|
## Datenbank-Schema (vollständig)
|
|
|
|
Alle Tabellen werden beim Backend-Start **automatisch angelegt** (Auto-Migration inkl. ALTER TABLE für neue Spalten). Kein manuelles Schema-Setup nötig.
|
|
|
|
---
|
|
|
|
### `agents` — Agent-Registry
|
|
|
|
```sql
|
|
CREATE TABLE agents (
|
|
id TEXT PRIMARY KEY, -- UUID des Agents (persistent)
|
|
name TEXT NOT NULL, -- Anzeigename (z.B. "OPN.intra.kunde.de")
|
|
hostname TEXT NOT NULL, -- Hostname der Firewall
|
|
ip TEXT NOT NULL, -- IP-Adresse des Agents
|
|
opnsense_version TEXT NOT NULL DEFAULT '', -- OPNsense-Version (z.B. "25.1.1")
|
|
agent_version TEXT NOT NULL DEFAULT '', -- Agent-Binary-Version (z.B. "1.0.3")
|
|
platform TEXT NOT NULL DEFAULT 'freebsd', -- Plattform: "freebsd", "linux"
|
|
registered_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), -- Erstregistrierung
|
|
last_heartbeat TIMESTAMPTZ, -- Letzter Heartbeat
|
|
customer_id INTEGER REFERENCES customers(id), -- Kundenzuordnung (nullable)
|
|
update_requested BOOLEAN NOT NULL DEFAULT FALSE -- Update-Flag fuer Updater-Daemon
|
|
);
|
|
CREATE INDEX idx_agents_customer ON agents(customer_id);
|
|
```
|
|
|
|
**Status-Berechnung** (kein DB-Feld, dynamisch im Backend):
|
|
|
|
| Status | Bedingung |
|
|
|--------|-----------|
|
|
| `online` | `last_heartbeat` < 2 Minuten |
|
|
| `stale` | `last_heartbeat` < 5 Minuten |
|
|
| `offline` | `last_heartbeat` > 5 Minuten |
|
|
| `unknown` | `last_heartbeat` ist NULL |
|
|
|
|
---
|
|
|
|
### `customers` — Kundenstammdaten
|
|
|
|
```sql
|
|
CREATE TABLE customers (
|
|
id SERIAL PRIMARY KEY,
|
|
number TEXT NOT NULL UNIQUE, -- RMM-Kundennummer (z.B. "K05068")
|
|
name TEXT NOT NULL, -- Kundenname
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
```
|
|
|
|
---
|
|
|
|
### `users` — Benutzer (Frontend-Login)
|
|
|
|
```sql
|
|
CREATE TABLE users (
|
|
id SERIAL PRIMARY KEY,
|
|
username TEXT NOT NULL UNIQUE,
|
|
password_hash TEXT NOT NULL, -- bcrypt-Hash
|
|
display_name TEXT NOT NULL DEFAULT '',
|
|
role TEXT NOT NULL DEFAULT 'admin', -- aktuell nur "admin"
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
last_login TIMESTAMPTZ -- nullable
|
|
);
|
|
```
|
|
|
|
Standard-Admin wird beim ersten Start angelegt: `admin` / `Start!123` (sofort ändern).
|
|
|
|
---
|
|
|
|
### `system_data` — Aktueller Systemzustand pro Agent
|
|
|
|
```sql
|
|
CREATE TABLE system_data (
|
|
agent_id TEXT PRIMARY KEY REFERENCES agents(id) ON DELETE CASCADE,
|
|
data_json JSONB NOT NULL, -- Vollständiger Heartbeat-Payload des Agents
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
```
|
|
|
|
---
|
|
|
|
### `config_backups` — Versionierte OPNsense-Configs
|
|
|
|
```sql
|
|
CREATE TABLE config_backups (
|
|
id SERIAL PRIMARY KEY,
|
|
agent_id TEXT NOT NULL REFERENCES agents(id) ON DELETE CASCADE,
|
|
hash TEXT NOT NULL, -- SHA256 der config.xml (Deduplizierung)
|
|
size INTEGER NOT NULL, -- Grösse in Bytes
|
|
config_xml TEXT NOT NULL, -- Vollständige config.xml
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
CREATE INDEX idx_config_backups_agent ON config_backups(agent_id, created_at DESC);
|
|
CREATE INDEX idx_config_backups_hash ON config_backups(agent_id, hash);
|
|
```
|
|
|
|
Deduplizierung: gleicher SHA256 → kein neuer Eintrag.
|
|
|
|
---
|
|
|
|
### `agent_events` — Online/Offline-Ereignisse
|
|
|
|
```sql
|
|
CREATE TABLE agent_events (
|
|
id SERIAL PRIMARY KEY,
|
|
agent_id TEXT NOT NULL REFERENCES agents(id) ON DELETE CASCADE,
|
|
event_type TEXT NOT NULL, -- "online", "offline", "stale", "connected", "disconnected"
|
|
message TEXT, -- optionale Zusatzinfo
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
CREATE INDEX idx_agent_events_agent ON agent_events(agent_id, created_at DESC);
|
|
```
|
|
|
|
---
|
|
|
|
### `agent_firmware` — Agent-Binaries pro Plattform
|
|
|
|
```sql
|
|
CREATE TABLE agent_firmware (
|
|
version TEXT NOT NULL, -- z.B. "1.0.3"
|
|
platform TEXT NOT NULL DEFAULT 'freebsd', -- "freebsd", "linux", "windows"
|
|
hash TEXT NOT NULL, -- SHA256 des Binaries
|
|
binary_data BYTEA NOT NULL, -- Das Binary selbst
|
|
uploaded_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
UNIQUE (version, platform)
|
|
);
|
|
```
|
|
|
|
---
|
|
|
|
### `tasks` — Task-Scheduler (geplante Aufgaben)
|
|
|
|
```sql
|
|
CREATE TABLE tasks (
|
|
id SERIAL PRIMARY KEY,
|
|
agent_id TEXT NOT NULL REFERENCES agents(id) ON DELETE CASCADE,
|
|
name TEXT DEFAULT '', -- Anzeigename der Aufgabe
|
|
action TEXT NOT NULL, -- "update", "backup", "reboot", ...
|
|
status TEXT NOT NULL DEFAULT 'scheduled', -- "scheduled","running","completed","failed"
|
|
schedule_type TEXT DEFAULT 'once', -- "once", "daily", "weekly", "monthly"
|
|
schedule_time TEXT DEFAULT '02:00', -- Uhrzeit (HH:MM)
|
|
schedule_weekday INT, -- 0=So, 1=Mo, ... 6=Sa (nur bei "weekly")
|
|
schedule_monthday INT, -- 1-31 (nur bei "monthly")
|
|
reboot BOOLEAN DEFAULT FALSE, -- Nach Update neu starten
|
|
health_check BOOLEAN DEFAULT FALSE, -- Nach Aufgabe Erreichbarkeit prüfen
|
|
health_check_timeout INT DEFAULT 600, -- Sekunden bis Timeout des Health-Checks
|
|
active BOOLEAN DEFAULT TRUE, -- Recurring: aktiv/inaktiv
|
|
scheduled_at TIMESTAMPTZ NOT NULL, -- Nächste/erste Ausführung (once)
|
|
started_at TIMESTAMPTZ, -- Tatsächlicher Start
|
|
finished_at TIMESTAMPTZ, -- Ende der Ausführung
|
|
last_run TIMESTAMPTZ, -- Letzter Lauf (recurring)
|
|
next_run TIMESTAMPTZ, -- Nächster Lauf (recurring)
|
|
run_count INT DEFAULT 0, -- Anzahl Ausführungen (recurring)
|
|
result JSONB, -- Ergebnis-Payload
|
|
webhook_url TEXT, -- URL für Webhook nach Abschluss
|
|
webhook_sent BOOLEAN DEFAULT FALSE,
|
|
webhook_response TEXT, -- HTTP-Response des Webhooks
|
|
created_by TEXT, -- Username des Erstellers
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
CREATE INDEX idx_tasks_status_scheduled ON tasks(status, scheduled_at);
|
|
CREATE INDEX idx_tasks_active_next_run ON tasks(active, next_run) WHERE active = TRUE;
|
|
```
|
|
|
|
**Webhook-Payload** (gesendetes JSON bei `webhook_url` gesetzt):
|
|
|
|
```json
|
|
{
|
|
"customer_id": "K05068",
|
|
"hostname": "opnsense.kunde.de",
|
|
"opnsense_version": "25.1.1",
|
|
"timestamp": "2026-03-06T08:00:00Z",
|
|
"trigger": "update_completed",
|
|
"reachable": true,
|
|
"update_status": "completed"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### `api_keys` — API-Keys (zusätzlich zu config.yaml)
|
|
|
|
```sql
|
|
CREATE TABLE api_keys (
|
|
id SERIAL PRIMARY KEY,
|
|
name TEXT NOT NULL,
|
|
key TEXT NOT NULL UNIQUE,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
last_used TIMESTAMPTZ
|
|
);
|
|
```
|
|
|
|
---
|
|
|
|
### `installers` — OPNsense Plugin-Pakete
|
|
|
|
```sql
|
|
CREATE TABLE installers (
|
|
id SERIAL PRIMARY KEY,
|
|
platform TEXT NOT NULL UNIQUE, -- "freebsd", "linux"
|
|
filename TEXT NOT NULL,
|
|
data BYTEA NOT NULL, -- ZIP-Paket (install.sh + Plugin)
|
|
sha256 TEXT NOT NULL,
|
|
size INTEGER NOT NULL,
|
|
uploaded_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
```
|
|
|
|
---
|
|
|
|
### `audit_log` — Audit-Protokoll
|
|
|
|
```sql
|
|
CREATE TABLE audit_log (
|
|
id SERIAL PRIMARY KEY,
|
|
timestamp TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
user_name TEXT NOT NULL,
|
|
action TEXT NOT NULL, -- z.B. "login", "delete_agent", "update_customer"
|
|
target_type TEXT, -- z.B. "agent", "customer", "user"
|
|
target_id TEXT,
|
|
target_name TEXT,
|
|
details TEXT,
|
|
source_ip TEXT
|
|
);
|
|
CREATE INDEX idx_audit_log_timestamp ON audit_log(timestamp DESC);
|
|
```
|
|
|
|
---
|
|
|
|
### `system_settings` — Backend-Einstellungen (Key/Value)
|
|
|
|
```sql
|
|
CREATE TABLE system_settings (
|
|
key TEXT PRIMARY KEY, -- "backend_url_internal", "backend_url_external", "api_key"
|
|
value TEXT NOT NULL,
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
```
|
|
|
|
---
|
|
|
|
### `metrics` — TimescaleDB Hypertable (Zeitreihen)
|
|
|
|
```sql
|
|
CREATE TABLE metrics (
|
|
time TIMESTAMPTZ NOT NULL,
|
|
agent_id TEXT NOT NULL,
|
|
metric TEXT NOT NULL, -- Name der Metrik
|
|
value DOUBLE PRECISION NOT NULL,
|
|
tags JSONB -- z.B. {"interface":"igb0"}
|
|
);
|
|
-- In Hypertable umwandeln:
|
|
SELECT create_hypertable('metrics', 'time', if_not_exists => TRUE);
|
|
CREATE INDEX idx_metrics_agent_metric ON metrics(agent_id, metric, time DESC);
|
|
```
|
|
|
|
**Verfügbare Metriken:**
|
|
|
|
| Metrik | Einheit | Tags |
|
|
|--------|---------|------|
|
|
| `cpu_usage` | Prozent | — |
|
|
| `memory_used_percent` | Prozent | — |
|
|
| `memory_used_bytes` | Bytes | — |
|
|
| `memory_total_bytes` | Bytes | — |
|
|
| `uptime_seconds` | Sekunden | — |
|
|
| `disk_used_percent` | Prozent | `{"mountpoint":"/","dataset":"zroot/ROOT"}` |
|
|
| `disk_used_bytes` | Bytes | `{"mountpoint":"/"}` |
|
|
| `interface_rx_bytes` | Bytes | `{"interface":"igb0"}` |
|
|
| `interface_tx_bytes` | Bytes | `{"interface":"igb0"}` |
|
|
| `gateway_rtt_ms` | Millisekunden | `{"gateway":"WAN_GW"}` |
|
|
| `gateway_loss_percent` | Prozent | `{"gateway":"WAN_GW"}` |
|
|
|
|
**TimescaleDB Policies** (automatisch gesetzt):
|
|
- **Retention**: Rohdaten nach 90 Tagen gelöscht
|
|
- **Compression**: Daten älter als 7 Tage komprimiert (`segmentby: agent_id, metric`)
|
|
|
|
---
|
|
|
|
### DB-Funktionen
|
|
|
|
- **`GetAgentByName`**: Sucht Agent nach Name — für Pre-Registration Matching (Agent registriert sich, Backend findet vorregistrierten Platzhalter mit `hostname="(ausstehend)"`).
|
|
|
|
---
|
|
|
|
## API Endpoints
|
|
|
|
Base-URL: `https://your-backend:8443/api/v1`
|
|
|
|
### Authentifizierung
|
|
|
|
Zwei Auth-Methoden (CombinedAuth Middleware):
|
|
- **API-Key** (Header `X-API-Key`): Fuer Agents und Automatisierung
|
|
- **JWT Bearer** (Header `Authorization: Bearer <token>`): Fuer Frontend
|
|
|
|
```
|
|
POST /auth/login Login → JWT Token (8h Ablauf)
|
|
GET /auth/me Eigene Benutzerdaten
|
|
```
|
|
|
|
```bash
|
|
# Login
|
|
curl -sk -X POST https://your-backend:8443/api/v1/auth/login \
|
|
-d '{"username":"admin","password":"YOUR_PASSWORD"}'
|
|
# → {"token":"eyJhbG...","user":{"id":1,"username":"admin"}}
|
|
```
|
|
|
|
### Agents
|
|
|
|
```
|
|
GET /agents Alle Agents auflisten
|
|
GET /agents/{id} Agent + Systemdaten
|
|
GET /agents/{id}/system Nur Systemdaten (JSONB)
|
|
DELETE /agents/{id} Agent loeschen (inkl. Daten, Events, Backups, Metriken)
|
|
POST /agents Firewall pre-registrieren
|
|
PUT /agents/{id}/customer Kunden zuordnen
|
|
DELETE /agents/{id}/customer Kundenzuordnung entfernen
|
|
POST /agent/register Agent-Registrierung (vom Agent selbst)
|
|
POST /agent/heartbeat Heartbeat + Systemdaten (vom Agent)
|
|
```
|
|
|
|
```bash
|
|
# Alle Agents
|
|
curl -sk -H "X-API-Key: YOUR_API_KEY" \
|
|
https://your-backend:8443/api/v1/agents
|
|
|
|
# Agent mit Systemdaten
|
|
curl -sk -H "X-API-Key: YOUR_API_KEY" \
|
|
https://your-backend:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee
|
|
|
|
# Nur Systemdaten
|
|
curl -sk -H "X-API-Key: YOUR_API_KEY" \
|
|
https://your-backend:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/system
|
|
|
|
# Pre-Registrierung
|
|
curl -sk -H "X-API-Key: YOUR_API_KEY" -X POST \
|
|
https://your-backend:8443/api/v1/agents \
|
|
-d '{"name":"OPN.intra.kunde.de","customer_id":1}'
|
|
|
|
# Agent loeschen
|
|
curl -sk -H "X-API-Key: YOUR_API_KEY" -X DELETE \
|
|
https://your-backend:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887
|
|
|
|
# Kunden zuordnen
|
|
curl -sk -H "X-API-Key: YOUR_API_KEY" -X PUT \
|
|
https://your-backend:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/customer \
|
|
-d '{"customer_id":1}'
|
|
```
|
|
|
|
Agent-Status (automatisch berechnet):
|
|
|
|
| Status | Bedingung |
|
|
|--------|-----------|
|
|
| `online` | Heartbeat < 2 Minuten |
|
|
| `stale` | Heartbeat < 5 Minuten |
|
|
| `offline` | Heartbeat > 5 Minuten |
|
|
| `unknown` | Kein Heartbeat |
|
|
|
|
### Agent-Events
|
|
|
|
```
|
|
GET /agents/events Alle Events (?limit=N&type=X)
|
|
GET /agents/{id}/events Events eines Agents
|
|
```
|
|
|
|
Event-Typen: `online`, `offline`, `stale`, `connected`, `disconnected`
|
|
|
|
```bash
|
|
curl -sk -H "X-API-Key: YOUR_API_KEY" \
|
|
"https://your-backend:8443/api/v1/agents/events?limit=10"
|
|
|
|
curl -sk -H "X-API-Key: YOUR_API_KEY" \
|
|
"https://your-backend:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/events?type=offline"
|
|
```
|
|
|
|
### Remote-Befehle (Exec)
|
|
|
|
```
|
|
POST /agents/{id}/exec Shell-Befehl ausfuehren
|
|
```
|
|
|
|
```bash
|
|
curl -sk -H "X-API-Key: YOUR_API_KEY" -X POST \
|
|
https://your-backend:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/exec \
|
|
-d '{"command":"uptime","timeout":30}'
|
|
# → {"data":{"output":"10:30AM up 45 days, ..."},"status":"ok"}
|
|
```
|
|
|
|
### Tunnel-Management
|
|
|
|
```
|
|
POST /agents/{id}/tunnel Tunnel oeffnen
|
|
GET /agents/{id}/tunnels Aktive Tunnel auflisten
|
|
DELETE /agents/{id}/tunnel/{tid} Tunnel schliessen
|
|
```
|
|
|
|
```bash
|
|
# SSH-Tunnel
|
|
curl -sk -H "X-API-Key: YOUR_API_KEY" -X POST \
|
|
https://your-backend:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/tunnel \
|
|
-d '{"target_host":"127.0.0.1","target_port":22}'
|
|
# → {"tunnel_id":"abc123","proxy_port":10000,...}
|
|
# Verbinden: ssh -p 10000 root@your-backend
|
|
|
|
# WebGUI-Tunnel (OPNsense Port 4444)
|
|
curl -sk -H "X-API-Key: YOUR_API_KEY" -X POST \
|
|
https://your-backend:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/tunnel \
|
|
-d '{"target_host":"127.0.0.1","target_port":4444}'
|
|
# Im Browser: https://your-backend:10001/
|
|
|
|
# PVE WebGUI-Tunnel (Proxmox Port 8006)
|
|
curl -sk -H "X-API-Key: YOUR_API_KEY" -X POST \
|
|
https://your-backend:8443/api/v1/agents/3f0a83a25d6fcdd8a623e76953559c87/tunnel \
|
|
-d '{"target_host":"127.0.0.1","target_port":8006}'
|
|
|
|
# Aktive Tunnel
|
|
curl -sk -H "X-API-Key: YOUR_API_KEY" \
|
|
https://your-backend:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/tunnels
|
|
|
|
# Tunnel schliessen
|
|
curl -sk -H "X-API-Key: YOUR_API_KEY" -X DELETE \
|
|
https://your-backend:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/tunnel/abc123
|
|
```
|
|
|
|
Tunnel-Architektur:
|
|
- Proxy-Port-Range: 10000-20000 (dynamisch)
|
|
- Jede TCP-Verbindung am Proxy bekommt eigene Session
|
|
- Agent oeffnet Ziel-Verbindung erst bei erstem Datenpaket (Lazy Connect)
|
|
- Binary WebSocket Messages: `[id_len:1][session_id][tcp_payload]`
|
|
|
|
### Config-Backups
|
|
|
|
```
|
|
POST /agents/{id}/backup Backup ausloesen (via WebSocket)
|
|
GET /agents/{id}/backups Alle Backups (?limit=N)
|
|
GET /agents/{id}/backups/{id|latest} Backup herunterladen (?format=xml)
|
|
DELETE /agents/{id}/backups/{id} Backup loeschen
|
|
GET /agents/{id}/backups/diff Diff (?a=ID&b=ID)
|
|
```
|
|
|
|
```bash
|
|
# Backup ausloesen
|
|
curl -sk -H "X-API-Key: YOUR_API_KEY" -X POST \
|
|
https://your-backend:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/backup
|
|
|
|
# Alle Backups
|
|
curl -sk -H "X-API-Key: YOUR_API_KEY" \
|
|
https://your-backend:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/backups
|
|
|
|
# Neuestes als XML
|
|
curl -sk -H "X-API-Key: YOUR_API_KEY" \
|
|
"https://your-backend:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/backups/latest?format=xml" \
|
|
-o config-backup.xml
|
|
|
|
# Diff
|
|
curl -sk -H "X-API-Key: YOUR_API_KEY" \
|
|
"https://your-backend:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/backups/diff?a=1&b=3"
|
|
```
|
|
|
|
Deduplizierung: Gleicher SHA256-Hash = kein neuer Eintrag.
|
|
|
|
### WireGuard Peer-Management
|
|
|
|
```
|
|
GET /agents/{id}/wireguard/peers Alle Peers (?server_name=X)
|
|
POST /agents/{id}/wireguard/peers Peer anlegen
|
|
DELETE /agents/{id}/wireguard/peers/{uuid} Peer loeschen
|
|
```
|
|
|
|
Peer-Anlage: Keypair generiert auf Firewall, naechste freie IP automatisch, Endpoint Auto-Detect via WAN-IP.
|
|
|
|
```bash
|
|
# Peer anlegen
|
|
curl -sk -H "X-API-Key: YOUR_API_KEY" -X POST \
|
|
https://your-backend:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/wireguard/peers \
|
|
-d '{"name":"VPN_MUELLER","allowed_ips":"0.0.0.0/0","dns":"<DNS-SERVER>"}'
|
|
|
|
# Alle Peers
|
|
curl -sk -H "X-API-Key: YOUR_API_KEY" \
|
|
https://your-backend:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/wireguard/peers
|
|
|
|
# Peer loeschen
|
|
curl -sk -H "X-API-Key: YOUR_API_KEY" -X DELETE \
|
|
https://your-backend:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/wireguard/peers/89c10e2d-148e-11f1-a7af-7c5a1c6c7b73
|
|
```
|
|
|
|
### Kunden (Customers)
|
|
|
|
```
|
|
GET /customers Alle Kunden
|
|
POST /customers Neuen Kunden anlegen
|
|
GET /customers/{id} Einzelnen Kunden abrufen
|
|
PUT /customers/{id} Kunden aktualisieren
|
|
DELETE /customers/{id} Kunden loeschen
|
|
GET /customers/{id}/agents Agents eines Kunden
|
|
```
|
|
|
|
```bash
|
|
# Kunden anlegen
|
|
curl -sk -H "X-API-Key: YOUR_API_KEY" -X POST \
|
|
https://your-backend:8443/api/v1/customers \
|
|
-d '{"number":"K05001","name":"Beispiel GmbH"}'
|
|
|
|
# Kunden aktualisieren
|
|
curl -sk -H "X-API-Key: YOUR_API_KEY" -X PUT \
|
|
https://your-backend:8443/api/v1/customers/1 \
|
|
-d '{"number":"K05001","name":"Beispiel AG"}'
|
|
|
|
# Agents eines Kunden
|
|
curl -sk -H "X-API-Key: YOUR_API_KEY" \
|
|
https://your-backend:8443/api/v1/customers/1/agents
|
|
```
|
|
|
|
### Benutzer (Users)
|
|
|
|
```
|
|
GET /users Alle Benutzer
|
|
POST /users Neuen Benutzer anlegen
|
|
PUT /users/{id}/password Passwort aendern (min. 6 Zeichen)
|
|
DELETE /users/{id} Benutzer loeschen
|
|
```
|
|
|
|
```bash
|
|
# Benutzer anlegen
|
|
curl -sk -H "Authorization: Bearer <TOKEN>" -X POST \
|
|
https://your-backend:8443/api/v1/users \
|
|
-d '{"username":"operator","password":"Sicher!123"}'
|
|
|
|
# Passwort aendern
|
|
curl -sk -H "Authorization: Bearer <TOKEN>" -X PUT \
|
|
https://your-backend:8443/api/v1/users/1/password \
|
|
-d '{"password":"NeuesPasswort!123"}'
|
|
```
|
|
|
|
### Metriken (TimescaleDB)
|
|
|
|
```
|
|
GET /agents/{id}/metrics Rohe Metriken (?metric=X&from=&to=&limit=N)
|
|
GET /agents/{id}/metrics/summary Aggregiert (?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`
|
|
|
|
```bash
|
|
# CPU letzte 24h
|
|
curl -sk -H "X-API-Key: YOUR_API_KEY" \
|
|
"https://your-backend:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/metrics?metric=cpu_usage"
|
|
|
|
# 5-Minuten-Durchschnitte
|
|
curl -sk -H "X-API-Key: YOUR_API_KEY" \
|
|
"https://your-backend:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/metrics/summary?metric=cpu_usage&bucket=5+minutes"
|
|
|
|
# Stuendliche RAM-Zusammenfassung mit Zeitraum
|
|
curl -sk -H "X-API-Key: YOUR_API_KEY" \
|
|
"https://your-backend:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/metrics/summary?metric=memory_used_percent&bucket=1+hour&from=2026-03-01T00:00:00Z&to=2026-03-01T23:59:59Z"
|
|
```
|
|
|
|
### Updates & Reboot
|
|
|
|
```
|
|
POST /agents/{id}/update-check Verfuegbare Updates pruefen
|
|
POST /agents/{id}/update Normales Update (Core + Packages)
|
|
POST /agents/{id}/major-update Major-Upgrade (2-Phasen)
|
|
POST /agents/{id}/reboot Reboot
|
|
```
|
|
|
|
```bash
|
|
# Update-Check
|
|
curl -sk -H "X-API-Key: YOUR_API_KEY" -X POST \
|
|
https://your-backend:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/update-check
|
|
|
|
# Update mit Reboot
|
|
curl -sk -H "X-API-Key: YOUR_API_KEY" -X POST \
|
|
https://your-backend:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/update \
|
|
-d '{"reboot":true}'
|
|
|
|
# Major-Update Phase 1 (Base+Kernel, dann Reboot)
|
|
curl -sk -H "X-API-Key: YOUR_API_KEY" -X POST \
|
|
https://your-backend:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/major-update \
|
|
-d '{"version":"26.1","reboot":true}'
|
|
|
|
# Major-Update Phase 2 (nach Reboot: Packages)
|
|
curl -sk -H "X-API-Key: YOUR_API_KEY" -X POST \
|
|
https://your-backend:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/major-update \
|
|
-d '{"version":"26.1","phase":"2"}'
|
|
|
|
# Reboot
|
|
curl -sk -H "X-API-Key: YOUR_API_KEY" -X POST \
|
|
https://your-backend:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/reboot \
|
|
-d '{"delay":5}'
|
|
```
|
|
|
|
### Firmware / Agent-Update
|
|
|
|
```
|
|
GET /firmware Alle Firmware-Versionen (?platform=X)
|
|
POST /firmware/upload?version=X&platform=Y Binary hochladen
|
|
GET /firmware/download?platform=Y Binary herunterladen (fuer Updater)
|
|
POST /agents/{id}/request-update Update-Flag setzen
|
|
DELETE /agents/{id}/request-update Update-Flag zuruecksetzen
|
|
POST /agents/request-update-all Alle Agents updaten
|
|
POST /agents/{id}/agent-update Legacy: Binary direkt via WebSocket pushen
|
|
```
|
|
|
|
```bash
|
|
# Firmware-Info
|
|
curl -sk -H "X-API-Key: YOUR_API_KEY" \
|
|
https://your-backend:8443/api/v1/firmware
|
|
|
|
# Nur FreeBSD-Firmware
|
|
curl -sk -H "X-API-Key: YOUR_API_KEY" \
|
|
"https://your-backend:8443/api/v1/firmware?platform=freebsd"
|
|
|
|
# Firmware hochladen (FreeBSD)
|
|
curl -sk -H "X-API-Key: YOUR_API_KEY" -X POST \
|
|
"https://your-backend:8443/api/v1/firmware/upload?version=1.0.3&platform=freebsd" \
|
|
--data-binary @build/rmm-agent
|
|
|
|
# Firmware hochladen (Linux)
|
|
curl -sk -H "X-API-Key: YOUR_API_KEY" -X POST \
|
|
"https://your-backend:8443/api/v1/firmware/upload?version=1.0.1&platform=linux" \
|
|
--data-binary @build/rmm-agent-linux
|
|
|
|
# Update fuer einzelnen Agent anfordern
|
|
curl -sk -H "X-API-Key: YOUR_API_KEY" -X POST \
|
|
https://your-backend:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/request-update
|
|
|
|
# Update-Flag zuruecksetzen
|
|
curl -sk -H "X-API-Key: YOUR_API_KEY" -X DELETE \
|
|
https://your-backend:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/request-update
|
|
|
|
# Alle Agents updaten
|
|
curl -sk -H "X-API-Key: YOUR_API_KEY" -X POST \
|
|
https://your-backend:8443/api/v1/agents/request-update-all
|
|
```
|
|
|
|
Update-Flow: Frontend setzt Flag → Updater (separater Prozess auf Firewall) pollt alle 60s → Download + SHA256-Verify + Rollback bei Fehler → Flag wird geloescht.
|
|
|
|
### WebSocket
|
|
|
|
```
|
|
GET /agent/ws?agent_id=X&api_key=X WebSocket-Verbindung (Agent)
|
|
GET /hub/status Hub-Status
|
|
```
|
|
|
|
```bash
|
|
# Hub-Status (verbundene Agents, aktive Tunnel)
|
|
curl -sk -H "X-API-Key: YOUR_API_KEY" \
|
|
https://your-backend:8443/api/v1/hub/status
|
|
```
|
|
|
|
WebSocket Commands (Backend → Agent):
|
|
|
|
| Command | Parameter | Beschreibung |
|
|
|---------|-----------|-------------|
|
|
| `exec` | `command`, `timeout` | Shell-Befehl ausfuehren |
|
|
| `backup` | — | Config.xml lesen + senden |
|
|
| `update_check` | — | Verfuegbare Updates pruefen |
|
|
| `update` | `reboot` | Normales Update |
|
|
| `major_update` | `version`, `phase`, `reboot` | Major-Upgrade |
|
|
| `reboot` | `delay` | Reboot |
|
|
| `tunnel_connect` | `session_id`, `tunnel_id`, `target_host`, `target_port` | TCP-Tunnel oeffnen |
|
|
| `tunnel_disconnect` | `session_id` | Tunnel-Session schliessen |
|
|
| `wg_add_peer` | `name`, `server_name`, `allowed_ips`, `dns`, `endpoint` | WireGuard Peer anlegen |
|
|
| `wg_list_peers` | `server_name` | WireGuard Peers auflisten |
|
|
| `wg_delete_peer` | `uuid` | WireGuard Peer loeschen |
|
|
| `agent_update` | Binary + Hash (im Data-Feld) | Agent-Binary aktualisieren (Legacy) |
|
|
|
|
---
|
|
|
|
## 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
|