Zum Inhalt springen
Prototyp pruefen

Ops Manual

Dieses Dokument ist das konsolidierte Betriebshandbuch fuer den ersten auslieferbaren Superheld-Stand: Android-App plus lokales superheld-cloud-Backend.


Der erste Lieferstand besteht aus zwei Komponenten:

KomponenteBeschreibungLaufzeitort
superheld-cloudBackend-API mit Secure-Mux, Event-Ingestion, Alert-/Incident-Ableitung, Job-Runtime, Token-Lifecycle, Webhook-DeliveryLokaler Prozess auf 127.0.0.1:8080
superheld-androidAndroid-App mit Device-Identitaet, signierter Event-Submission, Status-/Alert-/Incident-/Job-Refresh, TelemetrieAndroid-Geraet (USB-Tablet verifiziert)
  1. Die Android-App registriert sich per POST /devices mit RSA-Signatur.
  2. Die App sendet signierte Events per POST /events.
  3. Das Backend leitet aus akzeptierten Events Alerts ab; aus High-Severity-Events auch Incidents.
  4. Die App liest GET /status, GET /alerts, GET /incidents, GET /jobs und nachgelagerte Detail-Reads.
  5. Webhooks liefern Events an externe Systeme.

Alle Daten sind tenant-scoped. Tokens sind an genau einen Tenant gebunden. Cross-Tenant-Zugriffe werden vom Secure-Mux abgelehnt.

  • Device-Identitaet: RSA-Keypair pro Geraet, Proof-of-Possession bei Registrierung
  • API-Zugang: Bearer-Token mit Scope-Pruefung im Secure-Mux
  • Event-Integritaet: RSA-PSS-Signatur auf POST /events
  • Token-Speicherung: SHA-256(token) im Backend, Klartext nur einmal bei Create

Mit JSON-Persistenz:

Terminal-Fenster
cd /Users/benediktpoller/code/sh/superheld-cloud
SUPERHELD_DATA_DIR=/pfad/zum/data-dir \
SUPERHELD_BOOTSTRAP_TOKEN=<sicheres-token> \
SUPERHELD_BOOTSTRAP_TENANT_ID=<tenant-id> \
go run ./cmd/server

Mit SQLite-Persistenz (empfohlen fuer Restart-Sicherheit):

Terminal-Fenster
cd /Users/benediktpoller/code/sh/superheld-cloud
SUPERHELD_SQLITE_PATH=/pfad/zur/superheld.db \
SUPERHELD_BOOTSTRAP_TOKEN=<sicheres-token> \
SUPERHELD_BOOTSTRAP_TENANT_ID=<tenant-id> \
go run ./cmd/server

Im lokalen Dev-Pfad: Prozess mit Ctrl-C oder kill beenden. Der Server hat keine spezielle Graceful-Shutdown-Logik dokumentiert; offene Requests werden beim Stoppen abgebrochen.

  1. Server stoppen.
  2. Server mit demselben Kommando und denselben Umgebungsvariablen neu starten.
  3. Mit SQLite bleiben alle Daten erhalten. Mit JSON werden die Dateien beim Start neu geladen.
  4. Nach dem Start: curl -s http://127.0.0.1:8080/status -H 'Authorization: Bearer <token>' | jq . zur Verifikation.

Kein formaler Upgrade-Pfad dokumentiert. Aktueller Ablauf:

  1. Server stoppen.
  2. Neuen Code aus dem Repository ziehen (git pull in superheld-cloud).
  3. Server neu starten.
  4. Persistierte Daten bleiben kompatibel; aeltere Formate werden beim Lesen transparent migriert.

UmgebungsvariableDefaultBeschreibung
SUPERHELD_BIND_ADDR127.0.0.1:8080Adresse und Port fuer den Server

Default ist Loopback. Nicht-Loopback-Binds erwarten ein TLS-Zertifikat.

UmgebungsvariableBeschreibung
SUPERHELD_TLS_CERT_FILEPfad zum TLS-Zertifikat
SUPERHELD_TLS_KEY_FILEPfad zum TLS-Schluessel

Wenn beide gesetzt sind, startet der Server mit TLS und emittiert Strict-Transport-Security auf allen Antworten.

UmgebungsvariableBeschreibung
SUPERHELD_ALLOW_PLAINTEXT_BINDtrue erlaubt nicht-Loopback-Bind ohne TLS (nur fuer kontrollierte Dev-/Proxy-Setups)
  • Secure-Mux ist Default; ohne SUPERHELD_BOOTSTRAP_TOKEN startet der sichere Modus nicht.
  • Rate Limiting: 120 Anfragen/Minute, tenant-gebunden wenn authentifiziert.
  • Security-Header auf allen Antworten: X-Content-Type-Options: nosniff, X-Frame-Options: DENY, Referrer-Policy: no-referrer, Cache-Control: no-store.
  • Request-Body-Limit: Requests ueber dem konfigurierten Groessenlimit werden mit 413 abgelehnt.

Das Bootstrap-Token ist der initiale Zugang zum System. Es wird per Umgebungsvariable gesetzt und sollte nicht in Klartextlogs oder Quellcode erscheinen.

UmgebungsvariableBeschreibung
SUPERHELD_BOOTSTRAP_TOKENInitiales Zugriffstoken fuer den Secure-Mux
SUPERHELD_BOOTSTRAP_TENANT_IDTenant-Bindung des Bootstrap-Tokens
SUPERHELD_BOOTSTRAP_SCOPESKomma-getrennte Scopes (Default: alle)
SUPERHELD_BOOTSTRAP_TOKEN_TTLOptionale Lebensdauer (z. B. 24h)
Terminal-Fenster
curl -s -X POST http://127.0.0.1:8080/tokens \
-H "Authorization: Bearer <bootstrap-token>" \
-H "Content-Type: application/json" \
-d '{"scopes":["devices:write","events:write","status:read","alerts:read","incidents:read","incidents:write","jobs:read"]}' \
| jq .

Wichtig:

  • Das rohe Token wird nur einmal in der Create-Antwort zurueckgegeben.
  • Nur SHA-256(token) wird persistiert.
  • Neue Tokens koennen nur Scopes anfordern, die der aufrufende Token bereits besitzt.
Terminal-Fenster
curl -s -X DELETE http://127.0.0.1:8080/tokens/<token-id> \
-H "Authorization: Bearer <bootstrap-token>"
Terminal-Fenster
# Alle Token-Audit-Eintraege des Tenants
curl -s http://127.0.0.1:8080/tokens/audit \
-H "Authorization: Bearer <bootstrap-token>" | jq .
# Audit fuer ein bestimmtes Token
curl -s http://127.0.0.1:8080/tokens/<token-id>/audit \
-H "Authorization: Bearer <bootstrap-token>" | jq .

Filter: ?action=revoke oder ?token_id=<id> sind auf /tokens/audit verfuegbar.

  1. Kompromittiertes Token ueber DELETE /tokens/<id> widerrufen.
  2. Audit pruefen: GET /tokens/audit?token_id=<id> fuer Aktivitaeten des kompromittierten Tokens.
  3. Neues Token minten.
  4. App-Konfiguration mit neuem Token aktualisieren.

ModusUmgebungsvariableRestart-sicherEmpfohlen
JSON-DateienSUPERHELD_DATA_DIRJa (Dateien werden neu geladen)Fuer schnelle Dev-Laeufe
SQLiteSUPERHELD_SQLITE_PATHJa (zuverlaessig)Fuer Produktbetrieb

Unter SUPERHELD_DATA_DIR entstehen:

tokens.json, devices.json, events.json, alerts.json, incidents.json, jobs.json, traces.json, artifacts.json, webhooks.json, token_audit.json, job_audit.json

Aeltere Formate (z. B. incident_id statt id) werden beim Lesen transparent migriert.

Eine einzelne Datei unter SUPERHELD_SQLITE_PATH. Fehlende Spalten in aelteren Datensaetzen werden beim Lesen aus vorhandenen Spalten rekonstruiert.

  1. Server stoppen (oder sicherstellen, dass kein Schreibvorgang laeuft).
  2. JSON: Das gesamte SUPERHELD_DATA_DIR kopieren.
  3. SQLite: Die .db-Datei kopieren.
  1. Server stoppen.
  2. Backup an die konfigurierte Stelle kopieren.
  3. Server neu starten.
  4. Verifikation: GET /status, GET /tokens, GET /incidents pruefen.

EndpunktZweckFilter
GET /tokens/auditAlle Token-Lifecycle-Eintraege des Tenantsaction, token_id
GET /tokens/{id}/auditAudit eines bestimmten Tokens
GET /jobs/auditAlle Job-Review-Audit-Eintraege des Tenantsaction, reviewed_by
GET /jobs/{id}/auditAudit eines bestimmten Jobs

Alle Audit-Antworten folgen dem Cursor-/Limit-Paginierungsschema und liefern strukturierte fields neben dem rohen detail.

Die Runtime fuehrt eine interne Hash-Kette ueber Audit-Eintraege. Jeder Eintrag referenziert den Hash des vorigen Eintrags.

Token-Widerruf nachvollziehen:

Terminal-Fenster
curl -s 'http://127.0.0.1:8080/tokens/audit?action=revoke' \
-H "Authorization: Bearer <bootstrap-token>" | jq '.data[] | {timestamp, action, token_id: .fields.token_id}'

Job-Review-Entscheidungen pruefen:

Terminal-Fenster
curl -s 'http://127.0.0.1:8080/jobs/audit?action=approve' \
-H "Authorization: Bearer <bootstrap-token>" | jq '.data[] | {timestamp, action, reviewed_by: .fields.reviewed_by, job_id: .fields.job_id}'

Terminal-Fenster
curl -s -X POST http://127.0.0.1:8080/webhooks \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"url":"https://siem.example.com/ingest","secret":"<signing-secret>"}'

Anforderungen:

  • URL muss https:// verwenden.
  • Loopback-, Link-Local- und private Adressen werden abgelehnt.
  • Redirects auf solche Adressen ebenfalls.

Jede Zustellung traegt X-Superheld-Signature (HMAC-SHA256) und X-Superheld-Timestamp (Unix Seconds). Signing-Input: <timestamp>.<raw-body>.

VersuchVerzoegerung
1sofort
21 Sekunde
32 Sekunden
44 Sekunden

Nach 3 fehlgeschlagenen Wiederholungen landet die Zustellung in der Dead-Letter-Queue.

Terminal-Fenster
# Fehlgeschlagene Zustellungen auflisten
curl -s http://127.0.0.1:8080/webhooks/dlq \
-H "Authorization: Bearer <token>" | jq .
# Einzelnen Eintrag erneut zustellen
curl -s -X POST http://127.0.0.1:8080/webhooks/dlq \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"entry_id":"<dlq-entry-id>"}'
# Eintrag quittieren/loeschen
curl -s -X DELETE http://127.0.0.1:8080/webhooks/dlq \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"entry_id":"<dlq-entry-id>"}'

DLQ-Retention: 7 Tage im aktuellen Runtime-Vertrag.

Terminal-Fenster
curl -s http://127.0.0.1:8080/webhooks \
-H "Authorization: Bearer <token>" \
| jq '.data[] | {webhook_id, url, last_delivery_status, last_delivery_error, last_delivery_at, last_delivery_attempts}'

PruefpunktMethodeStatus
Runtime-CheckGET /status mit gueltigem TokenVerifiziert
Dedizierter Health-Endpoint/healthz oder /metricsNicht implementiert
Prometheus/OpenTelemetryMetrics-ExportNicht implementiert

GET /status ist der leichtgewichtige Runtime-Check. Ein separater Health-Endpoint ohne Auth ist heute nicht belegt.

Fuer eine vollstaendige Uebersicht, welche Observability-Pfade (Audit, Logging, Monitoring, SIEM, Telemetrie) heute verifiziert sind und was noch Zielarchitektur ist, siehe die Operatoren-Schnellreferenz in der Telemetrie-Seite.

Der Server schreibt nach stdout/stderr. Fuer persistentes Logging:

Terminal-Fenster
SUPERHELD_BOOTSTRAP_TOKEN=... \
SUPERHELD_BOOTSTRAP_TENANT_ID=... \
go run ./cmd/server 2>&1 | tee server.log

Wenn die App X-Superheld-Run-Id mitsendet, schreibt der Server pro Request eine strukturierte Zeile:

telemetry flow=status_refresh run_id=status-refresh-<uuid> tenant_id=tenant-local device_id=android-<uuid> app_version=0.1.0 backend_version=(devel) method=GET path=/status status=200 result=success latency=183µs

Bei Fehlern zusaetzlich: error_code=insufficient_scope

Wenn X-Superheld-Tenant-Id nicht zum Token-Tenant passt:

tenant_hint_mismatch token_tenant_id=tenant-local requested_tenant_id=tenant-debug token_id=... flow=... run_id=...
Terminal-Fenster
adb logcat -d -s SuperheldTelemetry:I

Zeigt telemetry flow=app_launch ... method=APP path=/main_activity ... backend_version=app_local und aehnliche Zeilen.

SymptomDiagnoseLoesung
Server startet nichtSUPERHELD_BOOTSTRAP_TOKEN oder SUPERHELD_BOOTSTRAP_TENANT_ID fehltUmgebungsvariablen setzen
App erreicht Backend nichtadb reverse fehlt oder Server nicht gestartetadb reverse tcp:8080 tcp:8080 und Server pruefen
401 auf allen RequestsToken ungueltig oder widerrufenNeues Token minten
403 insufficient_scopeToken hat benoetigten Scope nichtToken mit korrekten Scopes minten
403 tenant_mismatchApp-Tenant stimmt nicht mit Token-Tenant uebereinApp-Tenant oder Token anpassen
Incidents leer nach RestartJSON-Persistenz: Datei beschaedigt oder fehltSQLite verwenden oder JSON-Datei pruefen
Webhook-Zustellung schlaegt fehlZiel nicht erreichbar oder kein HTTPSZiel-URL und TLS pruefen, DLQ pruefen

Zwei Laeufe desselben Flows vergleichen:

Terminal-Fenster
go run ./cmd/telemetrycompare \
-log server.log \
-flow status_refresh \
-tenant-id tenant-local \
-app-version 0.1.0

Optionale Filter: -device-id, -backend-version, -result, -error-code, -run-a, -run-b.


KategorieBeispielPrimaere Massnahme
Token-KompromittierungBootstrap- oder App-Token geleaktToken widerrufen, Audit pruefen, neues Token minten
Backend-KompromittierungUnautorisierter Zugang zum Server-ProzessServer stoppen, Persistenz sichern, Audit pruefen
Geraete-KompromittierungAndroid-Geraet gerootet oder gestohlenGeraete-Token widerrufen, Events des Geraets pruefen
DatenexpositionPersistierte Daten an Unbefugte gelangtTokens widerrufen, Passwoerter rotieren, Umfang bestimmen
  1. Erkennen: Verdaechtiger Zugriff in Audit-Logs oder anomale API-Nutzung.
  2. Eindaemmen: DELETE /tokens/<id> fuer das kompromittierte Token.
  3. Untersuchen: GET /tokens/<id>/audit und GET /tokens/audit?token_id=<id> fuer alle Aktionen des Tokens.
  4. Bereinigen: Neues Token mit gleichen Scopes minten, App-Konfiguration aktualisieren.
  5. Dokumentieren: Zeitpunkt, betroffenes Token, durchgefuehrte Massnahmen, Ursache.
  1. Erkennen: GET /status schlaegt fehl oder App zeigt network_error.
  2. Eindaemmen: Server-Logs pruefen (tail server.log).
  3. Wiederherstellen: Server mit denselben Umgebungsvariablen neu starten.
  4. Verifizieren: GET /status, GET /incidents, GET /tokens pruefen.
  5. Dokumentieren: Ausfalldauer, Ursache, Datenverlust (falls vorhanden).
  1. Token widerrufen: DELETE /tokens/<app-token-id>.
  2. Events pruefen: GET /events fuer verdaechtige Eintraege des Geraets.
  3. Neues Token: Fuer Ersatzgeraet minten.
  • Alle kompromittierten Tokens widerrufen
  • Audit-Logs fuer den Zeitraum gesichert
  • Neue Tokens gemintet und verteilt
  • App-Konfiguration auf den neuen Zustand gezogen
  • Server-Persistenz intakt (Backup vorhanden)
  • GET /status liefert erwarteten Zustand