cc4c3fcecb
- Backend: Customer/Satellite Models, customer_id auf Server/Job/Audit - Satellite-API: heartbeat, poll (atomares Claiming), logs, result, scan-result, health-report - Auth via X-Api-Key (SHA-256 gehasht) - Job-Queue: pending/claimed/running/success/failed + Stale-Janitor - Batch-Trigger: ein Job pro Server, Satellite arbeitet sequenziell ab - Credentials bleiben lokal: nur symbolische credential_ref zentral - Neues Paket satellite/: Pull-Loop, WinRM/SSH/CAU/Scanner, PyInstaller-tauglich - Frontend: Kunden-Switcher, Satelliten-View, Polling statt WebSocket - Entfernt: WebSocket/Socket.io, Redis, zentrale Credentials, JobRunner - Docs: README/AGENTS/PROMPT auf neue Architektur aktualisiert
5.2 KiB
5.2 KiB
Insight Updater - Project Prompt
Overview
Zentrale, mandantenfaehige Update-Orchestrierung fuer Kundennetzwerke (MSP-Modell). Hub-and-Spoke: eine zentrale Instanz (Docker, bei Insight-IT) plus schlanke Satelliten pro Kunde (eine Binary, kein Docker beim Kunden noetig). Satelliten pollen Jobs von der Zentrale, fuehren Updates lokal im Kundennetz aus und melden Ergebnisse zurueck. Dashboard zeigt alles nach Kunde sortiert.
Target Stack
- Zentrale Backend: FastAPI + Python 3.11+, SQLAlchemy + SQLite/PostgreSQL, structlog
- Zentrale Frontend: Vue 3 + TypeScript + Vite, Pinia, Tailwind CSS
- Satellite: Python 3.11+, pywinrm, asyncssh, httpx, PyInstaller One-File-Binary
- Infra: Docker Compose (nur Zentrale), Traefik Labels
- CI/CD: Gitea Actions / Woodpecker CI fuer Build + Deploy auf monitoring (10.0.2.105)
Architektur-Entscheidungen
- Pull-Modell: Satelliten pollen (default 30s). Keine eingehenden Verbindungen beim Kunden, kein VPN, keine Firewall-Ausnahmen - nur ausgehend 443 zur Zentrale.
- Keine Live-Daten: Log-Batches statt WebSocket. Dashboard refresht alle 10s.
- Credentials lokal: WinRM/SSH-Zugangsdaten nur auf dem Satellite (credentials.yaml).
Zentral gibt es nur symbolische
credential_ref-Namen. - Netz-Orchestrierung: 1-2 Satelliten pro Kunde steuern alle Server des Kunden, aehnlich wie CAU einen Cluster steuert. Batch-Trigger legt pro Server einen Job an, der Satellite arbeitet sie sequenziell ab.
- Job-Claiming atomar: zwei Satelliten eines Kunden bekommen nie denselben Job.
Core Features
- Kunden + Satelliten - CRUD, API-Key einmalig angezeigt, rotierbar
- Server-Inventar pro Kunde - manuell oder per Netzwerk-Scan (Auto-Discovery)
- Job-Queue - pending/claimed/running/success/failed/cancelled + Stale-Janitor
- Windows Update - WinRM, Microsoft.Update.Session, optional Reboot
- Linux Update - apt/dnf/yum via SSH mit sudo, optional Reboot
- CAU - Invoke-CauRun auf Failover-Clustern
- Netzwerk-Scan - Ping + Port 5985/22, legt Hosts zentral als Server an
- Audit-Log - strukturiert, pro Kunde filterbar
Non-Goals
- Kein WSUS/SCCM-Ersatz, keine Approval-Workflows
- Kein Live-Streaming (bewusst: Pull + Batches)
- Kein RBAC ueber admin/user hinaus
- Keine zentral gespeicherten Kunden-Credentials
Success Criteria
- Kunde anlegen -> Satellite anlegen -> API-Key einmalig angezeigt
- Satellite startet -> erscheint als "online" im Dashboard (Heartbeat)
- Netzwerk-Scan -> gefundene Hosts im Inventar (discovered_by_scan)
- Update triggern -> Satellite claimed Job -> Logs + Ergebnis im Dashboard
- Batch: "Alle Server updaten" -> ein Job pro Server, sequenzielle Abarbeitung
- Zwei Satelliten eines Kunden: kein Job doppelt
- Satellite offline waehrend Job -> Janitor markiert Job nach Timeout als failed
docker compose up -d-> Zentrale healthy in <5 min
Verification Commands
curl -f http://localhost:8000/health
curl -f http://localhost:3000/
docker compose ps
Deployment Target
- Host: monitoring.insight.local (10.0.2.105)
- User: b0rbor4d (sudo via Vaultwarden)
- Docker: Podman/Docker Compose v2
- Reverse Proxy: Traefik (labels on compose services)
- Erreichbarkeit: HTTPS 443 von Kundenstandorten aus (ausgehend)
- Git Remote: ssh://git@gitea.insight-it.de:2222/b0rbor4d/insight-updater.git
Security
- Dashboard: JWT RS256, kurze Expiry
- Satelliten: API-Key (ius_...), SHA-256 gehasht in DB, Prefix fuer Anzeige
- Keine Kunden-Credentials in der zentralen DB
- Audit-Log: append-only
- TLS: Traefik + LetsEncrypt
Project Structure
~/projects/insight-updater/
├── backend/ # Zentrale API
│ ├── app/
│ │ ├── api/routes/ # auth, customers, satellites, servers, updates, audit, satellite_api
│ │ ├── core/ # config, security, db, logging, exceptions
│ │ ├── models/ # Customer, Satellite, Server, UpdateJob, UpdateLog, AuditLog, User
│ │ ├── schemas/ # Pydantic
│ │ ├── services/ # audit, janitor
│ │ └── main.py
│ ├── Dockerfile
│ └── pyproject.toml
├── frontend/ # Dashboard
│ ├── src/
│ │ ├── views/ # Dashboard, Customers, Satellites, Servers, Updates, Audit, Login
│ │ ├── stores/ # auth, customers, satellites, servers, updates
│ │ └── components/ # AppLayout (mit Kunden-Switcher)
│ ├── Dockerfile
│ └── package.json
├── satellite/ # Remote-Agent
│ ├── satellite/
│ │ ├── runner.py # Main-Loop
│ │ ├── client.py # Zentral-API-Client
│ │ ├── config.py # config.yaml + credentials.yaml
│ │ ├── winrm_exec.py, ssh_exec.py, cau_exec.py, scanner.py
│ ├── config.example.yaml
│ ├── credentials.example.yaml
│ └── pyproject.toml
├── docker-compose.yml
├── docker-compose.prod.yml
└── .env.example
Environment Variables
Zentrale siehe .env.example: SECRET_KEY, DATABASE_URL, JWT-Keys, LDAP-Stub.
Satellite siehe satellite/config.example.yaml: central_url, api_key, poll_interval.