Files
proxui/README.md
T

106 lines
6.2 KiB
Markdown

# ProxUI
Multi-Tenant-Konsole fuer Proxmox auf Basis von Go, Supabase Postgres/Auth, Redis/asynq und React.
## Architektur
- `backend/`: HTTP-API, Auth/JWT-Validierung, RBAC, DB-Zugriff und Proxmox-Orchestrierung
- `worker/`: asynchrone Jobs fuer Proxmox-Tasks, Reconciliation und Cleanup
- `console-proxy/`: Websocket-Proxy fuer noVNC/xterm.js ohne direkte Proxmox-Verbindung im Browser
- `platform/`: gemeinsame Go-Bausteine fuer Konfiguration, Logging und spaetere Querschnittsfunktionen
- `frontend/`: React/TypeScript/Vite-App fuer Kunden- und Admin-Workflows
- `migrations/`: versionierte SQL-Migrationen
- `deploy/`: lokale und spaetere Deployment-Artefakte
## Lokales Setup
1. Go >= 1.22 installieren.
2. Node.js >= 20 und npm installieren.
3. Docker Desktop oder kompatible Docker Engine installieren.
4. `.env.example` nach `.env` kopieren und lokale Werte setzen.
5. Abhaengigkeiten installieren: `npm install --prefix frontend`.
6. Go-Abhaengigkeiten installieren: `go work sync`.
7. Lokale Infrastruktur starten: `make dev`.
8. Migrationen ausfuehren: `make migrate`.
9. Backend starten: `go run ./backend/cmd/api`.
10. Console-Proxy starten: `go run ./console-proxy/cmd/console-proxy`.
11. Frontend starten: `npm run dev --prefix frontend`.
Supabase self-hosted liegt unter `deploy/supabase/`. Die lokale `deploy/supabase/.env` wird aus der offiziellen Vorlage erzeugt und nicht committed. Fuer App-`.env` die Werte `POSTGRES_PASSWORD`, `ANON_KEY` und `SERVICE_ROLE_KEY` aus `deploy/supabase/.env` uebernehmen.
Migrationen nutzen `MIGRATE_DATABASE_URL`, falls gesetzt. Andernfalls wird `DATABASE_DIRECT_URL` aus `.env` oder eine lokale Supavisor-URL aus `deploy/supabase/.env` verwendet.
Das Backend validiert Supabase-JWTs ueber `SUPABASE_JWKS_URL` und `SUPABASE_ISSUER`. Fuer das lokale Self-Hosted-Setup mit leerem JWKS wird zusaetzlich `SUPABASE_JWT_SECRET` als HS256-Fallback genutzt. Beim ersten authentifizierten Request synchronisiert das Backend den Supabase-User lazy nach `public.profiles`.
Cluster-Tokens werden mit AES-256-GCM verschluesselt. `MASTER_KEY_BASE64` muss ein base64-kodierter 32-Byte-Key sein, zum Beispiel erzeugt mit `openssl rand -base64 32`. Ohne gueltigen Master-Key bricht der Backend-Start ab.
Das Cluster-Repository speichert Proxmox-Token-Secrets nur als Ciphertext in `public.clusters.encrypted_token`. Entschluesselte Tokens bleiben interne Runtime-Daten und werden nicht in API-DTOs dokumentiert.
Der Proxmox-Client nutzt HTTPS mit normaler Zertifikatsvalidierung plus SHA-256-Fingerprint-Pinning gegen `clusters.tls_fingerprint`. Proxmox-Token werden nur als `PVEAPIToken=<token_id>=<secret>` Header an Proxmox gesendet.
Interne Cluster-Admin-Routen unter `/internal/clusters` sind nicht tenant-gebunden. Sie erfordern den Header `X-ProxUI-Operator-Token` mit `OPERATOR_TOKEN` und die isolierte Rolle `operator`; Responses enthalten nie `token_secret`.
Der Worker nutzt `asynq` gegen `REDIS_ADDR`, pingt beim Start dieselbe Supabase-DB ueber `DATABASE_URL`, entschluesselt Cluster-Credentials mit `MASTER_KEY_BASE64` und nutzt den gemeinsamen Proxmox-Client aus `platform/proxmox` fuer UPID-Polls und Reconciliation.
Lokale Dienste:
- Supabase API Gateway: `http://localhost:8000`
- Supabase Studio: `http://localhost:8000/project/default`
- Supavisor Session Pooler: `localhost:5432`
- Supavisor Transaction Pooler: `localhost:6543`
Aktuelle Targets:
- `make test`: Go-Tests
- `make build`: Go-Builds
- `make frontend-build`: Frontend-Production-Build
- `make lint`: Go Vet und Frontend-ESLint
- `make verify`: Lint, Tests und Builds
- `make dev-down`: Supabase-Stack stoppen
- `make dev-logs`: Supabase-Logs verfolgen
- `make migrate`: Migrationen auf den aktuellen Stand bringen
- `make migrate-down`: letzte Migration zurueckrollen
- `make migrate-version`: aktuelle Migrationsversion anzeigen
Worker-Jobs:
- `proxui.dummy`: Dummy-Job mit Payload `{"message":"..."}` fuer Smoke-Tests der asynq-Verarbeitung
- `proxmox.task.poll`: Pollt einen Proxmox-UPID ueber den gespeicherten Cluster, setzt VM-Status auf Erfolgs- oder Fehlerstatus und schreibt Audit-Metadaten.
- `proxmox.reconcile.all`: Laeuft alle 5 Minuten, prueft aktive Cluster gegen bekannte VMs und schreibt Drift als Audit-Event `vm.reconcile.drift`.
Backend-Endpunkte:
- `GET /healthz`: oeffentlicher Healthcheck
- `GET /me`: geschuetzt, synchronisiert `profiles` und gibt den authentifizierten Principal aus dem JWT zurueck
- `GET /tenants/{tenantID}/membership`: geschuetzt, synchronisiert `profiles`, prueft Tenant-Mitgliedschaft und gibt Rolle/Tenant zurueck
- `GET /projects/{projectID}/vms`: geschuetzt, listet nur VMs aus Projekten, deren Tenant der Nutzer angehoert
- `GET /vms/{vmID}`: geschuetzt, gibt VM-Details nur bei Tenant-Mitgliedschaft zurueck
- `POST /vms/{vmID}/start`: geschuetzt, prueft `vm.power`, ruft Proxmox auf und queued UPID-Polling
- `POST /vms/{vmID}/stop`: geschuetzt, prueft `vm.power`, ruft Proxmox auf und queued UPID-Polling
- `POST /vms/{vmID}/reboot`: geschuetzt, prueft `vm.power`, ruft Proxmox auf und queued UPID-Polling
- `POST /internal/clusters`: intern, legt Cluster an und speichert Token verschluesselt
- `PUT /internal/clusters/{clusterID}`: intern, aktualisiert Cluster und rotiert Token
- `PATCH /internal/clusters/{clusterID}/status`: intern, setzt Cluster-Status
Tenant-gescoped Backend-Routen laufen ueber JWT-Auth, Profil-Sync, Membership-Resolver und deklarative RBAC-Pruefung.
Frontend-Prototyp:
- Supabase Login/Registrierung ueber `VITE_SUPABASE_URL` und `VITE_SUPABASE_ANON_KEY`
- Backend-Profilcheck ueber `GET /me`
- Platzhalter-Ansichten fuer Projekte, VMs, SSH-Keys, Audit und Konsole
## CI
Forgejo Actions laufen unter `.forgejo/workflows/ci.yml`.
- `verify`: installiert Go/Node-Abhaengigkeiten und fuehrt `make verify` aus.
- `secret-scan`: fuehrt `zricethezav/gitleaks:v8.28.0` mit `.gitleaks.toml` aus. Die Konfiguration erlaubt nur dokumentierte Beispielwerte aus den offiziellen Supabase-Upstream-Dateien.
## Sicherheitsregeln
- Nur Backend, Worker und Console-Proxy sprechen mit Proxmox.
- Proxmox-Tokens werden nie im Frontend sichtbar und nie unverschluesselt gespeichert.
- Tenant-bezogene Queries muessen immer tenant-gefiltert sein.
- Secrets gehoeren in `.env` oder einen Secret-Manager, nie ins Repo.