[EPIC] Public-Readiness II: HTTP-/User-API härten (Endpoint-Scope-Audit, Auth/Session, Dependency-Scan, Secrets) #186
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Ziel
Zweite Flanke fuer Public: die oeffentliche HTTP-/User-API absichern (Browser-/User-Seite), parallel zum Agent-Kanal (#184). Auth-Flows, Endpoint-Scope, Dependencies, Secrets, Frontend.
Hintergrund
#184 haertet den Agent→Backend-Pfad. Sobald das Backend public ist, ist aber auch die User-API extern erreichbar — eine eigene Angriffsflaeche. Der #108-Cluster hat gezeigt, dass "Endpoint ohne Scope-Check" hier real vorkam.
Arbeitspakete
Endpoint-Scope-Audit (systematisch)
require_read/require_role+check_node_scope/list_user_accessible_nodeshaben (Muster aus #108). Checkliste pro Router, kein Endpoint ungeprueft.Auth-/Session-Haertung
none), Rotation/Revocation.Dependency-Scanning (in CI scharf)
Secrets-/Deployment-Hygiene
...change-meraus).Frontend
Definition of Done
Bezug
Schwester-Epic zu #184. Enthaelt/ko ordiniert #93, #119, #55 (CI-Gates), #95 (Service-Extraktion erleichtert das Scope-Audit + Tests).
Arbeitspaket 1/5 — Endpoint-Scope-Audit ✅ · Commit
bc816e7Systematischer Durchgang aller 24 Router (~270 Endpoints) via 6 parallele Read-only-Audit-Agents, Muster aus #108. Report im Wiki: Security-Endpoint-Audit.md.
16 Findings gefunden + behoben:
HIGH (cross-tenant Mutation / IDOR)
schedule_router/jobs-Cluster (6 Endpoints): list/create/get/patch/delete/run waren ungescoped →POST /jobs/{id}/runfuehrte fremde Jobs auf fremden Nodes aus. Jetzt require_read+Filter / check_node_scope / check_vm_scope / _scope_job.update_router POST /bulk-job: Operator konnte Updates auf fremden Tenant-VMs ausloesen → check_vm_scope je entry. +/bulk-job/{id} & cancel-item IDOR → _assert_job_in_scope.MEDIUM
docker compose-update/status: IDOR via geratenem cmd_id (cross-VM Live-Log) → an node/vmid gebunden.security /scan-history+ /scan-state,admin /cluster/overview,audit /stats: cross-tenant Daten/Counts → tenant-gescoped.template POST/PUT/DELETE: jeder authed User (inkl. viewer) schrieb globale Templates → require_role(operator) + UUID-Guard.LOW
backup /sync-history: viewer triggerte Agent-Arbeit → require_role(operator).Saubere Router (keine Findings): deploy, net, monitor, rdp, notification, auto_update, auth, faq, temperature, docgen, command, tunnel, me, task, log.
IDOR-Check mit erledigt: alle UUID/ID-Parameter ohne Ownership-Pruefung sind die obigen Findings; require_superadmin-Endpoints laden per ID ohne Check, aber SA ueberspringt Scope (kein IDOR).
⚠️ Aktivierung: reine Backend-Auth-Verschaerfung, wirksam erst nach Backend-Rebuild — gekoppelt mit dem #185-Deploy (Migration 0024 + Re-Enrollment), daher hier noch nicht gebaut.
Offene Pakete (Epic bleibt offen)
Sag, welches Paket als naechstes.
Paket 1/5 (Endpoint-Scope-Audit) verifiziert @
bc816e7— korrekt umgesetzt.HIGH einzeln gegen Code geprüft:
schedule_router:_scope_jobdeckt GET/PATCH/DELETE/run + List/Create (kein Start fremder Jobs auf fremden Nodes mehr) ✓update_router /bulk-jobPOST:check_vm_scopeje entry (Operator kann keine fremden Tenant-VMs mehr einreihen); GET + cancel-item via_assert_job_in_scope(404 statt 403 → kein Cross-Tenant-Orakel) ✓; alle per-VM-Endpoints (scan/update/preview/repair) mitcheck_vm_scope✓MEDIUM-Stichproben:
templatePOST/PUT/DELETE:require_role("operator")ergänzt (Rolegate fehlte) ✓admin /cluster/overview: aggregiert nur noch_scoped_nodes_for_bulkstatt alle ✓Report
wiki/Security-Endpoint-Audit.mdvorhanden, 15 Router sauber. Backend-Auth-Verschärfung → wirksam erst nach Rebuild, mit #185-Deploy gekoppelt (Migration 0024 + Re-Enroll, siehe Deployment-Public.md Abschnitt 7).Epic bleibt offen — 4 Pakete übrig: Auth/Session-Härtung (Login-Brute-Force + JWT) · Dependency-Scan-CI (#55) · Secrets (#93) · Frontend (#119).
Pakete A–D abgeschlossen (Endpoint-Scope-Audit/Paket 1 war `
bc816e7`). Epic bleibt offen.ec599a1`edb3f7d`9973377`38e0530`Paket B (die einzige echte Auth-Lücke): serverseitige Token-Invalidierung. Denylist-Tabelle `revoked_tokens` + Migration 0025 + globaler Cutoff `users.tokens_revoked_at`. Logout denylistet Access+Refresh-jti; `/refresh` rotiert (rotating refresh tokens); Reuse eines rotierten Refresh-jti → komplette Session-Kette gesperrt + `auth.refresh.reuse`-Log; neuer `DELETE /auth/logout-all`; abgelaufene Denylist-Einträge werden bei `/refresh` aufgeräumt. Live smoke-getestet: logout→401, rotation→neues Paar, reuse→401+chain-lock.
⚠️ Deploy: Paket B braucht `alembic upgrade head` (Migration 0025) beim Backend-Rebuild — passt mit dem #185-Deploy (ohnehin Rebuild) zusammen.
Bereits vorhanden (nicht angefasst): Login-Rate-Limit, JWT-Algo-Pinning, JWT-TTL, 2FA, Agent-Kanal #184.
Epic abgeschlossen ✅ — alle 5 Pakete verifiziert @
38e0530bc816e7) — 16 Cross-Tenant/IDOR-Fixes, HIGH einzeln gegen Code geprüft.ec599a1) — GUAC_SECRET-Schwach-Default raus (${GUAC_SECRET:?…}), .env.example vollständig.edb3f7d) —RevokedToken+ Migration 0025; Revocation wird inget_current_userbei JEDEM Request geprüft (assert_token_valid, rbac.py:70 — der Make-or-break); Logout revoked, Refresh-Rotation, Reuse-Detection mit Chain-Lock (revoke_all_user_tokens),tokens_revoked_at-Cutoff, Housekeeping. Live getestet (logout→401, rotation, reuse→401+chain-lock).9973377) — pip/cargo/npm-audit (Report+Gate), gitleaks blockierend.38e0530) — alle 4 {@html} bereits sanitisiert, Timer gepaart, svelte-check 0 Fehler.Migrations-Kette: 1 Head (0025), konsistent. Backend-Auth-Verschärfungen wirksam nach Rebuild (mit #185-Deploy gekoppelt, Migration 0025).
Beide Public-Readiness-Flanken stehen damit: #184 (Agent-Kanal) + #186 (HTTP-API).
Offene Design-Entscheidung (kein Blocker): Lint-Gates (fmt/clippy/ruff/svelte-check) bleiben bewusst auf
report— bei Public-Readiness korrekt, da nur Security-Gates (audit+gitleaks) scharf sein müssen. Lint blockierend erst nach einem dedizierten Lint-Cleanup (sonst sofort rot durch Bestands-Lint-Debt).