news
This commit is contained in:
60
docker/Dockerfile
Normal file
60
docker/Dockerfile
Normal file
@@ -0,0 +1,60 @@
|
||||
# syntax=docker/dockerfile:1.6
|
||||
|
||||
FROM python:3.11-slim AS runtime
|
||||
|
||||
ENV PYTHONUNBUFFERED=1 \
|
||||
PIP_NO_CACHE_DIR=1 \
|
||||
ANSIBLE_FORCE_COLOR=1
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
openssh-client \
|
||||
sshpass \
|
||||
git \
|
||||
curl \
|
||||
ca-certificates \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /opt/ansible-ui
|
||||
|
||||
RUN useradd --create-home --shell /bin/bash appuser \
|
||||
&& mkdir -p \
|
||||
/opt/ansible-ui/app \
|
||||
/opt/ansible/playbooks \
|
||||
/opt/ansible/inventories \
|
||||
/opt/ansible/ssh-keys \
|
||||
/var/lib/ansible_ui \
|
||||
/var/log/ansible_ui \
|
||||
&& chown -R appuser:appuser \
|
||||
/opt/ansible-ui \
|
||||
/opt/ansible/playbooks \
|
||||
/opt/ansible/inventories \
|
||||
/opt/ansible/ssh-keys \
|
||||
/var/lib/ansible_ui \
|
||||
/var/log/ansible_ui
|
||||
|
||||
RUN pip install --no-cache-dir \
|
||||
ansible \
|
||||
fastapi \
|
||||
uvicorn[standard] \
|
||||
jinja2 \
|
||||
python-multipart \
|
||||
aiofiles
|
||||
|
||||
COPY app /opt/ansible-ui/app
|
||||
|
||||
USER appuser
|
||||
|
||||
ENV DATA_ROOT=/opt/ansible-ui \
|
||||
PLAYBOOK_DIR=/opt/ansible/playbooks \
|
||||
INVENTORY_DIR=/opt/ansible/inventories \
|
||||
SSH_KEY_DIR=/opt/ansible/ssh-keys \
|
||||
DB_PATH=/var/lib/ansible_ui/ansible_ui.db \
|
||||
LOG_DIR=/var/log/ansible_ui \
|
||||
HTPASSWD_PATH=/opt/ansible-ui/.htpasswd
|
||||
|
||||
VOLUME ["/opt/ansible/playbooks", "/opt/ansible/inventories", "/opt/ansible/ssh-keys", "/var/lib/ansible_ui", "/var/log/ansible_ui"]
|
||||
|
||||
EXPOSE 8000
|
||||
|
||||
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
|
||||
29
docker/docker-compose.yml
Normal file
29
docker/docker-compose.yml
Normal file
@@ -0,0 +1,29 @@
|
||||
version: "3.9"
|
||||
|
||||
services:
|
||||
web:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: docker/Dockerfile
|
||||
container_name: ansible-webui
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8000:8000"
|
||||
environment:
|
||||
DATA_ROOT: /opt/ansible-ui
|
||||
PLAYBOOK_DIR: /opt/ansible/playbooks
|
||||
INVENTORY_DIR: /opt/ansible/inventories
|
||||
SSH_KEY_DIR: /opt/ansible/ssh-keys
|
||||
DB_PATH: /var/lib/ansible_ui/ansible_ui.db
|
||||
LOG_DIR: /var/log/ansible_ui
|
||||
HTPASSWD_PATH: /opt/ansible-ui/.htpasswd
|
||||
volumes:
|
||||
- ../app:/opt/ansible-ui/app:ro
|
||||
- ../data/playbooks:/opt/ansible/playbooks
|
||||
- ../data/inventories:/opt/ansible/inventories
|
||||
- ../data/ssh-keys:/opt/ansible/ssh-keys
|
||||
- ../data/ansible_ui.db:/var/lib/ansible_ui/ansible_ui.db
|
||||
- ../data/.htpasswd:/opt/ansible-ui/.htpasswd:ro
|
||||
- ../logs:/var/log/ansible_ui
|
||||
tty: true
|
||||
stdin_open: false
|
||||
177
entwicklung/api_endpoints.md
Normal file
177
entwicklung/api_endpoints.md
Normal file
@@ -0,0 +1,177 @@
|
||||
# API Endpoints — Web‑UI für Ansible‑TUI
|
||||
|
||||
Hinweis zur Authentifizierung
|
||||
- HTTP‑Basic wird extern via .htpasswd gepflegt; Webserver setzt Auth und ggf. REMOTE_USER.
|
||||
- Die Applikation verifiziert keine internen Benutzer, erwartet ggf. REMOTE_USER zur Audit‑Zuordnung.
|
||||
|
||||
Endpunkte (MVP)
|
||||
|
||||
GET /health
|
||||
- Beschreibung: Simple Health‑Check
|
||||
- Antwort: 200 OK
|
||||
|
||||
GET /playbooks
|
||||
- Beschreibung: Liste aller hochgeladenen Playbooks (Metadaten)
|
||||
- Query: ?limit=&offset=
|
||||
- Antwort: JSON Array [{id,name,filename,uploaded_by,uploaded_at}]
|
||||
|
||||
POST /uploads
|
||||
- Beschreibung: Upload eines ZIP/TAR mit Playbook(s)
|
||||
- Konsumiert: multipart/form-data file=...
|
||||
- Validierung: MIME und Dateiendung (zip,tar,tgz), Größenlimit
|
||||
- Antwort: 201 Created + Metadaten
|
||||
|
||||
GET /playbooks/{id}
|
||||
- Beschreibung: Metadaten zu einem Playbook
|
||||
- Antwort: JSON
|
||||
|
||||
POST /playbooks/{id}/run
|
||||
- Beschreibung: Startet einen Run via systemweiter ansible-playbook CLI. Keine Nutzung von ansible-runner.
|
||||
- Body: optional JSON {inventory: string, extra_vars: object, tags: [string], become: bool}
|
||||
- Behaviour: Prozess wird vom Service gestartet; stdout/stderr werden in temporäre Dateien geschrieben.
|
||||
- Antwort: 202 Accepted {run_id}
|
||||
|
||||
GET /runs/{run_id}/status
|
||||
- Beschreibung: Statusabfrage (queued,running,success,failed)
|
||||
- Antwort: JSON {run_id,status,exit_code,started_at,finished_at}
|
||||
|
||||
GET /runs/{run_id}/output
|
||||
- Beschreibung: Holt vollständiges stdout/stderr des Runs (Text/stream)
|
||||
- Antwort: text/plain (oder chunked)
|
||||
|
||||
GET /keys
|
||||
- Beschreibung: Listet referenzierbare SSH‑Keys (nur lesend)
|
||||
- Antwort: JSON [{key_id,filename,description}]
|
||||
|
||||
GET /logs?limit=&offset=
|
||||
- Beschreibung: Zugriff auf Run‑Logs / Audit‑Einträge (keine sensiblen Daten)
|
||||
- Antwort: JSON
|
||||
|
||||
Sicherheits‑Hinweis
|
||||
- Die Applikation führt keine Änderung an SSH‑Keys oder .htpasswd durch.
|
||||
- Alle schreibenden Betriebsaufgaben (Permissions, Key‑Rollout, TLS) sind außerhalb des MVP‑Scopes.
|
||||
## Erweiterung: Onboarding API — Endpoints für automatisches Host‑Onboarding
|
||||
|
||||
Authentifizierung / Autorisierung
|
||||
- Auth via vorhandene HTTP‑Basic/.htpasswd‑Integration; Webserver stellt REMOTE_USER zur Verfügung.
|
||||
- Ops‑spezifische Endpoints (z. B. Approve) erfordern REMOTE_USER ∈ Ops‑Gruppe (Ops‑Policy).
|
||||
- Transport: Produktion erfordert TLS (Ops‑Deployment‑Voraussetzung).
|
||||
|
||||
Zusätzliche Endpoints (Übersicht)
|
||||
- POST /onboard/requests
|
||||
- GET /onboard/requests
|
||||
- GET /onboard/requests/{id}/status
|
||||
- POST /onboard/requests/{id}/approve
|
||||
- POST /onboard/requests/{id}/cancel
|
||||
- GET /onboard/jobs
|
||||
- GET /onboard/keys
|
||||
- GET /onboard/requests/{id}/logs
|
||||
|
||||
POST /onboard/requests
|
||||
- Zweck: Erstellt eine Onboarding‑Anfrage / startet ein Onboarding‑Job (sofern Pre‑Checks erfolgreich sind).
|
||||
- Auth: REMOTE_USER (any authenticated user)
|
||||
- Konsumiert: application/json
|
||||
- Payload:
|
||||
{
|
||||
"host": "192.0.2.10", // host oder IP
|
||||
"port": 22, // optional, default 22
|
||||
"login_user": "ubuntu", // Account zur initialen Login‑Phase (sudo‑fähig)
|
||||
"login_password": "secret", // nur in‑transit; wird nicht persistiert
|
||||
"desired_user": "ansible", // Benutzer, der angelegt/wenn nötig benutzt wird
|
||||
"generate_key": true, // true => Server erzeugt Schlüsselpaar (Ed25519/RSA‑4096 fallback)
|
||||
"public_key": null, // optional, wenn false und Nutzer eigenen Schlüssel liefert
|
||||
"description": "Kurzinfo",
|
||||
"options": { // optional: z. B. {"force_approve":false}
|
||||
"force_approve": false
|
||||
}
|
||||
}
|
||||
- Verhalten:
|
||||
- Validierung von Pflichtfeldern.
|
||||
- Erzeugt Onboard‑Request und Onboard‑Job, reply enthält { "job_id": "...", "status": "created" }.
|
||||
- Wenn Fingerprint nicht mit Ops known_hosts übereinstimmt, wird status = "awaiting_approval".
|
||||
- Antwort: 201 Created
|
||||
{
|
||||
"job_id": "uuid",
|
||||
"status": "created" | "awaiting_approval" | "queued"
|
||||
}
|
||||
- Fehlercodes:
|
||||
- 400 Bad Request (Validierungsfehler)
|
||||
- 401 Unauthorized
|
||||
- 429 Too Many Requests (Rate‑Limit pro User/Host)
|
||||
|
||||
GET /onboard/requests
|
||||
- Zweck: Listet Onboarding‑Requests (nur Metadaten)
|
||||
- Query: ?limit=&offset=&status=
|
||||
- Antwort: JSON Array [{job_id, host, requested_by, status, created_at, fingerprint_sha256?}]
|
||||
|
||||
GET /onboard/requests/{id}/status
|
||||
- Zweck: Statusabfrage für einen Request
|
||||
- Antwort:
|
||||
{
|
||||
"job_id": "...",
|
||||
"host": "...",
|
||||
"status": "created|queued|running|awaiting_approval|approved|onboarded|failed|cancelled",
|
||||
"retries": 0,
|
||||
"started_at": "...",
|
||||
"finished_at": "...",
|
||||
"error_message": "kurze Fehlerdiagnose (sensitivitäts‑gefiltert)"
|
||||
}
|
||||
|
||||
POST /onboard/requests/{id}/approve
|
||||
- Zweck: Ops‑Endpoint zur Freigabe eines abweichenden Host‑Fingerprints
|
||||
- Auth: REMOTE_USER muss Ops sein (Server‑Side check)
|
||||
- Payload:
|
||||
{
|
||||
"approve": true,
|
||||
"operator_note": "Fingerprint validiert via call",
|
||||
"operator_id": "ops-username"
|
||||
}
|
||||
- Verhalten: Wenn genehmigt, Job wird zur Fortsetzung freigegeben; Audit‑Eintrag mit operator_id erzeugt.
|
||||
- Antwort: 200 OK { "job_id": "...", "status": "approved" }
|
||||
- Fehler: 403 Forbidden (wenn nicht Ops), 404 Not Found
|
||||
|
||||
POST /onboard/requests/{id}/cancel
|
||||
- Zweck: Bricht laufenden/queued Onboarding‑Job ab (z. B. User Abbruch)
|
||||
- Auth: Requester oder Ops
|
||||
- Antwort: 200 OK { "job_id": "...", "status": "cancelled" }
|
||||
|
||||
GET /onboard/jobs
|
||||
- Zweck: Admin/Operator Sicht auf Onboard‑Jobs (Metadaten)
|
||||
- Filters: status, requested_by, host
|
||||
- Antwort: Array von job‑Metadaten (keine sensitiven Inhalte)
|
||||
|
||||
GET /onboard/keys
|
||||
- Zweck: Listet erzeugte Public‑Keys (Metadaten only)
|
||||
- Antwort: [{ "key_id": "...", "host_id": "...", "public_key_fingerprint": "...", "created_at": "..." }]
|
||||
|
||||
GET /onboard/requests/{id}/logs
|
||||
- Zweck: Liefert redigierte Logs des Onboarding‑Jobs (Ausgaben, Schritte)
|
||||
- Sicherheits‑Hinweis: Logs sind gesäubert; keine Passwörter oder private Key‑Material enthalten.
|
||||
- Antwort: text/plain oder JSON { "lines":[ ... ] }
|
||||
|
||||
Sicherheits‑Hinweise für API‑Design
|
||||
- Login‑Password darf niemals geloggt werden; im API‑Server mittelbar nur in‑memory übergeben.
|
||||
- API darf niemals privaten Schlüssel in Responses zurückliefern.
|
||||
- Alle Endpoints, die sensible Ablaufsteuerung erlauben (approve, cancel), müssen REMOTE_USER‑Checks durchführen.
|
||||
- Rate‑Limits: Schutz gegen bruteforce / DOS.
|
||||
- Input‑Sanitization: host/username dürfen keine Shell‑Injection ermöglichen; SSH‑Interaktionen erfolgen kontrolliert.
|
||||
- Audit: Jeder state‑wechsel (created, awaiting_approval, approved, onboarded, failed, cancelled) schreibt ein Metadaten‑Audit (siehe [`webapp/entwicklung/schema.sql`](webapp/entwicklung/schema.sql:1) Anpassungen).
|
||||
|
||||
Mapping UI ↔ API
|
||||
- UI‑Form "Host Onboarding" ↟ POST /onboard/requests
|
||||
- UI‑Ops Dashboard ↟ GET /onboard/requests?status=awaiting_approval
|
||||
- UI‑Ops Approve Button ↟ POST /onboard/requests/{id}/approve
|
||||
- UI‑User Status Polling ↟ GET /onboard/requests/{id}/status
|
||||
- UI‑Logs ↟ GET /onboard/requests/{id}/logs
|
||||
|
||||
Beispiel‑Flow (Kurz)
|
||||
1. User sendet POST /onboard/requests mit login_password.
|
||||
2. API antwortet job_id.
|
||||
3. Onboarding Service führt Pre‑Check aus; bei Fingerprint‑Mismatch → awaiting_approval.
|
||||
4. Ops Approver ruft POST /onboard/requests/{id}/approve → Service fährt fort.
|
||||
5. Job schreibt audit_logs und setzt Host Status auf onboarded oder failed.
|
||||
|
||||
Referenzen zur weiteren Anpassung
|
||||
- Architektur: [`webapp/entwicklung/architektur.md`](webapp/entwicklung/architektur.md:1)
|
||||
- DB Schema: [`webapp/entwicklung/schema.sql`](webapp/entwicklung/schema.sql:1)
|
||||
- Roadmap: [`webapp/entwicklung/roadmap.md`](webapp/entwicklung/roadmap.md:1)
|
||||
149
entwicklung/architektur.md
Normal file
149
entwicklung/architektur.md
Normal file
@@ -0,0 +1,149 @@
|
||||
# Architektur — Web‑UI für Ansible‑TUI
|
||||
|
||||
Kurzer Überblick
|
||||
Dieses Dokument beschreibt die finale Architektur für das MVP Web‑UI gemäß dem gewählten Profil:
|
||||
Minimal — extern gepflegte .htpasswd, direkte ansible‑playbook‑CLI, ZIP/TAR‑Uploads, SSH‑Keys nur abgelegt.
|
||||
|
||||
Authentifizierung
|
||||
- Nur externe .htpasswd zur HTTP‑Basic‑Authentifizierung.
|
||||
- Die Applikation validiert Anfragen gegen die Webserver‑auth (keine DB‑Sync, keine interne Benutzerverwaltung).
|
||||
- Betrieb: Ops pflegt .htpasswd; die Applikation nimmt keine Änderungen an .htpasswd vor.
|
||||
|
||||
Executor
|
||||
- Playbooks werden durch Aufruf der systemweiten ansible‑playbook CLI ausgeführt.
|
||||
- Kein Einsatz von ansible‑runner oder eines persistenten Hintergrund‑Executors im MVP.
|
||||
- Die Applikation erstellt bei Bedarf temporäre Arbeitsverzeichnisse, schreibt erforderliche Metadaten und ruft ansible‑playbook mit den passenden Parametern.
|
||||
|
||||
SSH‑Key‑Handling
|
||||
- SSH‑Keys werden als Dateien im Dateisystem abgelegt (Uploads oder durch Ops bereitgestellt).
|
||||
- Die Applikation ändert keine Besitz‑ oder Berechtigungsattribute; Berechtigungsmanagement liegt bei den Betriebsprozessen/Opsteam.
|
||||
- Keys werden referenziert, aber nicht automatisch verteilt oder in externe Stores synchronisiert.
|
||||
|
||||
Netzwerk / Deployment
|
||||
- Kein integrierter Reverse‑Proxy oder TLS im MVP.
|
||||
- Container/Service horcht direkt auf Port 8000 (HTTP).
|
||||
- TLS, Reverse‑Proxy oder Ingress werden von der Ziel‑Betriebsumgebung bereitgestellt und in späteren Releases integriert.
|
||||
|
||||
Uploads / Artefakte
|
||||
- Unterstützte Uploads: ZIP und TAR. Eingangsprüfung auf erlaubte Dateitypen und Größenlimits.
|
||||
- Entpackung erfolgt in sicheren, temporären Verzeichnissen; keine automatische Ausführung von hochgeladenem Code außer kontrollierten Ansible‑Playbooks.
|
||||
|
||||
Persistenz / Datenbank
|
||||
- Minimales MVP vermeidet eigene Benutzer‑DB. Falls Metadaten nötig sind, begrenzt auf leichtgewichtige lokale Speicherung (z. B. SQLite).
|
||||
- Keine Speicherung sensitiver Geheimnisse in der Applikations‑DB; Secrets verbleiben unter Ops‑Verwaltung.
|
||||
|
||||
Sicherheitshinweise
|
||||
- Ops ist verantwortlich für sichere Aufbewahrung und Rollout von .htpasswd und SSH‑Keys.
|
||||
- Applikationslogs vermeiden sensitive Inhalte; Playbook‑Outputs können ggf. redigiert werden.
|
||||
|
||||
Offene Fragen
|
||||
- Keine offenen Fragen — alle Entscheidungen sind gemäß dem Minimal‑Profil finalisiert.
|
||||
## Erweiterung: Automatisches Host‑Onboarding (Feature‑Spec)
|
||||
|
||||
Zweck
|
||||
- Erlaubt automatisches Onboarding neuer Zielhosts mit wählbaren Optionen:
|
||||
1. Pro‑Host SSH‑Key: serverseitig erzeugtes Schlüsselpaar (Ed25519, Fallback RSA‑4096).
|
||||
2. Login per Username + temporärem Passwort (Sudo‑fähiger Account) für initiale Berechtigungsaufgaben.
|
||||
3. Passwort wird nur einmalig verwendet und danach unverzüglich verworfen.
|
||||
|
||||
Kontext / Referenzen
|
||||
- Diese Erweiterung baut auf bestehender Architektur auf; siehe Hauptdokumentation und API‑Liste: [`webapp/entwicklung/api_endpoints.md`](webapp/entwicklung/api_endpoints.md:1), DB‑Schema: [`webapp/entwicklung/schema.sql`](webapp/entwicklung/schema.sql:1) und Roadmap: [`webapp/entwicklung/roadmap.md`](webapp/entwicklung/roadmap.md:1).
|
||||
|
||||
Design‑Prinzipien (Policy: Strict Ops‑First)
|
||||
- Schlüssel: Ed25519 wird erzeugt. Falls Client/Host Ed25519 nicht unterstützt, Fallback RSA‑4096.
|
||||
- Host‑Fingerprint: strikt — Fingerprint muss mit Ops' known_hosts übereinstimmen oder vorab durch Ops manuell freigegeben werden. Abweichende Fingerprints erzeugen eine Onboarding‑Sperre (Ops‑Review).
|
||||
- Privater Schlüssel: niemals persistent auf Datenträger; nur im RAM des Onboarding‑Jobs verfügbar, nur für die Dauer des Jobs.
|
||||
- Passwort: nur im RAM gehalten; nach erfolgreichem Onboarding sofort unwiederbringlich verworfen. Bei Fehlern sind maximal 3 unmittelbare Retries erlaubt, danach Ops‑Intervention.
|
||||
- Audit: nur Metadaten (username, host, fingerprint‑SHA256, event=start|success|fail, timestamp, operator_id bei manueller Freigabe). Keine Passwörter oder Private‑Key‑Material in Logs oder DB. Audit‑Retention: 365 Tage.
|
||||
|
||||
Komponenten (Erweiterung)
|
||||
- Onboarding UI (neues Formular, siehe API‑Mapping).
|
||||
- Onboarding API (neue Endpoints; Auth via HTTP‑Basic/REMOTE_USER).
|
||||
- Onboarding Service / Job Runner (zuständig für Erzeugung Key, SSH‑Verbindung, sudo‑Aufgaben, Key‑Copy).
|
||||
- Ops Approval Queue (falls Host‑Fingerprint nicht bekannt).
|
||||
- DB Erweiterungen (Hosts‑Tabelle, Onboard‑Jobs, Key‑Referenzen, ephemeral markers) — siehe vorgeschlagene Schema‑Änderungen in [`webapp/entwicklung/schema.sql`](webapp/entwicklung/schema.sql:1).
|
||||
- Audit‑Subsystem: schreibt streng limitierte Events in audit_logs mit Tagging.
|
||||
|
||||
Prozessablauf (High‑Level)
|
||||
- UI: Benutzer öffnet "Host Onboarding" Formular und gibt ein: hostname/ip, ssh_port (optional), username (für initiales Passwort‑Login), temporäres Passwort (nur wenn Option 2 gewählt), gewünschter Ziel‑Benutzername (z. B. ansible user) und evtl. Beschreibung.
|
||||
- API: POST /onboard/requests erzeugt Onboard‑Request, validiert Felder, erstellt Onboard‑Job und antwortet mit job_id.
|
||||
- Pre‑Checks: Onboarding Service prüft Erreichbarkeit (TCP), prüft Host‑Fingerprint gegen Ops known_hosts.
|
||||
- Falls Fingerprint unbekannt/abweichend: Job wird in Ops‑Approval‑Queue gestellt; API gibt status=awaiting_approval zurück.
|
||||
- Falls Fingerprint OK: Fortsetzung.
|
||||
- Key Generation: Service erzeugt temporäres Schlüsselpaar (Ed25519 oder RSA‑4096); privater Schlüssel bleibt nur in‑memory.
|
||||
- SSH Login: Service stellt SSH‑Sitzung mit provided username+password auf. Die Login‑Phase verwendet sichere in‑memory Credentials; Zeitüberschreitung/Fehler führen zu Retry (max 3).
|
||||
- Privilegien: Service führt via sudo (password prompted, one‑time use) die notwendigen Befehle aus (Erstellen Zieluser, setfacl/chown, Erstellen ~/.ssh, Deploy public key).
|
||||
- Key‑Copy: öffentlicher Schlüssel wird in das target user's authorized_keys geschrieben; Dateirechte gesetzt.
|
||||
- Verifizieren: Service versucht Login per SSH‑Key (key auth) und optional überprüft sudo‑Ausführung ohne Passwort (wenn operator gewünscht).
|
||||
- Abschluss: Bei Erfolg markiert Job als completed, privater Schlüssel wird verworfen, Onboard‑Result in DB/Audit geschrieben. Bei Fehlern: bis 3 Retries, danach markiert als failed und Ops benachrichtigt.
|
||||
- Cleanup: temporäre Verzeichnisse/Handles werden gelöscht, keine sensible Persistenz.
|
||||
|
||||
Mermaid: Ablaufdiagramm (vereinfachte Darstellung)
|
||||
```
|
||||
graph TB
|
||||
UI[User nutzt Onboarding‑Formular]
|
||||
API[POST /onboard/requests]
|
||||
JOB[Onboarding Service: Job erstellt]
|
||||
PRECHK[Pre‑Checks: TCP + Fingerprint vs Ops known_hosts]
|
||||
APPROVE[Ops Approval Queue]
|
||||
KEYGEN[Key‑Erzeugung: Ed25519 / RSA‑4096]
|
||||
SSHLOGIN[SSH Login mit User+Passwort (RAM)]
|
||||
SUDO[Sudo‑Aufgaben: create user, setup ~/.ssh, copy pubkey]
|
||||
VERIFY[Verify key auth]
|
||||
SUCCESS[Onboarding success -> Audit + DB]
|
||||
FAIL[Onboarding failed -> Audit + Ops Benachrichtigung]
|
||||
|
||||
UI --> API --> JOB --> PRECHK
|
||||
PRECHK -- match --> KEYGEN --> SSHLOGIN --> SUDO --> VERIFY --> SUCCESS
|
||||
PRECHK -- mismatch --> APPROVE --> JOB
|
||||
VERIFY -- ok --> SUCCESS
|
||||
VERIFY -- nok --> FAIL
|
||||
```
|
||||
|
||||
Schnittstellen / Integration (Kurz)
|
||||
- Neue API Endpoints (voll spezifiziert in [`webapp/entwicklung/api_endpoints.md`](webapp/entwicklung/api_endpoints.md:1)):
|
||||
- POST /onboard/requests — erstellt Onboarding‑Request, Payload enthält host, port, username, password (nur in‑transit), desired_user, options (generate_key: true/false), description.
|
||||
- GET /onboard/requests/{id}/status — Jobstatus, ops approval indicator.
|
||||
- POST /onboard/requests/{id}/approve — Ops endpoint zum Freigeben eines Fingerprints (Auth: REMOTE_USER muss Ops sein).
|
||||
- GET /onboard/keys — listet public keys erzeugt (readonly metadata).
|
||||
- GET /onboard/jobs — Liste der Onboarding Jobs (nur Metadaten).
|
||||
- Sicherheit: Passwords ONLY accepted via HTTPS (Ops deployment requirement). App muss niemals persistieren Passwörter; API akzeptiert Passwort im Request Body, Job Runner liest ihn und löscht danach.
|
||||
|
||||
DB‑Änderungen (high level; detail in schema.sql)
|
||||
- Neue Tabelle hosts:
|
||||
- id, hostname/ip, primary_key_id (FK), fingerprint_sha256, onboarded_at, onboarded_by, status (pending/awaiting_approval/onboarded/failed), created_at
|
||||
- Neue Tabelle onboard_jobs:
|
||||
- id, host_id, requested_by, desired_user, options_json, retries, status, started_at, finished_at, error_message
|
||||
- ssh_keys erweitert / referenziert (public key metadata only; private key never stored)
|
||||
- audit_logs Nutzung: nur Metadaten (wie oben)
|
||||
|
||||
Sicherheits‑ und Audit‑Aspekte (Details)
|
||||
- Passwort‑Handling:
|
||||
- Password im API‑Request wird unmittelbar dem Job übergeben und nur im RAM gehalten.
|
||||
- Nach Jobabschluss oder nach Fehlern/Timeouts wird der Speicher unverzüglich ohne Swap/Logging freigegeben.
|
||||
- Implementationshinweis: nutze sichere Speicher‑APIs (mmap mit mlock wenn möglich) oder Host‑Mechanismen, um Swapping zu verhindern.
|
||||
- Private Key Handling:
|
||||
- Erzeugung im Job‑Prozess oder in isolierter Secure Enclave; privater Key nie auf Disk.
|
||||
- Wenn Ops‑Review/Transfer erforderlich, Key kann kurzfristig (maximal Job‑Dauer) in verschlüsseltem Prozess‑Speicher gehalten werden; standardmäßig verboten.
|
||||
- Fingerprint Handling:
|
||||
- Vergleich gegen Ops known_hosts (Ops liefert Pfad oder API für known_hosts‑Hash).
|
||||
- Bei Mismatch: keine automatische Akzeptanz; Ops‑Approval erforderlich.
|
||||
- Auditing:
|
||||
- Erfasste Felder: event_type, job_id, host, fingerprint_sha256, requested_by, operator_id (bei approval), short status message, timestamp.
|
||||
- Keine Speicherung sensibler Inhalte (kein Passwort, kein privater Key).
|
||||
- Audit‑Retention: 365 Tage; älterer Einträge werden anonymisiert oder gelöscht gemäß Ops‑Policy.
|
||||
- Log‑Sanitization:
|
||||
- Playbook/SSH Outputs werden auf sensitive Patterns geprüft/redigiert bevor sie persistiert oder angezeigt werden.
|
||||
|
||||
Betriebsverantwortung / Ops‑Aufgaben
|
||||
- Ops liefert trusted known_hosts repository oder API‑Endpoint zur Fingerprint‑Prüfung.
|
||||
- Ops sorgt für Transport‑TLS und sichere Deployment‑Konfiguration (no plaintext HTTP in Prod).
|
||||
- Ops prüft und genehmigt Host‑Fingerprints in Approval‑Queue.
|
||||
- Ops führt periodische Reviews/Key‑Rotation durch (nicht automatisch durch App).
|
||||
|
||||
Nächste Schritte (Dokumentation)
|
||||
- API‑Specs aktualisieren: [`webapp/entwicklung/api_endpoints.md`](webapp/entwicklung/api_endpoints.md:1)
|
||||
- Schema‑Änderungen in: [`webapp/entwicklung/schema.sql`](webapp/entwicklung/schema.sql:1)
|
||||
- Roadmap: neue Phase "Onboarding" mit Aufwandsschätzung und Meilensteine: [`webapp/entwicklung/roadmap.md`](webapp/entwicklung/roadmap.md:1)
|
||||
|
||||
(Ende Erweiterung)
|
||||
57
entwicklung/roadmap.md
Normal file
57
entwicklung/roadmap.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# Roadmap — Web-UI für Ansible-TUI (Minimal-Profil)
|
||||
|
||||
## Überblick
|
||||
- Ziel: Bereitstellung einer schlanken Web-UI, die Ansible-Playbooks per CLI startet.
|
||||
- Authentifizierung erfolgt ausschließlich via extern gepflegter .htpasswd.
|
||||
- SSH-Keys werden nur abgelegt und referenziert; Berechtigungen bleiben bei Ops.
|
||||
- Keine Reverse-Proxy/TLS-Komponente im MVP; Service lauscht direkt auf Port 8000.
|
||||
- Hochgeladene Artefakte: ZIP/TAR.
|
||||
- Geplante Erweiterung: Automatisches Host-Onboarding (Strict Ops-First Policy) nach MVP-Release, abgestimmt mit [`webapp/entwicklung/architektur.md`](webapp/entwicklung/architektur.md:1) und [`webapp/entwicklung/api_endpoints.md`](webapp/entwicklung/api_endpoints.md:1).
|
||||
|
||||
## Phase 0 – Vorbereitung (Woche 1)
|
||||
- Container-Basisimage finalisieren, Port 8000 exponieren.
|
||||
- Ordnerstruktur für Uploads, temporäre Runs und SSH-Key-Ablage anlegen.
|
||||
- Integration der Webserver-Basic-Auth (Übernahme REMOTE_USER, Fehlermeldungen).
|
||||
- Dokumentation für Ops zur Pflege der .htpasswd erstellen.
|
||||
|
||||
## Phase 1 – Implementierung Kernfunktionen (Woche 2–3)
|
||||
- Datei-Uploads (ZIP/TAR) inkl. Validierung implementieren.
|
||||
- Playbook-Metadaten persistieren laut [`schema.sql`](webapp/entwicklung/schema.sql:1).
|
||||
- CLI-Executor: Wrapper für ansible-playbook inkl. Parameteraufbereitung.
|
||||
- Run-Verwaltung (Status, Logpfade) bauen.
|
||||
- Read-only-API zur SSH-Key-Liste implementieren.
|
||||
- API-Endpunkte gemäß [`api_endpoints.md`](webapp/entwicklung/api_endpoints.md:1) fertigstellen.
|
||||
|
||||
## Phase 2 – Tests & Härtung (Woche 4)
|
||||
- Funktionale Tests für Upload, Run-Start, Statuspolling.
|
||||
- CLI-Aufruf unter verschiedenen Inventaren/Variablen validieren.
|
||||
- Security-Checks: Keine Speicherung sensitiver Daten, Log-Redaktion.
|
||||
- Belastungstest der Upload/Polling-Flows (einfacher Load-Test).
|
||||
- Container-Image Review (kein TLS, nur HTTP).
|
||||
|
||||
## Phase 3 – Release & Ops Handover (Woche 5)
|
||||
- Build-/Release-Pipeline konfigurieren (Container Registry).
|
||||
- Deployment-Checkliste erstellen (Port 8000, externe TLS-Schicht durch Ops).
|
||||
- Monitoring-Anbindung (Basis: Health Endpoint, Log-Verfügbarkeit).
|
||||
- Go-Live-Freigabe und Übergabe an Ops inkl. Betriebsdokumentation.
|
||||
|
||||
## Phase 4 – Automatisches Host-Onboarding (Woche 6–9)
|
||||
- Architektur- und Security-Review abschließen; Spezifikation finalisieren (Strict Ops-First Policy, siehe [`webapp/entwicklung/architektur.md`](webapp/entwicklung/architektur.md:1)).
|
||||
- Datenbankmigrationen und Service-Layer implementieren (Hosts, Onboard-Jobs, Key-Metadaten) gemäß [`webapp/entwicklung/schema.sql`](webapp/entwicklung/schema.sql:1).
|
||||
- Backend: Onboarding-Service & Job-Runner (Key-Erzeugung, Fingerprint-Prüfung, sudo-Tasks) plus API-Endpunkte & Rate-Limits laut [`webapp/entwicklung/api_endpoints.md`](webapp/entwicklung/api_endpoints.md:1).
|
||||
- UI/UX: Onboarding-Formular, Status-Detailansicht, Ops-Approval-Dashboard inkl. Log-Viewer.
|
||||
- QA & Security: Integrationstests, Sudo-/SSH-Härtung, Pen-Test light, Memory-Handling-Checks (keine Persistenz von Passwort/Secret).
|
||||
- Ops Enablement: Prozesse für known_hosts-Sync, Runbooks, Alerting, Eskalationspfade; Schulung der Ops-Gruppe.
|
||||
- Staging-Dryrun mit realistischem Host; Post-Mortem + Go/No-Go Entscheidung.
|
||||
- Abhängigkeiten: Abschluss Phase 1–3, verfügbare Ops-Ressourcen für Fingerprint-Freigaben und Sicherheitstests.
|
||||
|
||||
## Post-MVP Backlog
|
||||
- Integrierter Reverse-Proxy/TLS-Termination.
|
||||
- Erweiterter Credential-Store oder Secrets-Management.
|
||||
- Rollenbasierte Zugriffssteuerung jenseits .htpasswd.
|
||||
- UI-Verbesserungen für Run-Output (Streaming, Filter).
|
||||
- Automatisierte Key-Rotation inklusive Berechtigungsupdates.
|
||||
- Self-Service Ops Workflow für Re-Onboarding/Key-Rotation (Erweiterung der Onboarding-Plattform).
|
||||
|
||||
## Offene Fragen
|
||||
- Keine; Onboarding-Policy (Strict Ops-First) und Sicherheitsvorgaben abgestimmt.
|
||||
114
entwicklung/schema.sql
Normal file
114
entwicklung/schema.sql
Normal file
@@ -0,0 +1,114 @@
|
||||
-- Schema für minimale Metadatenhaltung (SQLite-kompatibel)
|
||||
-- Profil: Minimal — externe .htpasswd, direkte ansible-playbook CLI, SSH-Keys nur abgelegt
|
||||
-- Hinweis: Keine sensitiven Secrets oder Passwörter werden in dieser DB gespeichert.
|
||||
-- Erweiterung: Automatisches Host-Onboarding (Strict Ops-First Policy)
|
||||
|
||||
PRAGMA foreign_keys = ON;
|
||||
|
||||
CREATE TABLE playbooks (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
filename TEXT NOT NULL UNIQUE,
|
||||
uploaded_by TEXT,
|
||||
uploaded_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE runs (
|
||||
id TEXT PRIMARY KEY,
|
||||
playbook_id INTEGER NOT NULL,
|
||||
inventory TEXT,
|
||||
extra_vars_json TEXT, -- JSON-codierte Extra-Variablen
|
||||
tags_json TEXT, -- JSON-codierte Tags
|
||||
become INTEGER NOT NULL DEFAULT 0,
|
||||
status TEXT NOT NULL, -- queued|running|success|failed
|
||||
exit_code INTEGER,
|
||||
started_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
finished_at DATETIME,
|
||||
stdout_path TEXT, -- Dateipfad zu stdout
|
||||
stderr_path TEXT, -- Dateipfad zu stderr
|
||||
FOREIGN KEY(playbook_id) REFERENCES playbooks(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- Host-Onboarding: Hosts und Jobs
|
||||
CREATE TABLE hosts (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
host_identifier TEXT NOT NULL UNIQUE, -- FQDN oder IP
|
||||
port INTEGER NOT NULL DEFAULT 22,
|
||||
fingerprint_sha256 TEXT, -- SHA256 des Host-Keys (nur Fingerprint)
|
||||
fingerprint_status TEXT NOT NULL DEFAULT 'pending', -- pending|verified|mismatch
|
||||
status TEXT NOT NULL DEFAULT 'pending', -- pending|awaiting_approval|onboarded|failed|cancelled
|
||||
description TEXT,
|
||||
requested_by TEXT,
|
||||
approved_by TEXT,
|
||||
approved_at DATETIME,
|
||||
onboarded_at DATETIME,
|
||||
last_error TEXT,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME
|
||||
);
|
||||
|
||||
CREATE TABLE onboard_jobs (
|
||||
id TEXT PRIMARY KEY, -- UUID
|
||||
host_id INTEGER NOT NULL,
|
||||
requested_by TEXT NOT NULL,
|
||||
login_user TEXT NOT NULL,
|
||||
desired_user TEXT NOT NULL,
|
||||
options_json TEXT, -- JSON-codierte Optionen/Flags
|
||||
approval_required INTEGER NOT NULL DEFAULT 0,
|
||||
approved_by TEXT,
|
||||
approved_at DATETIME,
|
||||
status TEXT NOT NULL, -- created|queued|running|awaiting_approval|approved|onboarded|failed|cancelled
|
||||
retries INTEGER NOT NULL DEFAULT 0,
|
||||
max_retries INTEGER NOT NULL DEFAULT 3,
|
||||
started_at DATETIME,
|
||||
finished_at DATETIME,
|
||||
error_code TEXT,
|
||||
error_message TEXT,
|
||||
last_fingerprint_sha256 TEXT, -- Fingerprint zuletzt geprüft
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY(host_id) REFERENCES hosts(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE ssh_keys (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
key_id TEXT NOT NULL UNIQUE,
|
||||
host_id INTEGER UNIQUE, -- Pro Host genau ein aktiver Key
|
||||
key_type TEXT NOT NULL, -- ed25519|rsa4096|external
|
||||
public_key TEXT, -- Öffentlicher Schlüssel (optional für extern verwaltete Keys)
|
||||
fingerprint_sha256 TEXT NOT NULL UNIQUE,
|
||||
managed_externally INTEGER NOT NULL DEFAULT 0, -- 0: App erzeugt/verwalten, 1: Ops verwaltet
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY(host_id) REFERENCES hosts(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE audit_logs (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
run_id TEXT,
|
||||
onboard_job_id TEXT,
|
||||
host_id INTEGER,
|
||||
category TEXT NOT NULL,
|
||||
message TEXT NOT NULL,
|
||||
metadata_json TEXT, -- JSON-kodierte Zusatzinfos (z. B. Fingerprint-Hash)
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY(run_id) REFERENCES runs(id) ON DELETE SET NULL,
|
||||
FOREIGN KEY(onboard_job_id) REFERENCES onboard_jobs(id) ON DELETE SET NULL,
|
||||
FOREIGN KEY(host_id) REFERENCES hosts(id) ON DELETE SET NULL
|
||||
);
|
||||
|
||||
CREATE INDEX idx_runs_playbook ON runs(playbook_id);
|
||||
CREATE INDEX idx_runs_status ON runs(status);
|
||||
|
||||
CREATE INDEX idx_hosts_status ON hosts(status);
|
||||
CREATE INDEX idx_hosts_fingerprint_status ON hosts(fingerprint_status);
|
||||
|
||||
CREATE INDEX idx_onboard_jobs_host ON onboard_jobs(host_id);
|
||||
CREATE INDEX idx_onboard_jobs_status ON onboard_jobs(status);
|
||||
|
||||
CREATE INDEX idx_ssh_keys_fingerprint ON ssh_keys(fingerprint_sha256);
|
||||
|
||||
CREATE INDEX idx_audit_logs_run ON audit_logs(run_id);
|
||||
CREATE INDEX idx_audit_logs_job ON audit_logs(onboard_job_id);
|
||||
CREATE INDEX idx_audit_logs_host ON audit_logs(host_id);
|
||||
|
||||
-- Alle Betriebsaufgaben (Pflege .htpasswd, TLS, SSH-Key Berechtigungen) liegen außerhalb der Applikation.
|
||||
-- Onboarding-Policy: Privater Schlüssel und Passwörter werden nicht persistiert; nur Fingerprints und Metadaten.
|
||||
Reference in New Issue
Block a user