changed UI layout
new Navigation Dashboard
This commit is contained in:
@@ -0,0 +1,189 @@
|
||||
# Fixes & Hardening TODO
|
||||
|
||||
Kritisches Review-Backlog vor Produktiveinsatz und OSS-Release.
|
||||
Sortiert nach Risikoklasse. Datei-/Zeilenreferenzen beziehen sich auf den Stand bei Review-Erstellung.
|
||||
|
||||
---
|
||||
|
||||
## 🔴 Kritisch — vor Produktion blockierend
|
||||
|
||||
- [ ] **1. Default-Admin `admin/admin` entfernen**
|
||||
- Datei: `management/src/db.js:84`, `management/src/config.js:10`
|
||||
- Aktuell: leeres `AUTH_PASSWORD` → Passwort wird still auf `"admin"` gesetzt.
|
||||
- Fix: Bei leerem Passwort + leerer User-Tabelle Start mit klarer Fehlermeldung abbrechen. Keinen Default mehr in den Code.
|
||||
- README/`docs/deployment.md` entsprechend anpassen.
|
||||
|
||||
- [ ] **2. `API_TOKEN` im Node-Agent zur Pflicht machen**
|
||||
- Datei: `backend/src/index.js:24`, `backend/src/config.js:19`
|
||||
- Aktuell: `if (!config.apiToken) next();` → ohne Token offener Root-RCE-Endpunkt.
|
||||
- Fix: Beim Start verweigern wenn leer. Minimal-Länge erzwingen (z.B. 32 Zeichen).
|
||||
|
||||
- [ ] **3. HTTPS zwischen Management und Agent erzwingen**
|
||||
- Datei: `management/src/agentClient.js:2`, `management/src/routes/nodes.js:91`
|
||||
- Aktuell: `node.baseUrl` darf beliebiges Schema haben, Bearer-Token läuft potenziell im Klartext.
|
||||
- Fix: `baseUrl` muss `https://` sein (Validator). Optional: eigene CA + Cert-Pinning pro Node, mindestens dokumentieren.
|
||||
|
||||
- [ ] **4. CSRF-Risiko durch reflektierendes CORS schließen**
|
||||
- Datei: `management/src/index.js:18`
|
||||
- Aktuell: `cors({ origin: true, credentials: true })` reflektiert jede Origin.
|
||||
- Fix: Whitelist konkreter Frontend-Origins via Env. Cookie auf `SameSite=Strict` setzen oder CSRF-Token-Pattern (Double-Submit) ergänzen.
|
||||
|
||||
- [ ] **5. Brute-Force-Schutz beim Login**
|
||||
- Datei: `management/src/routes/auth.js:12`
|
||||
- Aktuell: kein Rate-Limit, kein Lockout.
|
||||
- Fix: `express-rate-limit` o.ä. — z.B. 5 Versuche / 15 min / IP + User. Audit-Event für gesperrte Versuche.
|
||||
|
||||
- [ ] **6. Restore atomarisieren — kein direktes `dd` auf Produktiv-Volume**
|
||||
- Datei: `backend/src/executor.js:92` (`streamResticDumpToDd`), `backend/src/routes/restore.js`
|
||||
- Aktuell: Wenn `restic dump` abbricht, sind GB bereits auf der VM-Disk → Disk irreversibel kaputt.
|
||||
- Fix-Optionen:
|
||||
- In temporäres ZFS-Volume schreiben, danach Größen-/Hash-Verifikation, dann atomarer `zfs rename`/clone-Swap.
|
||||
- Oder: vor Restore automatisch Disk-Snapshot anlegen; bei Fehler rollback.
|
||||
- Größe vorab prüfen (`restic stats` vs. `zfs get volsize`).
|
||||
|
||||
- [ ] **7. Backup-Verifikation einbauen**
|
||||
- Datei: `backend/src/routes/backup.js` (VM-Pfad ~Z.71, Container-Pfad ~Z.137)
|
||||
- Aktuell: Bei Pipe-Fehler (`zfs send` !=0, `createReadStream`-Abbruch) committed restic ggf. einen unvollständigen Snapshot mit Status „success".
|
||||
- Fix:
|
||||
- Vor Start erwartete Größe ermitteln (`zfs get volsize` / `used`).
|
||||
- Nach Restic-Commit `restic stats <snapshotId>` vergleichen.
|
||||
- Bei Mismatch oder Pipe-Fehler: Restic-Snapshot per ID `forget`+`prune`en, Job auf `failed`.
|
||||
|
||||
- [ ] **8. Bearer-Token aus Frontend-`localStorage` entfernen**
|
||||
- Datei: `frontend/src/api.js:9`
|
||||
- Aktuell: Agent-API-Token im Browser-Storage; bei XSS sofort kompromittiert.
|
||||
- Fix: Frontend nutzt ausschließlich Cookie-Auth zum Management. `VITE_API_TOKEN`/`setApiToken` ersatzlos streichen.
|
||||
|
||||
---
|
||||
|
||||
## 🟠 Hoch
|
||||
|
||||
- [ ] **9. Session-Cookie `Secure`-Flag**
|
||||
- Datei: `management/src/auth.js:37`
|
||||
- Fix: `Secure` immer setzen (in Production hart erzwingen), Cookie-Attribute über Config konfigurierbar machen.
|
||||
|
||||
- [ ] **10. Race beim Sichtbarmachen des Snapshot-Devices**
|
||||
- Datei: `backend/src/routes/backup.js:57`
|
||||
- Aktuell: 2 s `sleep` reicht nicht garantiert.
|
||||
- Fix: Polling-Schleife auf `fs.access(snapshotDevice)` mit Timeout; zusätzlich `udevadm trigger && udevadm settle`.
|
||||
|
||||
- [ ] **11. Persistenter Job- und Lock-Store im Agent**
|
||||
- Datei: `backend/src/jobs.js`
|
||||
- Aktuell: in-memory; bei Crash gehen laufende Jobs verloren, Locks bleiben hängen oder verschwinden inkonsistent (z.B. ZFS `volmode=dev`).
|
||||
- Fix: SQLite-Tabelle für Jobs/Locks. Beim Start: alle `running`/`queued` Jobs zu `failed` markieren, Cleanup-Pfad ausführen.
|
||||
|
||||
- [ ] **12. Toten `SESSION_SECRET` aufräumen**
|
||||
- Datei: `management/src/config.js:8`
|
||||
- Aktuell: gelesen, aber nirgendwo genutzt — sieht aus wie ein Loch.
|
||||
- Fix: Entweder Session-IDs HMAC-signieren oder Variable entfernen + `.env.example` säubern.
|
||||
|
||||
- [ ] **13. Snapshot-ID-Prefix-Matching eindeutig machen**
|
||||
- Datei: `backend/src/validators.js:66`
|
||||
- Aktuell: `startsWith` — bei Prefix-Kollision wird stillschweigend der erste Treffer genommen.
|
||||
- Fix: Bei >1 Treffer 409 zurückgeben; UI auf 12-Hex-Prefix umstellen.
|
||||
|
||||
- [ ] **14. RBAC einführen**
|
||||
- Aktuell: ein User, alle Rechte, kein Read-only.
|
||||
- Fix: Mindestens Rollen `admin` / `operator` / `viewer`. Restore nur für `admin`.
|
||||
|
||||
- [ ] **15. ENV-Escaping in `writeEnvSettings` verbessern**
|
||||
- Datei: `backend/src/config.js:105`
|
||||
- Aktuell: Nur `\` und `"` escaped; `$`, Backticks, Newlines nicht.
|
||||
- Fix: Eigener Serializer mit korrektem Escaping aller Sonderzeichen.
|
||||
|
||||
- [ ] **16. Settings-Endpunkt sperren bis `API_TOKEN` initial gesetzt ist**
|
||||
- Datei: `backend/src/routes/settings.js`
|
||||
- Hängt mit Fix #2 zusammen — nach #2 automatisch erfüllt, hier zur Sicherheit dokumentieren/testen.
|
||||
|
||||
---
|
||||
|
||||
## 🟡 Mittel
|
||||
|
||||
- [ ] **17. `Math.random()` durch `crypto.randomBytes` ersetzen**
|
||||
- Datei: `management/src/db.js:90` (`cryptoId`).
|
||||
|
||||
- [ ] **18. Systemd-Hardening für den Agent**
|
||||
- Datei: `deploy/systemd/incus-backup-agent.service`
|
||||
- Hinzufügen: `NoNewPrivileges=true`, `ProtectSystem=strict`, `ProtectHome=true`, `PrivateTmp=true`, `ReadWritePaths=/dev/zvol /var/lib/incus /opt/incus-backup-ui/backend`, `CapabilityBoundingSet=...`, eingeschränkte `AmbientCapabilities`.
|
||||
|
||||
- [ ] **19. `npm start` durch direkten `node`-Aufruf ersetzen**
|
||||
- Datei: beide `deploy/systemd/*.service`
|
||||
- `ExecStart=/usr/bin/node src/index.js` — kein npm-Wrapper-Prozess, kein PATH-Risiko.
|
||||
|
||||
- [ ] **20. CORS am Agent entfernen**
|
||||
- Datei: `backend/src/index.js:16`
|
||||
- Agent wird nie aus dem Browser angesprochen → Angriffsfläche raus.
|
||||
|
||||
- [ ] **21. `schedules.json`-Pfad explizit konfigurierbar**
|
||||
- Datei: `backend/src/scheduler.js:6`
|
||||
- Aktuell: `process.cwd()`-abhängig.
|
||||
- Fix: über Env (`SCHEDULES_PATH`) absolut konfigurieren, Default unter `/var/lib/incus-backup-agent/`.
|
||||
|
||||
- [ ] **22. Audit-Log-Integrität**
|
||||
- Datei: `management/src/store.js:71`
|
||||
- Append-only Constraint + Hash-Chain (jeder Event hat `prev_hash`). Optional Off-Site-Versand (Webhook).
|
||||
|
||||
- [ ] **23. Passwort-Hashing auf argon2id umstellen**
|
||||
- Datei: `management/src/crypto.js`
|
||||
- Aktuell: `scryptSync` mit Node-Defaults, ohne explizite Parameter.
|
||||
- Fix: `@node-rs/argon2` oder explizite scrypt-Parameter dokumentieren + Migration-Pfad.
|
||||
|
||||
- [ ] **24. Rate-Limit / Quoten für Backups**
|
||||
- Pro VM und global (z.B. max N parallele Streams nach S3). Disk-Space-/Quota-Check vor Start.
|
||||
|
||||
- [ ] **25. `incus snapshot delete` Retry verallgemeinern**
|
||||
- Datei: `backend/src/routes/backup.js:303`
|
||||
- Aktuell: Substring-Match auf englische Stderr — bricht bei lokalisierten Builds.
|
||||
- Fix: Generischer Retry (n Versuche, Backoff) bei nicht-0 Exit-Code.
|
||||
|
||||
- [ ] **26. Restic-`ls` streamen statt vollständig in RAM laden**
|
||||
- Datei: `backend/src/routes/snapshots.js:19`
|
||||
- Für Container-Backups mit vielen Files relevant.
|
||||
|
||||
- [ ] **27. Container-Restore implementieren oder Container-Backup deaktivieren**
|
||||
- Datei: `backend/src/routes/restore.js:21`
|
||||
- Aktuell: 501. Backups laufen, aber nicht wiederherstellbar = Backup-Theater.
|
||||
- Fix: Sicheren `zfs receive`-Workflow umsetzen oder Container-Backup im UI/API ausschalten bis fertig.
|
||||
|
||||
- [ ] **28. Pre-Backup VM-Zustand prüfen**
|
||||
- Live-Migration, laufende interne Snapshots, fehlende Berechtigungen → klare Fehler statt halb durchgeführter Pipeline.
|
||||
|
||||
---
|
||||
|
||||
## 🟢 Niedrig / Aufräumen
|
||||
|
||||
- [ ] **29. `.DS_Store` aus Repo entfernen und in `.gitignore` aufnehmen**
|
||||
- [ ] **30. `frontend/dist/` ist eingecheckt** — ignorieren und löschen.
|
||||
- [ ] **31. `incus-backup-ui-plan.md` auf Secrets/Bucket-Namen prüfen** bevor OSS.
|
||||
- [ ] **32. Container-Limit (Restore fehlt) prominent in README dokumentieren.**
|
||||
- [ ] **33. Scheduler-Jitter einbauen** (`management/src/scheduler.js`, `backend/src/scheduler.js`) — sonst belasten viele Nodes synchron S3.
|
||||
- [ ] **34. `formatBytes` deduplizieren** (`backend/src/routes/backup.js`, `restore.js`) → `executor.js` oder `utils.js`.
|
||||
- [ ] **35. `.env`-Dateipermissions dokumentieren** — `chmod 600` im Deployment-Doc verlangen.
|
||||
- [ ] **36. Schema-Versionierung statt `addColumnIfMissing`** — z.B. `schema_version`-Tabelle + nummerierte Migrationen.
|
||||
- [ ] **37. `audit_events.details` Größenlimit** oder JSON-Spalte (SQLite hat JSON1).
|
||||
|
||||
---
|
||||
|
||||
## 📦 OSS-Release-Voraussetzungen
|
||||
|
||||
- [ ] **38. Tests einführen** — aktuell keinerlei Tests im Repo. Mindestens:
|
||||
- `validators.js` (vmName-/snapshot-Regex, Pfad-Validation).
|
||||
- `crypto.js` (hash/verify Roundtrip, Timing-Safe).
|
||||
- `jobs.js` (Locking, Trimming).
|
||||
- Pipeline-Smoke-Tests mit gemockten Befehlen.
|
||||
- [ ] **39. CI-Pipeline** (GitHub Actions): Lint, Tests, `npm audit`, Lockfile-Check.
|
||||
- [ ] **40. `SECURITY.md`** mit Disclosure-Adresse + GPG-Key.
|
||||
- [ ] **41. Threat-Model dokumentieren** — explizit machen, was außerhalb des Schutzbereichs liegt (root-Agent, vertrauenswürdiges Netz, etc.).
|
||||
- [ ] **42. `LICENSE`-Datei ergänzen** (z.B. MIT/Apache-2.0).
|
||||
- [ ] **43. `CONTRIBUTING.md`** + Code-of-Conduct.
|
||||
- [ ] **44. Beispiel-`compose.yaml` oder Ansible-Rolle** für reproduzierbares Deployment.
|
||||
|
||||
---
|
||||
|
||||
## Top-5 Sofort-Patches (Vorschlag Reihenfolge)
|
||||
|
||||
1. #1 Default-Passwort entfernen + #2 `API_TOKEN` Pflicht.
|
||||
2. #3 HTTPS-Pflicht für Agent-URL.
|
||||
3. #4 CORS-Whitelist + #9 `Secure`-Cookie.
|
||||
4. #5 Login-Rate-Limit.
|
||||
5. #6/#7 Restore- und Backup-Verifikation (größter Aufwand, größter Impact auf Datenintegrität).
|
||||
Reference in New Issue
Block a user