rmm2/README.md
cynfo3000 f47154787d WebSocket-Infrastruktur: bidirektionaler Command-Kanal + TCP-Tunnel
- Agent: WS-Client mit Reconnect, Command-Handler (exec, tunnel_open/close/data)
- Backend: WS-Hub, Tunnel-Manager mit dynamischen Proxy-Ports (10000-20000)
- API: /agents/{id}/exec, /tunnel, /tunnels, /proxy/{tunnel_id}
- Binary WebSocket Messages fuer effiziente Tunnel-Daten
- gorilla/websocket (pure Go, kein CGO)
- README aktualisiert
2026-02-28 07:42:33 +01:00

9.4 KiB

OPNsense RMM System

Remote Monitoring & Management System fuer OPNsense Firewalls mit WebSocket-basierter Kommunikation und TCP-Tunnel-Funktionalitaet.

Ueberblick

Dieses System besteht aus zwei Komponenten:

  • Backend (Go) - REST API Server mit WebSocket Hub, TLS und SQLite-Datenbank, laeuft auf einem Linux-Server
  • Agent (Go) - Laeuft auf OPNsense/FreeBSD, sammelt Systemdaten, haelt WebSocket-Verbindung zum Backend und ermoeglicht Remote-Commands/Tunneling

Architektur

┌──────────────────────┐    WebSocket + HTTPS (TLS)    ┌──────────────────────┐
│   OPNsense FW        │ ◄─────────────────────────────► │   RMM Backend        │
│   (FreeBSD)          │  wss://backend:8443/api/v1/    │   (Linux)            │
│                      │       agent/ws                 │                      │
│   rmm-agent          │                                │   REST API           │
│   - Hardware/CPU/RAM │   POST /agent/register         │   WebSocket Hub      │
│   - Disk/Network     │   POST /agent/heartbeat        │   Tunnel Manager     │
│   - Services/Certs   │                                │   SQLite DB          │
│   - WebSocket Client │   Commands:                    │   :8443             │
│   - Tunnel Manager   │   • exec (Befehl ausfuehren)  │                      │
│                      │   • tunnel_open/close          │   192.168.85.13      │
│   192.168.85.33      │   • tunnel_data (TCP-Proxy)    │                      │
└──────────────────────┘                                └──────────────────────┘

                       TCP-Tunnel Flow:
      Browser/Client ──► Backend Proxy ──► WebSocket ──► Agent ──► OPNsense Service
                     (Port 10000-20000)   (Binary)    (Local)    (z.B. :443, :22)

Neue Funktionen (WebSocket/Tunnel)

1. Bidirektionale Kommunikation

  • WebSocket-Verbindung: Agent baut nach Registrierung eine persistente WebSocket-Verbindung zum Backend auf
  • Automatisches Reconnect: Bei Verbindungsabbruch mit exponential backoff
  • Ping/Pong Keepalive: Verbindung wird automatisch überwacht
  • Command-Response-Pattern: Backend kann Commands an Agents senden und Responses erhalten

2. Remote Command Execution

  • exec Command: Backend kann Befehle auf der OPNsense ausführen lassen
  • Timeout-Support: Configurable timeouts für Command-Execution
  • stdout/stderr Output: Vollständige Ausgabe wird zurückgeliefert

3. TCP-Tunneling über WebSocket

  • tunnel_open: Agent öffnet TCP-Verbindung zu lokalem Service (z.B. OPNsense WebUI :443)
  • Dynamische Proxy-Ports: Backend allokiert automatisch freie Ports (10000-20000)
  • Binary WebSocket Messages: Effiziente Datenübertragung ohne Base64-Overhead
  • Multi-Tunnel Support: Mehrere gleichzeitige Tunnel pro Agent möglich

4. HTTP-Proxy durch Tunnel

  • Reverse Proxy: GET /api/v1/agents/{id}/proxy/{tunnel_id}/* leitet HTTP-Traffic durch Tunnel
  • Transparent: Browser kann direkt auf OPNsense WebUI zugreifen über Backend-URL

Voraussetzungen

  • Go 1.22+
  • make
  • OpenSSL (fuer manuelle Zertifikat-Generierung)
  • SSH-Zugang zu den Zielservern
  • gorilla/websocket Library (automatisch über go mod)

Build

# Beide Komponenten bauen
make all

# Nur Backend (linux/amd64)
make backend

# Nur Agent (freebsd/amd64)  
make agent

# Dependencies aktualisieren
cd agent && go mod tidy
cd backend && go mod tidy

# TLS-Zertifikate generieren (optional, Backend generiert automatisch)
make certs

Die Binaries landen in build/.

Konfiguration

Backend (backend/config.yaml)

listen_addr: ":8443"
tls_cert: "certs/server.crt"
tls_key: "certs/server.key"
db_path: "rmm.db"
api_keys:
  - "01532e5a7c9e70bf2757df77a2f5b9b9"

Neue WebSocket-Features:

  • WebSocket-Hub läuft automatisch
  • Tunnel-Manager verwaltet aktive Tunnel
  • Port-Range 10000-20000 für dynamische Proxy-Ports

Agent (agent/config.yaml)

backend_url: "https://192.168.85.13:8443"
api_key: "01532e5a7c9e70bf2757df77a2f5b9b9"
interval_seconds: 60
agent_name: "opnsense-fw01"
insecure: true

WebSocket wird automatisch gestartet:

  • WebSocket URL: wss://192.168.85.13:8443/api/v1/agent/ws?agent_id=XXX&api_key=XXX
  • Reconnect mit Backoff bei Verbindungsabbruch
  • Ping/Pong Keepalive alle 30s

Deployment

Backend (192.168.85.13)

make deploy-backend

Dies startet:

  1. REST API Server auf :8443
  2. WebSocket Hub für Agent-Verbindungen
  3. Tunnel Manager für TCP-Proxies
  4. SQLite-Datenbank für persistente Daten

Agent (192.168.85.33 / OPNsense)

make deploy-agent

Dies startet:

  1. HTTP Heartbeat-Loop (weiterhin alle 60s)
  2. WebSocket-Client mit automatischem Reconnect
  3. Command-Handler für eingehende Befehle
  4. Tunnel-Manager für TCP-Verbindungen

API-Dokumentation

WebSocket Commands (Backend → Agent)

exec - Befehl ausführen

{
  "type": "command",
  "id": "cmd-123",
  "command": "exec",
  "params": {
    "command": "ps aux | head -10",
    "timeout": 30
  }
}

Response:

{
  "type": "response", 
  "id": "cmd-123",
  "status": "ok",
  "data": {
    "output": "PID  COMMAND\n1    kernel\n..."
  }
}

tunnel_open - TCP-Tunnel öffnen

{
  "type": "command",
  "id": "cmd-124", 
  "command": "tunnel_open",
  "params": {
    "target_host": "127.0.0.1",
    "target_port": 443
  }
}

Response:

{
  "type": "response",
  "id": "cmd-124",
  "status": "ok", 
  "data": {
    "tunnel_id": "a1b2c3d4e5f6789a"
  }
}

tunnel_close - TCP-Tunnel schließen

{
  "type": "command",
  "id": "cmd-125",
  "command": "tunnel_close", 
  "params": {
    "tunnel_id": "a1b2c3d4e5f6789a"
  }
}

Neue REST API Endpoints

POST /api/v1/agents/{id}/exec

Befehl auf Agent ausführen.

Request:

{
  "command": "uptime",
  "timeout": 30
}

Response (200):

{
  "message": "Command gesendet",
  "command_id": "cmd-123"
}

POST /api/v1/agents/{id}/tunnel

TCP-Tunnel zu Agent öffnen.

Request:

{
  "target_host": "127.0.0.1", 
  "target_port": 443
}

Response (201):

{
  "tunnel_id": "a1b2c3d4e5f6789a",
  "proxy_port": 12345,
  "target_host": "127.0.0.1",
  "target_port": 443,
  "created_at": "2024-01-28T12:30:00Z"
}

DELETE /api/v1/agents/{id}/tunnel/{tunnel_id}

Tunnel schließen.

Response (200):

{
  "message": "Tunnel geschlossen"
}

GET /api/v1/agents/{id}/tunnels

Aktive Tunnel auflisten.

Response (200):

[
  {
    "tunnel_id": "a1b2c3d4e5f6789a",
    "proxy_port": 12345, 
    "target_host": "127.0.0.1",
    "target_port": 443,
    "active": true,
    "created_at": "2024-01-28T12:30:00Z"
  }
]

GET /api/v1/agents/{id}/proxy/{tunnel_id}/*

HTTP-Reverse-Proxy durch Tunnel.

Beispiel:

GET /api/v1/agents/abc123/proxy/tunnel789/
→ Leitet weiter an OPNsense WebUI (127.0.0.1:443) über Tunnel

GET /api/v1/hub/status

WebSocket Hub Status.

Response (200):

{
  "status": "running",
  "connected_agents": ["abc123", "def456"],
  "stats": {
    "connected_agents": 2,
    "active_tunnels": 3
  },
  "timestamp": "2024-01-28T12:30:00Z"
}

WebSocket Endpoint

GET /api/v1/agent/ws

WebSocket-Upgrade für Agents.

Query Parameters:

  • agent_id: Agent-ID (aus Registrierung)
  • api_key: API-Key für Authentifizierung

Usage:

wss://192.168.85.13:8443/api/v1/agent/ws?agent_id=abc123&api_key=xxx

Tunnel-Datenformat

Binary WebSocket Messages

TCP-Tunnel-Daten werden als Binary Messages übertragen:

Format: [tunnel_id_length:1][tunnel_id][data]

  • Byte 0: Länge der Tunnel-ID (max 255)
  • Bytes 1-N: Tunnel-ID als UTF-8 String
  • Bytes N+1-Ende: TCP-Payload-Daten

Beispiel-Usage

  1. Tunnel öffnen:

    curl -X POST http://backend:8443/api/v1/agents/abc123/tunnel \
      -H "X-API-Key: xxx" \
      -d '{"target_host":"127.0.0.1","target_port":443}'
    
  2. Über Tunnel auf OPNsense WebUI zugreifen:

    # Backend allokiert Port 12345 für Tunnel
    # Browser kann jetzt zugreifen über:
    https://192.168.85.13:12345/
    
  3. Oder über HTTP-Proxy:

    https://192.168.85.13:8443/api/v1/agents/abc123/proxy/tunnel789/
    

Technische Details

CGO-frei

  • Beide Komponenten kompilieren mit CGO_ENABLED=0
  • Agent läuft auf FreeBSD/amd64 (OPNsense)
  • Backend läuft auf Linux/amd64
  • gorilla/websocket ist pure Go, kein CGO erforderlich

Sicherheit

  • TLS-verschlüsselte WebSocket-Verbindungen (WSS)
  • API-Key-Authentifizierung für alle Endpoints
  • Agent validiert Commands vor Ausführung
  • Tunnel sind isoliert per Agent/Tunnel-ID

Performance

  • Binary WebSocket Messages für Tunnel-Daten (kein Base64-Overhead)
  • Connection-Pooling für gleichzeitige Tunnel
  • Effiziente Port-Allokation für Proxies
  • Heartbeat läuft weiterhin parallel (für Monitoring auch ohne WS)

Monitoring

  • Agent funktioniert auch ohne WebSocket (nur Heartbeat)
  • WebSocket-Verbindungsstatus wird überwacht
  • Inactive Tunnel werden automatisch bereinigt
  • Hub-Status zeigt Connected Agents und aktive Tunnel

Lizenz

Intern.