Hub-and-Spoke Umbau: Multi-Tenant Zentrale + Satellite-Agent

- 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
This commit is contained in:
B0rbor4d
2026-08-07 03:42:06 +00:00
parent b91dd66fee
commit cc4c3fcecb
72 changed files with 2759 additions and 1642 deletions
+75 -132
View File
@@ -1,172 +1,115 @@
# Insight Updater
Self-hosted update orchestration for Windows (CAU/WSUS) and Linux servers via WinRM/SSH. Web UI to manage inventory, trigger updates, stream live progress via WebSocket.
Zentrale, mandantenfaehige Update-Orchestrierung fuer Kundennetzwerke. Hub-and-Spoke:
eine zentrale Instanz (Docker) plus schlanke Satelliten beim Kunden (einzelne Binary,
kein Docker noetig). Satelliten pollen Jobs von der Zentrale, fuehren Updates lokal
im Kundennetz aus (WinRM / SSH / CAU) und melden Ergebnisse zurueck.
## Architektur
```
Kundennetz A Kundennetz B Zentrale
┌──────────────┐ ┌──────────────┐ ┌───────────────┐
│ Satellite 1 │ │ Satellite 1 │ outbound │ Backend │
│ (Binary) │───┐ │ (Binary) │───┐ HTTPS │ (FastAPI) │
└──────────────┘ │ └──────────────┘ │────────────▶│ + DB │
┌──────────────┐ │ ┌──────────────┐ │ │ + Frontend │
│ Satellite 2 │───┘ │ Satellite 2 │───┘ │ (Dashboard, │
└──────────────┘ WinRM/SSH └──────────────┘ │ nach Kunde) │
lokal └───────────────┘
```
- **Pull-Modell**: Satelliten fragen alle N Sekunden nach Jobs - keine eingehenden Verbindungen beim Kunden noetig
- **Multi-Tenant**: jede Entitaet (Server, Jobs, Satelliten, Audit) haengt an einem Kunden
- **Credentials bleiben lokal**: WinRM/SSH-Zugangsdaten liegen nur auf dem Satellite (`credentials.yaml`), niemals zentral
- **Netz-Orchestrierung**: 1-2 Satelliten pro Kunde steuern das ganze Netz, aehnlich CAU im Cluster
## Komponenten
| Teil | Pfad | Technologie |
|------|------|-------------|
| Zentrale (Backend) | `backend/` | FastAPI, SQLAlchemy 2.0, SQLite/PostgreSQL |
| Zentrale (Frontend) | `frontend/` | Vue 3, TypeScript, Vite, Pinia, Tailwind |
| Satellite (Agent) | `satellite/` | Python, pywinrm, asyncssh, httpx, PyInstaller |
## Features
- **Server Inventory** — Windows/WinRM, Linux/SSH, CAU Clusters
- **Live Updates** — WebSocket log stream with progress per node
- **CAU Support** — Trigger `Invoke-CauRun`, track per-node phases
- **Linux Patching** — `apt/dnf/yum update` via SSH with sudo
- **Audit Log** — Structured JSON: who, when, what server, outcome
- **Health Checks** — WinRM/SSH connectivity test
- **LDAP Ready** — Config schema + stub for Active Directory auth
- **Kunden-Verwaltung** mit Satelliten pro Kunde (API-Key, einmalig angezeigt)
- **Server-Inventar** pro Kunde, inkl. Auto-Discovery per Netzwerk-Scan
- **Job-Queue**: pending - claimed - running - success/failed, mit Stale-Janitor
- **Batch-Trigger**: Update-Jobs fuer alle Server eines Kunden auf einmal
- **Netzwerk-Scan**: Ping + Port-Probe (5985/22), legt gefundene Hosts zentral an
- **Log-Upload** in Batches (kein Live-Stream noetig, 10s Dashboard-Refresh)
- **Audit-Log**: strukturiert, pro Kunde filterbar
- **Auth**: JWT (RS256) fuer Dashboard-User, API-Key (SHA-256 gehasht) fuer Satelliten
## Quick Start (Development)
## Quick Start (Zentrale, Development)
```bash
# Clone and enter
git clone ssh://git@gitea.insight-it.de:2222/b0rbor4d/insight-updater.git
cd insight-updater
# Configure environment
cp .env.example .env
# Edit .env with your secrets
# Start all services
docker compose up -d --build
# Access
# Frontend: http://localhost:3000
# Backend API: http://localhost:8000
# API Docs: http://localhost:8000/docs
# Backend API: http://localhost:8000/docs
# Login: admin / admin (bzw. ADMIN_INITIAL_PASSWORD)
```
## Satellite beim Kunden
```bash
cd satellite
pip install -e .
cp config.example.yaml config.yaml # central_url + api_key eintragen
cp credentials.example.yaml credentials.yaml # lokale Zugangsdaten
insight-satellite
```
Produktiv als Windows-Binary: `pyinstaller --onefile satellite/runner.py`, Details in `satellite/README.md`.
## Workflow
1. Kunde anlegen (Dashboard - Kunden)
2. Satellite anlegen - API-Key wird einmalig angezeigt
3. Satellite beim Kunden installieren (Binary + config.yaml + credentials.yaml)
4. Netzwerk-Scan starten - gefundene Hosts landen im Inventar
5. Updates triggern: einzeln, per Batch oder ganzer Kunde
6. Ergebnisse im Dashboard (nach Kunde sortiert) pruefen
## Production Deployment (monitoring.insight.local)
```bash
# On monitoring host (10.0.2.105)
git clone ssh://git@gitea.insight-it.de:2222/b0rbor4d/insight-updater.git
cd insight-updater
# Configure production environment
cp .env.example .env
# Fill in all secrets: SECRET_KEY, ENCRYPTION_KEY, DB_PASSWORD, LDAP creds, etc.
# Generate JWT keys
cp .env.example .env # Secrets fuellen
mkdir -p keys
openssl genrsa -out keys/private.pem 2048
openssl rsa -in keys/private.pem -pubout -out keys/public.pem
# Deploy
docker compose -f docker-compose.prod.yml up -d --build
```
## Architecture
Wichtig: die Zentrale muss per HTTPS von den Kunden-Standorten aus erreichbar sein
(ausgehend 443 reicht). Traefik-Labels sind vorbereitet.
```
┌─────────────┐ WebSocket ┌─────────────┐
│ Frontend │ ◀─────────────▶ │ Backend │
│ (Vue 3) │ REST + WS │ (FastAPI) │
└─────────────┘ └──────┬──────┘
┌──────────────────┼──────────────────┐
▼ ▼ ▼
┌───────────┐ ┌───────────┐ ┌───────────┐
│ WinRM │ │ SSH │ │ CAU │
│ Service │ │ Service │ │ Service │
└───────────┘ └───────────┘ └───────────┘
```
## Umgebungsvariablen
## Tech Stack
Siehe `.env.example`. Zentrale braucht nur noch: SECRET_KEY, DATABASE_URL, JWT-Keys,
optional LDAP. WinRM/SSH-Config ist in den Satellite gewandert (dessen `config.yaml`).
| Layer | Technology |
|-------|------------|
| Backend | Python 3.11+, FastAPI, SQLAlchemy 2.0, Alembic |
| Frontend | Vue 3, TypeScript, Vite, Pinia, Tailwind CSS |
| Database | SQLite (dev) / PostgreSQL (prod) |
| Cache/Queue | Redis 7 |
| Auth | JWT (RS256), LDAP stub |
| Encryption | Fernet (cryptography) |
| WebSocket | python-socketio |
| Windows | python-winrm (Kerberos/NTLM) |
| Linux | asyncssh / paramiko |
| Deploy | Docker Compose, Traefik |
## Project Structure
```
insight-updater/
├── backend/
│ ├── app/
│ │ ├── api/ # REST routes
│ │ ├── core/ # config, security, db
│ │ ├── models/ # SQLAlchemy models
│ │ ├── schemas/ # Pydantic schemas
│ │ ├── services/ # winrm, ssh, cau, audit
│ │ ├── websocket/ # Socket.io handlers
│ │ └── main.py
│ ├── tests/
│ ├── Dockerfile
│ ├── pyproject.toml
│ └── requirements.txt
├── frontend/
│ ├── src/
│ │ ├── components/
│ │ ├── views/
│ │ ├── stores/
│ │ ├── api/
│ │ └── main.ts
│ ├── Dockerfile
│ ├── nginx.conf
│ ├── package.json
│ └── vite.config.ts
├── docker-compose.yml # Development
├── docker-compose.prod.yml # Production
├── .env.example
├── .gitignore
├── AGENTS.md
├── PROMPT.md
└── README.md
```
## Environment Variables
Key variables (see `.env.example` for full list):
| Variable | Description |
|----------|-------------|
| `SECRET_KEY` | JWT signing key (32+ chars) |
| `ENCRYPTION_KEY` | Fernet key for credentials (32 bytes base64) |
| `DATABASE_URL` | SQLite (dev) or PostgreSQL (prod) |
| `WINRM_TRANSPORT` | `ntlm` \| `kerberos` \| `credssp` |
| `LDAP_ENABLED` | Enable LDAP auth stub |
| `JWT_PRIVATE_KEY_PATH` | Path to RS256 private key |
| `JWT_PUBLIC_KEY_PATH` | Path to RS256 public key |
## Development Commands
## Development
```bash
# Backend
cd backend
pip install -e .
uvicorn app.main:app --reload
# Run tests
pytest -v
# Lint
ruff check .
mypy .
cd backend && pip install -e . && uvicorn app.main:app --reload
# Frontend
cd frontend
npm install
npm run dev
cd frontend && npm install && npm run dev
# Build
npm run build
# Type check
vue-tsc --noEmit
# Satellite (lokaler Test gegen Dev-Zentrale)
cd satellite && pip install -e . && insight-satellite
```
## API Documentation
- Swagger UI: `http://localhost:8000/docs`
- ReDoc: `http://localhost:8000/redoc`
- WebSocket: `ws://localhost:8000/ws/updates`
## License
MIT Insight IT
MIT - Insight IT