first commit
This commit is contained in:
547
Jumphost_Konzept.md
Normal file
547
Jumphost_Konzept.md
Normal file
@ -0,0 +1,547 @@
|
||||
# Konzept: Sicherer Multi-Protokoll-Jumphost (SSH/RDP) mit Web-Gateway
|
||||
|
||||
**Version:** 0.2 (Entwurf) | **Datum:** 19.08.2026 | **Autor:** Konzepterstellung für Midas
|
||||
|
||||
**Änderungen gegenüber v0.1:** Grundannahme „Jumphost läuft auf Linux" bestätigt; TLS-Zertifikatsmodi für den nginx-Betrieb ergänzt (internes PKI-Zertifikat auf dem Jumphost selbst **oder** vorgelagerter externer Reverse Proxy mit eigener PKI/TLS-Terminierung), siehe Kap. 6.3, 7.2 und 9.
|
||||
|
||||
## Inhaltsverzeichnis
|
||||
|
||||
1. Zielsetzung & Grundannahmen
|
||||
2. Anforderungsübersicht
|
||||
3. Architekturüberblick
|
||||
4. Komponentenbeschreibung
|
||||
5. Datenmodell (SQLite)
|
||||
6. Security- und Hardening-Konzept
|
||||
7. Ansible-Deployment-Konzept
|
||||
8. Systemd-Services
|
||||
9. Betrieb mit vs. ohne nginx
|
||||
10. Rollout-Plan & Teststrategie
|
||||
11. Technologie-Stack (Zusammenfassung)
|
||||
12. Offene Punkte & Erweiterungsoptionen
|
||||
|
||||
---
|
||||
|
||||
## 1. Zielsetzung & Grundannahmen
|
||||
|
||||
Ziel ist ein zentraler **Jumphost/Bastion-Gateway**, über den sämtlicher administrativer Zugriff auf Ziel-Systeme (Linux via SSH, Windows via RDP) erfolgt. Nutzer greifen ausschließlich **browserbasiert** auf eine Weboberfläche zu – es wird kein lokal installierter SSH- oder RDP-Client benötigt. Dadurch lassen sich Vollbildmodus, Copy & Paste, Session-Aufzeichnung und Auditierung zentral und clientunabhängig umsetzen.
|
||||
|
||||
**Grundannahmen:**
|
||||
|
||||
- Der **Jumphost-Server selbst läuft auf Linux** (Voraussetzung für systemd, empfohlen: Debian/Ubuntu LTS oder RHEL/Rocky). "Windows und Linux" bezieht sich auf die **Ziel-Systeme**, nicht auf das Betriebssystem des Jumphosts. ✅ *Bestätigt.*
|
||||
- Zielgröße: kleine bis mittlere Umgebung (bis ca. 200 Nutzer, bis ca. 1000 verwaltete Hosts). SQLite ist dafür bei korrekter Konfiguration (WAL-Modus, ein Schreibprozess) ausreichend performant. Bei deutlich höherer Last ist ein Umstieg auf PostgreSQL als Erweiterungsoption vorgesehen (siehe Kap. 12).
|
||||
- Es wird von einer **On-Premises- oder privaten Cloud-Umgebung** ausgegangen, in der der Jumphost die einzige erlaubte Route zu den Zielsystemen ist (Netzwerksegmentierung: Zielsysteme sind aus dem Nutzernetz nicht direkt erreichbar).
|
||||
|
||||
---
|
||||
|
||||
## 2. Anforderungsübersicht
|
||||
|
||||
| Anforderung | Umsetzung im Konzept |
|
||||
|---|---|
|
||||
| Jumphost für Windows- und Linux-Ziele | RDP-Proxy für Windows-Ziele, SSH-Proxy für Linux-Ziele |
|
||||
| Userverwaltung mit TOTP | Lokale Userverwaltung, Pflicht-2FA via TOTP (RFC 6238) |
|
||||
| Hostgruppen | RBAC-Modell: Rollen × Hostgruppen × Rechte |
|
||||
| SSH inkl. Keyverwaltung | Zentrale, verschlüsselte Keyverwaltung, serverseitige Nutzung, keine Key-Auslieferung an Browser |
|
||||
| RDP | Browserbasierter RDP-Client über guacd/FreeRDP |
|
||||
| Dateitransfer | SFTP-Kanal (SSH-Ziele) und Laufwerksumleitung (RDP-Ziele) |
|
||||
| Vollbild | HTML5-Client im Browser-Fullscreen-Modus |
|
||||
| Copy & Paste | Clipboard-Synchronisation über Guacamole-Protokoll, pro Hostgruppe deaktivierbar |
|
||||
| Auditlog | Manipulationssicheres, verkettetes Audit-Log aller Aktionen |
|
||||
| SQLite & Python | Backend in Python (FastAPI/ASGI), SQLite als Datenhaltung |
|
||||
| Ansible-Playbook | Rollenbasiertes Playbook, Modus mit/ohne nginx |
|
||||
| systemd Service | Gehärtete Unit-Files für alle Dienste |
|
||||
| Höchste Security/Hardening | Durchgängiges Hardening auf Anwendungs-, Transport- und OS-Ebene (Kap. 6) |
|
||||
|
||||
---
|
||||
|
||||
## 3. Architekturüberblick
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────┐
|
||||
│ Nutzer (Browser) │
|
||||
│ HTML5-Terminal (xterm.js) + Guacamole- │
|
||||
│ Client (guacamole-common-js), TOTP-Login│
|
||||
└───────────────────┬───────────────────────┘
|
||||
│ HTTPS/WSS (TLS 1.3)
|
||||
┌────────────────────────────────┼────────────────────────────────┐
|
||||
│ (optional) nginx – TLS-Terminierung, │
|
||||
│ Security-Header, Rate-Limiting, WS-Proxy │
|
||||
└────────────────────────────────┬────────────────────────────────┘
|
||||
│ (localhost / unix socket)
|
||||
┌────────────────────────────────▼────────────────────────────────┐
|
||||
│ Jumphost-App (Python, FastAPI, ASGI) │
|
||||
│ ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌──────────────────┐ │
|
||||
│ │ Auth & │ │ RBAC / │ │ Session- │ │ Audit-/Logging- │ │
|
||||
│ │ TOTP │ │ Hostgrp. │ │ Broker │ │ Engine │ │
|
||||
│ └───────────┘ └───────────┘ └───────────┘ └──────────────────┘ │
|
||||
│ ┌───────────────────┐ ┌───────────────────────────────────┐ │
|
||||
│ │ SSH-Proxy-Modul │ │ RDP-Proxy-Anbindung (guacd) │ │
|
||||
│ │ (asyncssh) │ │ via Guacamole-Protokoll │ │
|
||||
│ └─────────┬─────────┘ └───────────────┬───────────────────┘ │
|
||||
│ │ SQLite (WAL) – Users, Hosts, Keys (verschl.), │
|
||||
│ │ Sessions, Audit-Log, Hostgruppen │
|
||||
└────────────┼─────────────────────────────┬─────────────────────┘
|
||||
│ SSH (Keys aus Vault) │ Guacamole-Protokoll
|
||||
┌────────────▼───────────┐ ┌───────────▼──────────────┐
|
||||
│ Linux-Zielsysteme │ │ guacd (Protokoll-Daemon) │
|
||||
│ (SSH, SFTP) │ │ → RDP via FreeRDP │
|
||||
└─────────────────────────┘ └───────────┬───────────────┘
|
||||
│ RDP (verschl.)
|
||||
┌───────────▼──────────────┐
|
||||
│ Windows-Zielsysteme │
|
||||
└───────────────────────────┘
|
||||
```
|
||||
|
||||
**Designentscheidung RDP-Proxy:** Für RDP wird empfohlen, **nicht** das komplette Protokoll neu zu implementieren, sondern den bewährten, quelloffenen **guacd**-Daemon (Apache-Guacamole-Projekt, Protokoll-Engine inkl. FreeRDP-Anbindung) als reine Protokoll-Übersetzungskomponente einzusetzen. Die eigentliche Anwendung – Auth, TOTP, RBAC, Hostgruppen, Audit, Oberfläche – bleibt vollständig eigenentwickelt in Python/SQLite; **die Java-basierte Guacamole-Client-Webanwendung selbst wird nicht verwendet**. guacd läuft als eigener, isolierter systemd-Dienst und kommuniziert nur lokal (Unix-Socket oder localhost) mit dem Python-Backend. Für SSH wird kein guacd benötigt – hier terminiert das Python-Backend die Verbindung selbst über eine asynchrone SSH-Bibliothek (`asyncssh`) und pusht Terminal-I/O per WebSocket an `xterm.js` im Browser.
|
||||
|
||||
---
|
||||
|
||||
## 4. Komponentenbeschreibung
|
||||
|
||||
### 4.1 Backend-Anwendung (Python)
|
||||
- **Framework:** FastAPI (ASGI) mit Uvicorn/Hypercorn als Server, `asyncio`-basiert für nebenläufige Sessions.
|
||||
- **API:** REST für Verwaltung (User, Hosts, Gruppen, Keys), WebSocket-Endpunkte für Live-Sessions (SSH-Terminal-Stream, Guacamole-Protokoll-Tunnel).
|
||||
- **ORM/DB-Zugriff:** SQLAlchemy Core oder direkt `sqlite3`/`aiosqlite` mit strikt parametrisierten Queries (kein String-Concat), Pydantic-Modelle zur Validierung aller Eingaben.
|
||||
- **Templating/Frontend:** Serverseitig ausgeliefertes, schlankes SPA (z. B. mit Jinja2 + Vanilla-JS/xterm.js/guacamole-common-js), keine unnötigen externen Abhängigkeiten, Assets lokal gehostet (kein CDN-Bezug, reduziert Angriffsfläche und funktioniert offline).
|
||||
|
||||
### 4.2 SSH-Proxy-Modul
|
||||
- Verbindungsaufbau zum Zielsystem **serverseitig** über `asyncssh`, unter Verwendung des zentral verwalteten Schlüssels (siehe 4.4).
|
||||
- Der Nutzer sieht im Browser nur ein Terminal (xterm.js über WebSocket) – der private Schlüssel verlässt den Server nie.
|
||||
- **Strict Host Key Checking**: bekannte Host-Keys werden pro Zielsystem in der DB gepinnt; unbekannte/abweichende Host-Keys blockieren die Verbindung und lösen einen Alert aus (kein automatisches TOFU-Accept in Produktion).
|
||||
- Terminal-I/O wird parallel in einen Session-Recorder gestreamt (siehe 6.5).
|
||||
- Sitzungsspezifische Idle-Timeouts und harte Maximaldauer konfigurierbar pro Hostgruppe.
|
||||
|
||||
### 4.3 RDP-Proxy-Anbindung
|
||||
- Python-Backend baut einen Guacamole-Protokoll-Tunnel zu `guacd` auf (lokal, kein Netzwerkzugriff von außen).
|
||||
- `guacd` verbindet sich seinerseits per RDP (TLS-verschlüsselt, NLA aktiviert) zum Windows-Zielsystem.
|
||||
- Browser rendert die Session über `guacamole-common-js` in einem `<canvas>`-Element.
|
||||
- **Vollbild:** über die Browser-Fullscreen-API (`element.requestFullscreen()`), vom Backend nicht beeinflussbar, rein clientseitig aktivierbar per Button.
|
||||
- **Copy & Paste:** native Guacamole-Clipboard-Synchronisation (bidirektional Browser ↔ Zielsystem). Pro Hostgruppe/Verbindung serverseitig deaktivierbar (Compliance-Anforderung für hochsensible Systeme).
|
||||
- **Dateitransfer bei RDP:** über Guacamole-Laufwerksumleitung (virtuelles Laufwerk `Guacamole RDP FS`), serverseitig ein-/ausschaltbar, mit Upload-Größenlimit und optionalem AV-Scan-Hook (ClamAV) vor Freigabe.
|
||||
|
||||
### 4.4 Keyverwaltung (SSH)
|
||||
- Private Schlüssel werden **verschlüsselt in SQLite** abgelegt (AES-256-GCM), der Schlüssel-Verschlüsselungs-Schlüssel (KEK) liegt **nicht** in der Datenbank, sondern in einer separaten, restriktiv berechtigten Datei (`0600`, dedizierter Service-User) oder – empfohlen – im systemd-Credential-Store (`systemd-creds`) bzw. optional einer externen KMS/Vault-Anbindung.
|
||||
- Unterstützt werden sowohl klassische statische Schlüsselpaare (Ed25519, min. RSA-3072 falls Legacy nötig) als auch **kurzlebige, CA-signierte SSH-Zertifikate** (empfohlener Zielzustand): der Jumphost besitzt eine eigene SSH-CA, signiert bei Sessionstart ein Zertifikat mit z. B. 5 Minuten Gültigkeit, das Zielsystem vertraut nur der CA. Dadurch entfällt die Verteilung/Rotation statischer Public Keys auf allen Zielsystemen komplett.
|
||||
- Rotation: automatisierte Rotation statischer Schlüssel über Ansible-Playbook, Journaling jeder Rotation im Audit-Log.
|
||||
|
||||
### 4.5 Userverwaltung & Authentifizierung
|
||||
- Lokale User-Tabelle mit Argon2id-Passwort-Hashes (Fallback: bcrypt, falls Argon2-Bibliothek in der Zielumgebung nicht verfügbar).
|
||||
- **TOTP verpflichtend** für alle Accounts (RFC 6238, kompatibel mit gängigen Authenticator-Apps), Secret verschlüsselt gespeichert, QR-Code-Enrollment nur einmalig anzeigbar, Recovery-Codes (einmalig, gehasht gespeichert).
|
||||
- Vorbereitet für optionale spätere Erweiterung um WebAuthn/FIDO2 als Ersatz/Ergänzung zu TOTP sowie LDAP/AD-Bind als externe Quelle (siehe Kap. 12).
|
||||
- Account-Lockout nach N Fehlversuchen (progressive Verzögerung), erzwungener Passwortwechsel nach Erstanmeldung, Session-Timeout (idle + absolute).
|
||||
|
||||
### 4.6 Rollen, Hostgruppen & Rechte (RBAC)
|
||||
- **Hostgruppen** bündeln Zielsysteme (z. B. „Prod-Linux-DB", „Windows-Fileserver", „DMZ").
|
||||
- **Rollen** definieren, was ein Nutzer/eine Gruppe innerhalb einer Hostgruppe darf: `ssh_connect`, `rdp_connect`, `file_transfer`, `clipboard`, `session_recording_view` (Playback fremder Sessions, z. B. für Auditoren), `admin_hostgroup`.
|
||||
- Zuordnung erfolgt über eine Verknüpfungstabelle User/Gruppe × Hostgruppe × Rolle (siehe Datenmodell), sodass granular z. B. „Team A darf SSH auf Hostgruppe X, aber kein Copy & Paste und keinen Filetransfer" abgebildet werden kann.
|
||||
- Optional vorbereitet: zeitlich befristete/Just-in-Time-Freigaben (Access-Requests mit Ablaufzeit) als Erweiterung.
|
||||
|
||||
### 4.7 Audit-Log
|
||||
- Erfasst: Login/Logout (inkl. Fehlversuche), TOTP-Ereignisse, Sessionstart/-ende je Zielsystem, Dateitransfers (Richtung, Dateiname, Größe, Hash), Rechteänderungen, Admin-Aktionen, Verbindungsabbrüche, Host-Key-Mismatches.
|
||||
- Manipulationssicherheit: jeder Log-Eintrag enthält den Hash des Vorgängereintrags (Hash-Chain, ähnlich einer einfachen Blockchain) – nachträgliches Verändern oder Löschen einzelner Einträge wird durch Kettenbruch erkennbar. Zusätzlich optionale Ausleitung an externen Syslog/SIEM in Echtzeit (Log verlässt damit den Jumphost, unabhängige Kopie).
|
||||
- Die Audit-Tabelle ist **append-only** auf Anwendungsebene (kein UPDATE/DELETE-Pfad in der API); zusätzlich empfiehlt sich ein DB-Trigger, der `UPDATE`/`DELETE` auf der Tabelle verweigert.
|
||||
|
||||
---
|
||||
|
||||
## 5. Datenmodell (SQLite)
|
||||
|
||||
Vereinfachtes Kernschema (Auszug, ohne Indizes/Constraints der Übersicht halber gekürzt):
|
||||
|
||||
```sql
|
||||
PRAGMA journal_mode = WAL;
|
||||
PRAGMA foreign_keys = ON;
|
||||
|
||||
CREATE TABLE users (
|
||||
id INTEGER PRIMARY KEY,
|
||||
username TEXT UNIQUE NOT NULL,
|
||||
password_hash TEXT NOT NULL, -- Argon2id
|
||||
totp_secret_enc BLOB NOT NULL, -- AES-256-GCM verschlüsselt
|
||||
totp_enrolled INTEGER NOT NULL DEFAULT 0,
|
||||
is_active INTEGER NOT NULL DEFAULT 1,
|
||||
is_admin INTEGER NOT NULL DEFAULT 0,
|
||||
failed_logins INTEGER NOT NULL DEFAULT 0,
|
||||
locked_until TEXT,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
password_changed_at TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE recovery_codes (
|
||||
id INTEGER PRIMARY KEY,
|
||||
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
code_hash TEXT NOT NULL,
|
||||
used_at TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE roles (
|
||||
id INTEGER PRIMARY KEY,
|
||||
name TEXT UNIQUE NOT NULL -- z.B. ssh_connect, rdp_connect, file_transfer, clipboard, admin
|
||||
);
|
||||
|
||||
CREATE TABLE host_groups (
|
||||
id INTEGER PRIMARY KEY,
|
||||
name TEXT UNIQUE NOT NULL,
|
||||
description TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE hosts (
|
||||
id INTEGER PRIMARY KEY,
|
||||
host_group_id INTEGER NOT NULL REFERENCES host_groups(id),
|
||||
hostname TEXT NOT NULL,
|
||||
address TEXT NOT NULL,
|
||||
protocol TEXT NOT NULL CHECK (protocol IN ('ssh','rdp')),
|
||||
port INTEGER NOT NULL,
|
||||
os_type TEXT NOT NULL CHECK (os_type IN ('linux','windows')),
|
||||
ssh_host_key_fingerprint TEXT, -- Pinning für Strict Host Key Checking
|
||||
rdp_require_nla INTEGER NOT NULL DEFAULT 1,
|
||||
clipboard_enabled INTEGER NOT NULL DEFAULT 1,
|
||||
file_transfer_enabled INTEGER NOT NULL DEFAULT 1,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
);
|
||||
|
||||
CREATE TABLE ssh_keys (
|
||||
id INTEGER PRIMARY KEY,
|
||||
label TEXT NOT NULL,
|
||||
owner_user_id INTEGER REFERENCES users(id), -- NULL = shared/service key
|
||||
private_key_enc BLOB NOT NULL, -- AES-256-GCM, KEK extern
|
||||
public_key TEXT NOT NULL,
|
||||
key_type TEXT NOT NULL, -- ed25519, rsa-3072, ca-cert...
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
rotated_at TEXT,
|
||||
expires_at TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE host_ssh_key_map (
|
||||
host_id INTEGER NOT NULL REFERENCES hosts(id) ON DELETE CASCADE,
|
||||
ssh_key_id INTEGER NOT NULL REFERENCES ssh_keys(id),
|
||||
PRIMARY KEY (host_id, ssh_key_id)
|
||||
);
|
||||
|
||||
CREATE TABLE user_hostgroup_roles (
|
||||
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
host_group_id INTEGER NOT NULL REFERENCES host_groups(id) ON DELETE CASCADE,
|
||||
role_id INTEGER NOT NULL REFERENCES roles(id),
|
||||
granted_by INTEGER REFERENCES users(id),
|
||||
granted_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
expires_at TEXT, -- optionale zeitlich befristete Freigabe
|
||||
PRIMARY KEY (user_id, host_group_id, role_id)
|
||||
);
|
||||
|
||||
CREATE TABLE sessions (
|
||||
id INTEGER PRIMARY KEY,
|
||||
user_id INTEGER NOT NULL REFERENCES users(id),
|
||||
host_id INTEGER NOT NULL REFERENCES hosts(id),
|
||||
protocol TEXT NOT NULL,
|
||||
started_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
ended_at TEXT,
|
||||
client_ip TEXT NOT NULL,
|
||||
recording_path TEXT, -- Pfad/Referenz zur Session-Aufzeichnung
|
||||
end_reason TEXT -- logout, timeout, error, admin_kill
|
||||
);
|
||||
|
||||
CREATE TABLE file_transfers (
|
||||
id INTEGER PRIMARY KEY,
|
||||
session_id INTEGER NOT NULL REFERENCES sessions(id),
|
||||
direction TEXT NOT NULL CHECK (direction IN ('upload','download')),
|
||||
filename TEXT NOT NULL,
|
||||
size_bytes INTEGER NOT NULL,
|
||||
sha256 TEXT NOT NULL,
|
||||
av_scan_result TEXT,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
);
|
||||
|
||||
CREATE TABLE audit_log (
|
||||
id INTEGER PRIMARY KEY,
|
||||
ts TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
|
||||
user_id INTEGER REFERENCES users(id),
|
||||
event_type TEXT NOT NULL, -- login, login_failed, session_start, ...
|
||||
details_json TEXT NOT NULL,
|
||||
prev_hash TEXT NOT NULL,
|
||||
entry_hash TEXT NOT NULL -- sha256(prev_hash || ts || event_type || details_json)
|
||||
);
|
||||
|
||||
-- Schutz gegen nachträgliche Manipulation auf DB-Ebene:
|
||||
CREATE TRIGGER no_audit_update BEFORE UPDATE ON audit_log
|
||||
BEGIN SELECT RAISE(ABORT, 'audit_log ist append-only'); END;
|
||||
CREATE TRIGGER no_audit_delete BEFORE DELETE ON audit_log
|
||||
BEGIN SELECT RAISE(ABORT, 'audit_log ist append-only'); END;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Security- und Hardening-Konzept
|
||||
|
||||
Dies ist der **wichtigste Teil** des Konzepts und durchzieht alle Ebenen: Anwendung, Transport, Betriebssystem, Prozessisolation.
|
||||
|
||||
### 6.1 Threat-Model (Kurzfassung)
|
||||
|
||||
Wesentliche Angriffsvektoren, gegen die das Design hart absichert: kompromittierte Nutzer-Credentials (→ Pflicht-2FA, Lockout), Diebstahl von SSH-Schlüsseln (→ Keys nie im Client, Verschlüsselung at rest, CA-Zertifikate mit kurzer TTL), Man-in-the-Middle (→ TLS 1.3 only, Host-Key-Pinning), Rechteausweitung über die Web-App (→ strikte Eingabevalidierung, parametrisierte Queries, RBAC serverseitig durchgesetzt), Manipulation von Audit-Daten durch einen kompromittierten Admin-Account (→ Hash-Chain + externe Log-Ausleitung), Kompromittierung des Jumphost-Prozesses selbst (→ systemd-Sandboxing, minimale Rechte, Netzwerksegmentierung als zusätzliche Schicht).
|
||||
|
||||
### 6.2 Authentifizierung & Session-Sicherheit
|
||||
- Argon2id-Hashing (Parameter an aktuelle OWASP-Empfehlung angelehnt, z. B. m=19 MiB, t=2, p=1 als Startwert, umgebungsabhängig kalibrieren).
|
||||
- TOTP verpflichtend, kein Login ohne zweiten Faktor möglich; Secret-Verschlüsselung mit separatem Schlüssel (nicht identisch mit KEK der SSH-Keys, Prinzip der Schlüsseltrennung).
|
||||
- Rate-Limiting & progressive Lockout gegen Brute-Force (pro Account und pro Quell-IP), zusätzlich Fail2ban auf OS-Ebene als zweite Verteidigungslinie gegen Login-Endpoint-Scanning.
|
||||
- Session-Cookies: `HttpOnly`, `Secure`, `SameSite=Strict`, kurze Lebensdauer + Refresh, serverseitige Session-Invalidierung bei Passwortänderung.
|
||||
- Absolute und Idle-Timeouts pro Hostgruppe konfigurierbar; sensible Aktionen (z. B. Schlüsselverwaltung, Rechtevergabe) verlangen Re-Authentifizierung.
|
||||
|
||||
### 6.3 Transportverschlüsselung
|
||||
- **Ausschließlich TLS 1.3** (TLS 1.2 nur als Übergangs-Fallback, falls zwingend erforderlich), moderne Cipher-Suiten, HSTS mit langer `max-age` und `includeSubDomains`.
|
||||
- WebSocket-Verbindungen (Terminal-Stream, Guacamole-Tunnel) laufen ausschließlich über WSS.
|
||||
- Optional Mutual-TLS für administrative API-Zugriffe (z. B. Ansible-getriebene Konfigurationsänderungen von einer festen Management-Quelle aus).
|
||||
- Zertifikate über Ansible-Rolle verwaltet. Im nginx-Betrieb werden dabei **zwei TLS-Zertifikatsmodi** unterstützt (Details und Konfiguration siehe Kap. 7.2):
|
||||
1. **`internal_pki`** – nginx auf dem Jumphost terminiert TLS selbst, mit einem Zertifikat aus einer internen/unternehmenseigenen PKI (kein direkter Internetbezug nötig).
|
||||
2. **`external_reverse_proxy`** – ein bereits vorhandener, vorgelagerter externer Reverse Proxy/Load Balancer übernimmt die öffentliche TLS-Terminierung mit einer eigenen (unternehmensweiten oder öffentlichen) PKI; das lokale nginx auf dem Jumphost dient dann als zweite, interne Schicht.
|
||||
In beiden Fällen bleibt der Grundsatz „TLS 1.3 end-to-end bis zur Anwendung" erhalten – unverschlüsseltes internes HTTP wird nicht als Standard vorgesehen (siehe 7.2).
|
||||
|
||||
### 6.4 Schlüssel- und Geheimnisverwaltung
|
||||
- Trennung von Datenverschlüsselungsschlüsseln (DEK, in DB pro Datensatz) und Schlüsselverschlüsselungsschlüsseln (KEK, außerhalb der DB).
|
||||
- KEK-Ablage über `systemd-creds` (LoadCredentialEncrypted) oder TPM-gebundene Speicherung, wo verfügbar; alternativ Anbindung an HashiCorp Vault/OpenBao als Erweiterungsoption.
|
||||
- Keine Secrets in Ansible-Klartext-Variablen – ausschließlich über `ansible-vault` verschlüsselt, mit Vault-Passwort außerhalb des Repositories (z. B. über CI-Secret-Store oder separates Passwort-Management).
|
||||
- Konsequentes Prinzip: **kein Private Key verlässt jemals den Server-Prozess** – weder Richtung Browser noch Richtung Log.
|
||||
|
||||
### 6.5 Session-Aufzeichnung & Integrität
|
||||
- SSH-Sessions werden als Terminal-Cast (z. B. asciicast-kompatibles Format) aufgezeichnet, RDP-Sessions als Guacamole-native Aufzeichnung (serverseitig, ohne Zusatzsoftware auf dem Client).
|
||||
- Aufzeichnungen werden mit fortlaufendem Hash verkettet (analog Audit-Log), um nachträgliche Manipulation erkennbar zu machen.
|
||||
- Zugriff auf Aufzeichnungen selbst wieder RBAC-gesteuert (`session_recording_view`), jeder Playback-Zugriff wird auditiert (Audit-Log über das Audit-Log, „wer hat wessen Session angeschaut").
|
||||
- Aufbewahrungsfrist konfigurierbar, automatische Löschung/Archivierung nach Ablauf (Datenschutz-/Compliance-Anforderungen beachten, insb. bei mitgeloggtem Tastatur-Input).
|
||||
|
||||
### 6.6 Web-Anwendungs-Hardening
|
||||
- CSRF-Schutz für alle zustandsändernden Endpunkte, striktes Content-Security-Policy-Header (kein `unsafe-inline`, keine externen Script-Quellen), `X-Frame-Options: DENY`, `X-Content-Type-Options: nosniff`, `Referrer-Policy: no-referrer`.
|
||||
- Sämtliche API-Eingaben über Pydantic-Schemas validiert (Typ, Länge, Whitelist erlaubter Zeichen), Datei-Uploads mit Größenlimit, Dateityp-Prüfung (Magic-Bytes, nicht nur Endung) und optionalem AV-Scan (ClamAV) vor Freigabe zum Download durch andere Nutzer.
|
||||
- Abhängigkeiten fixiert (Lockfile), regelmäßiger Scan mit `pip-audit`/`safety` in CI, minimaler Dependency-Footprint.
|
||||
- Keine Debug-/Stacktrace-Ausgabe in Produktionsfehlermeldungen; strukturierte Fehlerbehandlung, generische Fehlermeldungen nach außen.
|
||||
|
||||
### 6.7 Betriebssystem- und Prozess-Hardening
|
||||
- Dedizierter, unprivilegierter Service-User pro Dienst (App, guacd), kein Root-Betrieb.
|
||||
- systemd-Sandboxing (Details Kap. 8): `NoNewPrivileges`, `ProtectSystem=strict`, `ProtectHome=true`, `PrivateTmp=true`, `ProtectKernelTunables`, `ProtectKernelModules`, `ProtectControlGroups`, `RestrictNamespaces`, `RestrictAddressFamilies`, `RestrictSUIDSGID`, `MemoryDenyWriteExecute`, `SystemCallFilter=@system-service`, `CapabilityBoundingSet=` minimal (nur was zwingend nötig, im Regelfall leer).
|
||||
- Firewall (nftables) im Default-Deny-Modus: eingehend nur 443/tcp (bzw. App-Port bei Betrieb ohne nginx) und ggf. 22/tcp für administrativen Zugriff auf den Jumphost selbst (idealerweise ebenfalls nur aus einem Management-Netz); ausgehend nur zu den definierten Zielsystem-Netzen.
|
||||
- Automatische Sicherheitsupdates (`unattended-upgrades`) für das Basissystem, geregelter Patch-Prozess für die Anwendung selbst.
|
||||
- `auditd` auf OS-Ebene zusätzlich zum Anwendungs-Audit-Log, insbesondere für Zugriffe auf die SQLite-Datei und Konfigurationsdateien.
|
||||
- SELinux (RHEL-Familie) bzw. AppArmor (Debian/Ubuntu)-Profil als zusätzliche Verteidigungslinie empfohlen (im Playbook als optionale Rolle vorgesehen).
|
||||
|
||||
### 6.8 Backup & Wiederherstellung
|
||||
- Verschlüsselte, regelmäßige Backups der SQLite-Datei (Achtung: konsistente Snapshots via SQLite-Online-Backup-API oder `VACUUM INTO`, nicht per einfachem Filecopy während des Betriebs).
|
||||
- KEK/Vault-Backup getrennt von DB-Backup aufbewahren (sonst hebelt ein gemeinsamer Backup-Diebstahl die Verschlüsselung aus).
|
||||
- Dokumentierter Wiederherstellungs-Testlauf als fester Bestandteil des Betriebskonzepts (mind. jährlich).
|
||||
|
||||
### 6.9 Monitoring & Alerting
|
||||
- Prometheus-Metrics-Endpoint (intern, nicht öffentlich) für aktive Sessions, fehlgeschlagene Logins, Fehlerraten.
|
||||
- Alerts bei: gehäuften Fehlversuchen, Host-Key-Mismatch, Zugriff außerhalb üblicher Zeiten/Netze, Bruch der Audit-Hash-Chain.
|
||||
- Externe Log-Ausleitung (Syslog/SIEM) als unabhängige zweite Quelle für forensische Auswertung, auch falls der Jumphost selbst kompromittiert würde.
|
||||
|
||||
---
|
||||
|
||||
## 7. Ansible-Deployment-Konzept
|
||||
|
||||
### 7.1 Rollenstruktur
|
||||
|
||||
```
|
||||
ansible/
|
||||
├── site.yml
|
||||
├── inventory/
|
||||
│ ├── production.ini
|
||||
│ └── group_vars/
|
||||
│ ├── all.yml # gemeinsame Variablen
|
||||
│ ├── jumphost_with_nginx.yml # enable_nginx_proxy: true
|
||||
│ └── jumphost_no_nginx.yml # enable_nginx_proxy: false
|
||||
├── roles/
|
||||
│ ├── os_hardening/ # CIS-nahe Basis-Härtung (Firewall, SSH-Daemon des Hosts, auditd, unattended-upgrades)
|
||||
│ ├── firewall_nftables/
|
||||
│ ├── fail2ban/
|
||||
│ ├── python_runtime/ # venv, gehärtete Paketinstallation
|
||||
│ ├── jumphost_app/ # Deployment der eigentlichen Anwendung + systemd unit
|
||||
│ ├── guacd/ # Installation guacd + FreeRDP, systemd unit, lokal gebunden
|
||||
│ ├── sqlite_init/ # Schema-Migration, Verzeichnis-/Rechtevergabe
|
||||
│ ├── tls_certificates/ # tls_mode: internal_pki | external_reverse_proxy | acme_public
|
||||
│ ├── nginx_proxy/ # NUR wenn enable_nginx_proxy: true
|
||||
│ └── backup/ # Cron/systemd-Timer für verschlüsselte Backups
|
||||
└── files/ / templates/
|
||||
```
|
||||
|
||||
### 7.2 Steuerung mit/ohne nginx
|
||||
|
||||
Die Variable `enable_nginx_proxy` (in `group_vars`) steuert per `when`-Bedingung, ob die Rolle `nginx_proxy` inkludiert wird:
|
||||
|
||||
```yaml
|
||||
# site.yml (Auszug)
|
||||
- hosts: jumphosts
|
||||
roles:
|
||||
- os_hardening
|
||||
- firewall_nftables
|
||||
- fail2ban
|
||||
- python_runtime
|
||||
- sqlite_init
|
||||
- guacd
|
||||
- jumphost_app
|
||||
- { role: nginx_proxy, when: enable_nginx_proxy | default(false) }
|
||||
- tls_certificates
|
||||
- backup
|
||||
```
|
||||
|
||||
Bei `enable_nginx_proxy: false` terminiert die Python-App TLS **direkt** (Uvicorn/Hypercorn mit `--ssl-certfile`/`--ssl-keyfile`), die Firewall-Rolle öffnet dann direkt den App-Port (Standard 8443) statt 443 auf nginx.
|
||||
|
||||
### 7.2a TLS-Zertifikatsmodi im nginx-Betrieb
|
||||
|
||||
Zusätzlich zu `enable_nginx_proxy` steuert die Variable `tls_mode` (nur relevant, wenn nginx aktiv ist), **woher** das TLS-Zertifikat kommt, mit dem nginx auf dem Jumphost selbst terminiert bzw. ob nginx überhaupt selbst terminiert:
|
||||
|
||||
```yaml
|
||||
# group_vars/jumphost_with_nginx.yml
|
||||
enable_nginx_proxy: true
|
||||
tls_mode: internal_pki # internal_pki | external_reverse_proxy | acme_public
|
||||
```
|
||||
|
||||
**Modus `internal_pki` – nginx terminiert selbst, Zertifikat aus interner PKI:**
|
||||
- Für rein interne Umgebungen ohne öffentliche Erreichbarkeit gedacht.
|
||||
- Die Rolle `tls_certificates` bezieht das Zertifikat entweder (a) automatisiert per ACME-Protokoll von einer internen CA, die ACME spricht (z. B. `step-ca`, oder Microsoft ADCS mit ACME-Plugin), oder (b) aus einem vorab per `ansible-vault` verschlüsselten Cert/Key-Paar, das zentral von der bestehenden Unternehmens-PKI ausgestellt und ins Repository (verschlüsselt) eingespielt wird.
|
||||
- Damit Browser der Nutzer das Zertifikat ohne Warnung akzeptieren, muss das interne Root-/Intermediate-CA-Zertifikat auf den Client-Rechnern als vertrauenswürdig hinterlegt sein (i. d. R. bereits über GPO/MDM im Unternehmen vorhanden – kein Bestandteil dieses Playbooks, aber als Voraussetzung dokumentiert).
|
||||
- Erneuerung automatisiert über systemd-Timer + Ansible-Handler (Reload von nginx bei neuem Zertifikat, ohne Verbindungsabbruch bestehender Sessions dank `nginx -s reload`).
|
||||
|
||||
**Modus `external_reverse_proxy` – TLS-Terminierung erfolgt vorgelagert:**
|
||||
- Für Umgebungen, in denen bereits ein zentraler Reverse Proxy/Load Balancer (z. B. F5, HAProxy, zentrales nginx/Traefik-Ingress, Cloud-LB) existiert, der die öffentliche TLS-Terminierung mit der unternehmensweiten oder einer öffentlichen PKI übernimmt.
|
||||
- Empfohlene Umsetzung (**Defense-in-Depth, "TLS all the way"**): Die Strecke zwischen externem Reverse Proxy und dem lokalen nginx auf dem Jumphost wird **erneut verschlüsselt** (Re-Encryption) – das lokale nginx terminiert dabei ein zweites, internes TLS mit einem Zertifikat aus der internen PKI (technisch identisch zum `internal_pki`-Zweig), optional mit Mutual-TLS, sodass nur der bekannte externe Proxy sich verbinden kann.
|
||||
- Bewusste Ausnahme, **nicht Standardeinstellung**: Klartext-HTTP zwischen externem Proxy und Jumphost ist nur zulässig, wenn diese Strecke nachweislich in einem eigenen, physisch/logisch getrennten und zugriffskontrollierten Segment liegt, und erfordert eine dokumentierte Risikoakzeptanz (`tls_mode: external_reverse_proxy` mit zusätzlichem Flag `internal_hop_plaintext_accepted: true`, das im Playbook explizit gesetzt werden muss – kein stiller Default).
|
||||
- In diesem Modus muss dem lokalen nginx die IP-Adresse/das Subnetz des externen Reverse Proxys als vertrauenswürdig bekannt gemacht werden, damit `X-Forwarded-For` und `X-Forwarded-Proto` korrekt und nicht durch Dritte fälschbar ausgewertet werden – sonst wäre das Feld `client_ip` im Audit-Log (Kap. 5) manipulierbar:
|
||||
|
||||
```nginx
|
||||
# roles/nginx_proxy/templates/jumphost.conf.j2 (Auszug, Modus external_reverse_proxy)
|
||||
set_real_ip_from {{ external_reverse_proxy_cidr }}; # z.B. 10.10.5.0/24
|
||||
real_ip_header X-Forwarded-For;
|
||||
real_ip_recursive on;
|
||||
|
||||
server {
|
||||
listen 443 ssl; # zweite, interne TLS-Schicht (Re-Encryption)
|
||||
ssl_certificate /etc/jumphost/tls/internal.crt;
|
||||
ssl_certificate_key /etc/jumphost/tls/internal.key;
|
||||
ssl_protocols TLSv1.3;
|
||||
|
||||
location / {
|
||||
proxy_pass http://unix:/run/jumphost/app.sock;
|
||||
proxy_set_header X-Forwarded-Proto https;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Modus `acme_public`** (unverändert gegenüber v0.1): Let's-Encrypt/öffentliches ACME für Deployments mit direkter Internet-Erreichbarkeit und öffentlichem DNS-Namen.
|
||||
|
||||
Alle drei Modi werden von **derselben** Rolle `tls_certificates` über eine `case`/`when`-Verzweigung auf `tls_mode` abgedeckt – es entsteht kein separater Wartungspfad.
|
||||
|
||||
### 7.3 Secrets im Playbook
|
||||
- Alle sensiblen Variablen (KEK-Ausgangsmaterial, initiales Admin-Passwort, ggf. Vault-Zugangsdaten) liegen ausschließlich in `ansible-vault`-verschlüsselten Dateien (`group_vars/*/vault.yml`).
|
||||
- Playbook-Läufe erfordern `--ask-vault-pass` oder eine extern bereitgestellte Vault-ID-Datei (nicht im Repository).
|
||||
- Idempotenz: alle Rollen so gestaltet, dass wiederholte Ausführung keine Nebenwirkungen hat (Handler statt Direktbefehle, `creates`/`state`-Parameter konsequent genutzt).
|
||||
|
||||
---
|
||||
|
||||
## 8. Systemd-Services
|
||||
|
||||
### 8.1 Haupt-Anwendung (`jumphost-app.service`)
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
Description=Jumphost Gateway Application
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=jumphost
|
||||
Group=jumphost
|
||||
ExecStart=/opt/jumphost/venv/bin/uvicorn app.main:app \
|
||||
--uds /run/jumphost/app.sock
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
|
||||
# --- Hardening ---
|
||||
NoNewPrivileges=true
|
||||
ProtectSystem=strict
|
||||
ProtectHome=true
|
||||
PrivateTmp=true
|
||||
PrivateDevices=true
|
||||
ProtectKernelTunables=true
|
||||
ProtectKernelModules=true
|
||||
ProtectControlGroups=true
|
||||
RestrictNamespaces=true
|
||||
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
|
||||
RestrictSUIDSGID=true
|
||||
MemoryDenyWriteExecute=true
|
||||
LockPersonality=true
|
||||
SystemCallFilter=@system-service
|
||||
SystemCallErrorNumber=EPERM
|
||||
CapabilityBoundingSet=
|
||||
ReadWritePaths=/var/lib/jumphost /run/jumphost
|
||||
UMask=0077
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
### 8.2 guacd-Dienst (`guacd.service`)
|
||||
Analoge Hardening-Direktiven, zusätzlich `RestrictAddressFamilies=AF_UNIX AF_INET` (nur lokale Kommunikation zur App und ausgehend RDP), eigener unprivilegierter User `guacd`, kein Zugriff auf das SQLite-Datenverzeichnis.
|
||||
|
||||
### 8.3 Backup-Timer (`jumphost-backup.timer` / `.service`)
|
||||
`OnCalendar=daily`, ruft ein Skript auf, das `sqlite3 ... "VACUUM INTO '/backup/....db'"` ausführt und anschließend verschlüsselt (z. B. `age` oder GPG) ablegt; ebenfalls mit reduzierten systemd-Capabilities.
|
||||
|
||||
---
|
||||
|
||||
## 9. Betrieb mit vs. ohne nginx
|
||||
|
||||
| Kriterium | **Mit nginx** | **Ohne nginx (direkt)** |
|
||||
|---|---|---|
|
||||
| TLS-Terminierung | Ausgereift, breite Erfahrung, einfache Cipher-Konfiguration | Möglich (Uvicorn/Hypercorn), weniger battle-tested für Internet-exponierte Lasten |
|
||||
| WebSocket-Handling | Sehr robust, granulare Timeout-/Buffer-Konfiguration | Funktioniert, aber weniger Tuning-Optionen |
|
||||
| Security-Header/Rate-Limiting | Zentral und einfach über nginx-Module/`limit_req` | Muss in der Anwendung selbst implementiert werden |
|
||||
| WAF-Anbindung (z. B. ModSecurity) | Möglich | Nicht ohne Zusatzkomponente |
|
||||
| Angriffsfläche | Zusätzliche Komponente = zusätzlicher Patch-Bedarf | Minimalere Angriffsfläche, weniger Komponenten |
|
||||
| Eignung | **Empfohlen für internet-exponierten/produktiven Betrieb** | Sinnvoll für rein internen Betrieb in bereits stark segmentiertem Netz oder minimalistische Testumgebungen |
|
||||
|
||||
**Empfehlung:** Produktivbetrieb, insbesondere bei Erreichbarkeit außerhalb eines bereits stark abgesicherten internen Netzes, **mit nginx** als vorgelagertem Reverse Proxy. Der Modus „ohne nginx" bleibt als bewusst unterstützte, schlankere Option für stark isolierte interne Deployments erhalten – beide Pfade werden vom selben Playbook über eine einzige Variable gesteuert, wodurch kein Wartungsaufwand für zwei getrennte Codebasen entsteht.
|
||||
|
||||
**TLS-Zertifikatsmodi innerhalb des nginx-Betriebs** (Details Kap. 7.2a): Sowohl der Fall „nginx terminiert selbst mit einem Zertifikat aus der internen PKI" (`internal_pki`) als auch der Fall „ein vorgelagerter externer Reverse Proxy übernimmt die TLS-Terminierung mit eigener PKI, das lokale nginx dient als zweite interne Schicht" (`external_reverse_proxy`) werden unterstützt und über die Variable `tls_mode` gesteuert – ohne dass dafür zwei getrennte Playbook-Varianten gepflegt werden müssen.
|
||||
|
||||
---
|
||||
|
||||
## 10. Rollout-Plan & Teststrategie
|
||||
|
||||
1. **Proof of Concept**: Kernfunktionen (Login+TOTP, ein SSH-Ziel, ein RDP-Ziel, Audit-Log) in isolierter Testumgebung.
|
||||
2. **Security-Review/Penetrationstest**: vor jedem produktiven Rollout verpflichtend, insbesondere Prüfung von Session-Isolation, Key-Handling, RBAC-Bypass-Versuchen.
|
||||
3. **Pilotbetrieb**: begrenzter Nutzerkreis, begrenzte Hostgruppen, engmaschiges Audit-Log-Review.
|
||||
4. **Rollout**: schrittweise Ausweitung, Altlösungen (z. B. direkte SSH/RDP-Zugänge) parallel abschalten.
|
||||
5. **Kontinuierlich**: automatisierte Tests (Unit-Tests für RBAC-Logik und Audit-Hash-Chain, Integrationstests für SSH-/RDP-Sessionaufbau, Dependency-Scans in CI, jährlicher Penetrationstest).
|
||||
|
||||
---
|
||||
|
||||
## 11. Technologie-Stack (Zusammenfassung)
|
||||
|
||||
| Bereich | Technologie |
|
||||
|---|---|
|
||||
| Backend-Framework | Python 3.12+, FastAPI, Uvicorn/Hypercorn (ASGI) |
|
||||
| Datenbank | SQLite (WAL-Modus), `aiosqlite`/SQLAlchemy Core |
|
||||
| SSH | `asyncssh` |
|
||||
| RDP | guacd (Apache-Guacamole-Protokoll-Daemon) + FreeRDP, `guacamole-common-js` im Frontend |
|
||||
| Terminal-Frontend | `xterm.js` |
|
||||
| Auth | Argon2id (`argon2-cffi`), TOTP (`pyotp`) |
|
||||
| Verschlüsselung | AES-256-GCM für Secrets at rest, TLS 1.3 in transit |
|
||||
| Reverse Proxy (optional) | nginx |
|
||||
| Deployment | Ansible (Rollen, Vault) |
|
||||
| Prozess-Management | systemd (gehärtete Units) |
|
||||
| Monitoring | Prometheus-Exporter (optional), Syslog/SIEM-Anbindung |
|
||||
| CI/Dependency-Sicherheit | `pip-audit`, Lockfile-basierte Builds |
|
||||
|
||||
---
|
||||
|
||||
## 12. Offene Punkte & Erweiterungsoptionen
|
||||
|
||||
- **LDAP/Active-Directory-Anbindung** als alternative/zusätzliche Identitätsquelle statt rein lokaler User.
|
||||
- **WebAuthn/FIDO2** als Ersatz oder Ergänzung zu TOTP für höhere Phishing-Resistenz.
|
||||
- **Skalierung**: bei Bedarf Migrationspfad von SQLite auf PostgreSQL (Schema ist bewusst so gehalten, dass eine Migration ohne grundlegenden Redesign möglich ist).
|
||||
- **Just-in-Time-Zugriff**: zeitlich befristete, genehmigungspflichtige Zugriffsanfragen statt dauerhafter Rechtevergabe.
|
||||
- **Hochverfügbarkeit**: Aktiv/Passiv-Setup mit synchronisierter DB und geteiltem Session-Storage bei Bedarf an Ausfallsicherheit.
|
||||
- **Mobile-/Tablet-Optimierung** der Weboberfläche.
|
||||
- **Externe Vault-Integration** (HashiCorp Vault/OpenBao) als Ersatz für die dateibasierte KEK-Verwaltung in größeren Umgebungen.
|
||||
|
||||
---
|
||||
|
||||
### Nächste Schritte
|
||||
|
||||
1. Zielgröße und Netzsegmentierung final festlegen (Kap. 1) sowie gewünschte Linux-Distribution für den Jumphost bestimmen.
|
||||
2. Entscheidung, welcher TLS-Zertifikatsmodus (Kap. 7.2a: `internal_pki`, `external_reverse_proxy` oder `acme_public`) initial umgesetzt wird – ggf. auch mehrere, je nach Zielumgebung (z. B. intern vs. DMZ).
|
||||
3. Entscheidung zu kurzlebigen SSH-CA-Zertifikaten vs. ausschließlich statischen Schlüsseln treffen (beeinflusst Ansible-Rolle und Zielsystem-Vorbereitung).
|
||||
4. Freigabe dieses Konzepts als Grundlage für die Implementierungsphase (Backend-Projektskelett, DB-Migrationen, Ansible-Rollen).
|
||||
Reference in New Issue
Block a user