diff --git a/docs/GNAI-001-INFRA_BaseSystem.md b/docs/GNAI-001-INFRA_BaseSystem.md index 461da2d..6e30717 100644 --- a/docs/GNAI-001-INFRA_BaseSystem.md +++ b/docs/GNAI-001-INFRA_BaseSystem.md @@ -37,12 +37,10 @@ Vor der Betriebssystem-Installation sind folgende Schritte im BIOS (Aufrufen via * Im BIOS navigieren zu: `Tool` -> `Instant Flash`. * BIOS-Version auf **`19.02`** (oder neuer) aktualisieren. - 2. **RAM-Performance:** * Navigieren zu: `OC Tweaker` -> `DRAM Configuration`. * **Load XMP Setting:** auf **XMP Profile 1** stellen. - 3. **Virtualisierung & PCI-Einstellungen (Wichtig für GPU/ROCm):** * Navigieren zu: `Advanced` -> `CPU Configuration` -> **Intel Virtualization Technology** -> `Enabled`. * Navigieren zu: `Advanced` -> `PCI Configuration`: @@ -165,7 +163,6 @@ apt update # Grundlegende Tools und GPU-Firmware installieren apt install -y curl wget git htop tmux pciutils firmware-amd-graphics firmware-linux-nonfree - ``` #### 4. SSH-Schlüssel hinterlegen (Remote-Zugriff) @@ -178,7 +175,6 @@ mkdir -p ~/.ssh chmod 700 ~/.ssh nano ~/.ssh/authorized_keys # Public-Key des Admin-PCs einfügen chmod 600 ~/.ssh/authorized_keys - ``` --- @@ -200,4 +196,4 @@ Vor der Übergabe an das KI-Team (Phase 2) muss das System folgende Punkte beste | Datum | Version | Geändert von | Beschreibung der Änderung | | --- | --- | --- | --- | | 2026-08-24 | 1.0 | spektr | Erstellung des Initial-Dokuments (Hardware & OS) | -| 2026-08-24 | 1.1 | spektr / Assistant | Detaillierung der BIOS-ReBAR-Settings, Netinst-CLI-Schritte, Post-Installation & Abnahmekriterien hinzugefügt. | \ No newline at end of file +| 2026-08-24 | 1.1 | spektr / Assistant | Detaillierung der BIOS-ReBAR-Settings, Netinst-CLI-Schritte, Post-Installation & Abnahmekriterien hinzugefügt. | diff --git a/docs/GNAI-002-INFRA_Users.md b/docs/GNAI-002-INFRA_Users.md index db4a12a..2915fe8 100644 --- a/docs/GNAI-002-INFRA_Users.md +++ b/docs/GNAI-002-INFRA_Users.md @@ -1,9 +1,7 @@ -# Standard Operating Procedure (SOP) - -**Dokumenten-ID:** GNAI-INFRA-002 - -**Titel:** Benutzerverwaltung, SSH-Härtung & Netzwerkkonfiguration (Phase 2) +# Standard Operating Procedure +**Dokumenten-ID:** GNAI-002-INFRA +**Titel:** Benutzerverwaltung, SSH-Härtung & Netzwerkkonfiguration (Phase 2) **Version:** 1.0 --- @@ -33,7 +31,6 @@ Als `root` am Server anmelden: ```bash su - apt update && apt install -y sudo - ``` #### 2. Benutzer anlegen & Berechtigungen vergeben @@ -46,7 +43,6 @@ Neuen Benutzer anlegen und zur `sudo`-Gruppe hinzufügen: # Beispiel für Benutzer 'ghost' oder 'debugofen' sudo adduser debugofen sudo usermod -aG sudo debugofen - ``` --- @@ -55,18 +51,16 @@ sudo usermod -aG sudo debugofen #### 1. Netzschnittstelle ermitteln & anpassen -Lass dir die primäre Netzwerkschnittstelle anzeigen (z. B. `enp8s0`): +Primäre Netzwerkschnittstelle anzeigen lassen (z. B. `enp8s0`): ```bash ip addr show - ``` -Bearbeite die Datei `/etc/network/interfaces`: +Datei bearbeiten: `/etc/network/interfaces`: ```bash sudo nano /etc/network/interfaces - ``` Netzwerkkonfiguration für statische IP eintragen: @@ -82,16 +76,14 @@ iface enp8s0 inet static address 10.0.0.90/24 gateway 10.0.0.1 dns-nameservers 10.0.0.1 1.1.1.1 - ``` #### 2. DNS-Resolver prüfen/anpassen -Prüfe die Datei `/etc/resolv.conf`: +Datei überprüfen `/etc/resolv.conf`: ```bash sudo nano /etc/resolv.conf - ``` Sicherstellen, dass folgende Nameserver eingetragen sind: @@ -99,7 +91,6 @@ Sicherstellen, dass folgende Nameserver eingetragen sind: ```text nameserver 10.0.0.1 nameserver 1.1.1.1 - ``` #### 3. Netzwerkdienst neustarten & Funktion prüfen @@ -108,7 +99,6 @@ nameserver 1.1.1.1 sudo systemctl restart networking ip -4 addr ping -c 4 google.com - ``` *(Tritt ein Konfigurationskonflikt auf, das System einmal per `sudo reboot` neustarten).* @@ -117,24 +107,22 @@ ping -c 4 google.com ### 3.3 SSH-Key-Generierung & Übertragung (Workstation-Seite) -Führe diese Schritte auf der **lokalen Workstation** aus. +Die folgenden Schritte werden auf der **lokalen Workstation** ausgeführt. #### 1. Ed25519 SSH-Schlüsselpaar erzeugen ```bash ssh-keygen -t ed25519 -C "ghost@ghostnet-ki" -f ~/.ssh/id_ed25519_ghost ssh-keygen -t ed25519 -C "debugofen@ghostnet-ki" -f ~/.ssh/id_ed25519_debugofen - ``` #### 2. Public Keys auf den Server übertragen -Verwende `ssh-copy-id`, um die öffentlichen Schlüssel auf den Server zu kopieren (vorläufig noch mit Passwort-Authentifizierung): +Der Befehl `ssh-copy-id` wird verwendet, um die öffentlichen Schlüssel auf den Server zu kopieren (vorläufig noch mit Passwort-Authentifizierung): ```bash ssh-copy-id -i ~/.ssh/id_ed25519_ghost.pub ghost@10.0.0.90 ssh-copy-id -i ~/.ssh/id_ed25519_debugofen.pub debugofen@10.0.0.90 - ``` #### 3. Schlüsselbasierten Login testen @@ -142,16 +130,14 @@ ssh-copy-id -i ~/.ssh/id_ed25519_debugofen.pub debugofen@10.0.0.90 ```bash ssh -i ~/.ssh/id_ed25519_ghost ghost@10.0.0.90 ssh -i ~/.ssh/id_ed25519_debugofen debugofen@10.0.0.90 - ``` #### 4. Workstation Client-Config einrichten (`~/.ssh/config`) -Erstelle/bearbeite die Datei `~/.ssh/config` auf der Workstation, um Kurznamen für Verbindungen zu nutzen: +Die Datei `~/.ssh/config` auf der Workstation erstellen/bearbeiten, um Kurznamen für Verbindungen zu nutzen: ```bash nano ~/.ssh/config - ``` Inhalt eintragen: @@ -165,21 +151,18 @@ Host ghostnet.ki Hostname 10.0.0.90 User ghost IdentityFile ~/.ssh/id_ed25519_ghost - ``` Berechtigungen auf der Workstation korrigieren: ```bash chmod 600 ~/.ssh/config - ``` Verbindung über den Alias testen: ```bash ssh ghostnet.ki - ``` --- @@ -192,10 +175,9 @@ Sobald der SSH-Key-Login erfolgreich getestet wurde, wird die Passwort-Authentif ```bash sudo nano /etc/ssh/sshd_config.d/99-security.conf - ``` -Füge folgenden Inhalt ein: +Den folgenden Inhalt einfügen: ```text # Root-Login über SSH komplett verbieten @@ -210,7 +192,6 @@ PermitEmptyPasswords no # Nur explizite SSH-Key Methoden erlauben PubkeyAuthentication yes - ``` #### 2. SSH-Konfiguration prüfen und Dienst neustarten @@ -223,7 +204,6 @@ sudo sshd -t # Wenn sshd -t keine Fehler ausgibt, Dienst neustarten sudo systemctl restart sshd - ``` --- diff --git a/docs/GNAI-004-SEC_Access-Control.md b/docs/GNAI-004-SEC_Access-Control.md index 495cdd5..95000d1 100644 --- a/docs/GNAI-004-SEC_Access-Control.md +++ b/docs/GNAI-004-SEC_Access-Control.md @@ -4,7 +4,7 @@ **Titel:** Homelab / LLM-Infrastruktur – Sicherheits-, Authentifizierungs- und Zugriffskonzept **Version:** 1.0 **Status:** Architekturentscheidung -**Vorgänger / Referenzen:** GNAI-INFRA-003 +**Vorgänger / Referenzen:** GNAI-003-INFRA --- diff --git a/docs/GNAI-005-SEC_Reverse-Proxy.md b/docs/GNAI-005-SEC_Reverse-Proxy.md new file mode 100644 index 0000000..61bf8f3 --- /dev/null +++ b/docs/GNAI-005-SEC_Reverse-Proxy.md @@ -0,0 +1,314 @@ +# Technical Architecture Specification + +**Dokumenten-ID:** GNAI-006-SEC +**Titel:** Homelab / Infrastructure – Reverse Proxy & Containerized IPS Specification +**Version:** 1.0 +**Status:** Aktiv +**Vorgänger / Referenzen:** GNAI-003-INFRA, GNAI-004-SEC + +--- + +## 1. Zweck & Geltungsbereich + +Dieses Dokument definiert die verbindliche System- und Sicherheitsarchitektur für den zentralen Reverse Proxy und das Intrusion Prevention System (IPS) der Ghostnet-Infrastruktur auf Proxmox LXC 103 (`reverse-proxy`). + +**Umfang dieses Dokuments:** + +* Betrieb von Nginx Proxy Manager (NPM) als zentraler Ingress-Controller +* Containerisiertes Fail2Ban als IPS mit nftables-Integration auf dem LXC +* Log-Parsing-Regeln und Filterdefinitionen für das NPM-spezifische Access-Log-Format +* Gehärtete Firewall-Baseline und Zugriffssteuerung + +--- + +## 2. System- Baseline (LXC 103) + +| Parameter | Wert | +| --- | --- | +| Container-ID | CT 103 | +| Hostname | `reverse-proxy`
| +| Betriebssystem | Debian GNU/Linux 13 (Trixie) | +| Unprivileged | Ja | +| Cores / RAM / Swap | 2 Cores / 1024 MB RAM / 512 MB Swap | +| RootFS | 8 GB | +| Netzwerkkonfiguration | IP: `10.0.0.10/24` | GW: `10.0.0.1` | Bridge: `vmbr0`
| +| LXC Features | `nesting=1`, `keyctl=1`
| +| Proxmox Host | Proxmox VE 8.4.21 (Kernel `6.8.12-23-pve`) | + +*Hinweis zur Proxmox-Firewall:* Proxmox Cluster- und Node-Firewalls sind deaktiviert (`enable 0`). Die Paketfilterung erfolgt exklusiv lokal über `nftables` innerhalb des LXC. + +--- + +## 3. Netzwerk- & Firewall-Architektur (nftables) + +Die lokale Paketfilterung basiert auf `nftables` mit einer strikten `INPUT policy drop`-Doktrin. + +```nftables +table inet filter { + chain input { + type filter hook input priority filter; policy drop; + iifname "lo" accept + ct state invalid drop + ct state established,related accept + ip protocol icmp accept + ip saddr 10.0.0.0/24 tcp dport { 22, 81 } accept + tcp dport { 80, 443 } accept + } + + chain forward { + type filter hook forward priority filter; policy accept; + } + + chain output { + type filter hook output priority filter; policy accept; + } +} +``` + +### Port-Matrix + +| Port | Protokoll | Zweck | Erreichbarkeit | +| --- | --- | --- | --- | +| 80 | TCP | HTTP Ingress (NPM) | Öffentlich | +| 443 | TCP | HTTPS Ingress (NPM) | Öffentlich | +| 81 | TCP | NPM Web Admin Interface | Nur LAN (`10.0.0.0/24`) | +| 22 | TCP | OpenSSH Management | Nur LAN (`10.0.0.0/24`) | +| 3000 | TCP | NPM Node.js Backend | Intern / Nicht exponiert | + +--- + +## 4. Container-Infrastruktur (Podman Quadlets) + +Nginx Proxy Manager und Fail2Ban werden als rootful Podman-Container via systemd Quadlets mit `Network=host` betrieben. + +### 4.1 Nginx Proxy Manager Quadlet + +* **Datei:** `/etc/containers/systemd/nginx-proxy-manager.container` +* **Image:** `docker.io/jc21/nginx-proxy-manager:2.11.1` *(ausdrücklich gepinnt)* + +```ini +[Unit] +Description=Nginx Proxy Manager +Wants=network-online.target +After=network-online.target + +[Container] +Image=docker.io/jc21/nginx-proxy-manager:2.11.1 +ContainerName=nginx-proxy-manager +Network=host +Volume=/opt/nginx-proxy-manager/data:/data:rw +Volume=/opt/nginx-proxy-manager/letsencrypt:/etc/letsencrypt:rw +Environment=DISABLE_IPV6=true +Environment=TZ=Europe/Berlin + +[Service] +Restart=always +TimeoutStartSec=300 + +[Install] +WantedBy=multi-user.target +``` + +### 4.2 Fail2Ban IPS Quadlet + +* **Datei:** `/etc/containers/systemd/fail2ban.container` +* **Image:** `lscr.io/linuxserver/fail2ban:latest` +* **Capabilities:** `NET_ADMIN`, `NET_RAW` *(kein `--privileged`)* + +```ini +[Unit] +Description=Fail2Ban +Wants=network-online.target +After=network-online.target + +[Container] +Image=lscr.io/linuxserver/fail2ban:latest +ContainerName=fail2ban +Network=host +AddCapability=NET_ADMIN +AddCapability=NET_RAW +Volume=/opt/fail2ban/config:/config:rw +Volume=/opt/nginx-proxy-manager/data/logs:/remotelogs/npm:ro +Environment=TZ=Europe/Berlin + +[Service] +Restart=always +TimeoutStartSec=300 + +[Install] +WantedBy=multi-user.target +``` + +--- + +## 5. NPM Logformat & Parsing-Regeln + +NPM nutzt ein eigenes Access-Log-Format, bei dem die eigentliche Client-IP nicht am Zeilenanfang steht. + +**Beispielzeile:** + +```text +[03/Sep/2026:18:35:02 +0200] - 204 204 - POST https jellyfin.ghostnet.selfhost.eu "/Sessions/Playing/Progress" [Client 93.228.100.74] [Length 0] [Gzip -] [Sent-to 10.0.0.11] "JellyfinDesktop/2.0.0" "-" +``` + +**Verbindliche Parser-Regeln:** + +1. Die Client-IP muss zwingend aus dem Feld `[Client ]` extrahiert werden. +2. URL-Pfade oder Host-Header dürfen nicht fälschlicherweise als IP-Quelle interpretiert werden. +3. Statuscodes oder Response-Zeiten sind für automatisches Banning ungeeignet, da legitim nicht erreichbare Backends (502) False Positives auslösen würden. + +--- + +## 6. Fail2Ban-Konfiguration & Jails + +LinuxServer.io nutzt `/config/fail2ban/` als interne Konfigurationsstruktur. Sämtliche Konfigurationen liegen persistent auf dem Host unter `/opt/fail2ban/config/fail2ban/`. + +### 6.1 Wichtige Erkenntnis zur Action-Syntax + +Standardmäßig nutzt die Action `nftables-multiport` bei fehlenden Parametern Port 22 (SSH). **Sperrports müssen zwingend direkt in der `action`-Zeile des Jails in eckigen Klammern übergeben werden**, um Anfragen auf HTTP/HTTPS durchzusetzen: + +```ini +action = nftables-multiport[port="80,443", protocol=tcp] +``` +--- + +### 6.2 Jail 1: Exploit & Scanner Protection (`npm-scanner`) + +Gezielte Blockade von Pfad-Traversal-Versuchen, Secret-Abfragen und automatisierten Framework-Scans. + +* **Filter:** `/opt/fail2ban/config/fail2ban/filter.d/npm-scanner.conf` + + ```ini + [Definition] + failregex = ^\[.*\] - [0-9]{3} [0-9]{3} - (GET|POST|HEAD) [^ ]+ [^ ]+ "/(?:[^"]*/)?(?:\.env[^"/]*|\.git/[^" ]*|\.aws/[^" ]*|wp-config\.php[^" ]*|wp-login\.php(?:\?[^" ]*)?|wp-admin(?:/[^" ]*)?|actuator(?:/[^" ]*)?|_ignition(?:/[^" ]*)?|storage/logs(?:/[^" ]*))" \[Client \] + ignoreregex = + ``` + +* **Jail:** `/opt/fail2ban/config/fail2ban/jail.d/npm-scanner.local` + + ```ini + [npm-scanner] + enabled = true + filter = npm-scanner + backend = auto + logpath = /remotelogs/npm/proxy-host-*_access.log + findtime = 10m + maxretry = 3 + bantime = 1h + ignoreip = 127.0.0.1/8 10.0.0.0/24 + action = nftables-multiport[port="80,443", protocol=tcp] + ``` + +--- + +### 6.3 Jail 2: Bad User-Agents (`npm-badbots`) + +Blockade bekannter Angriffs-Scanner und Reconnaissance-Tools. + +* **Filter:** `/opt/fail2ban/config/fail2ban/filter.d/npm-badbots.conf` + *(Wichtig: Nutzt lokale Case-Insensitivity `(?i:...)`, um Python-RegEx-Kompilierungsfehler zu vermeiden)* + + ```ini + [Definition] + failregex = ^\[.*\] - [0-9]{3} [0-9]{3} - (?:GET|POST|HEAD|OPTIONS) [^ ]+ [^ ]+ "[^"]*" \[Client \] .* "[^"]*(?i:sqlmap|nikto|nmap|masscan|zgrab|nessus|openvas|dirbuster|gobuster|wpscan|python-requests|go-http-client|censys|whatweb|acunetix)[^"]*" + ignoreregex = + ``` + +* **Jail:** `/opt/fail2ban/config/fail2ban/jail.d/npm-badbots.local` + + ```ini + [npm-badbots] + enabled = true + filter = npm-badbots + backend = auto + logpath = /remotelogs/npm/proxy-host-*_access.log + findtime = 10m + maxretry = 2 + bantime = 24h + ignoreip = 127.0.0.1/8 10.0.0.0/24 + action = nftables-multiport[port="80,443", protocol=tcp] + ``` + +--- + +## 7. Aktive Proxy Hosts + +Aktuell im Nginx Proxy Manager konfigurierte und aktive Routen: + +| ID | Hostname | Backend-Ziel | Dienst | +| --- | --- | --- | --- | +| 1 | `jellyfin.ghostnet.selfhost.eu` | `10.0.0.11:8096` | Jellyfin Media Server | +| 3 | `nextcloud.ghostnet.selfhost.eu` | `10.0.0.12:8080` | Nextcloud Cloud Storage | +| 4 | `git.ghostnet.selfhost.eu` | `10.0.0.17:3000` | Gitea Code Hosting | +| 7 | `auth.ghostnet.selfhost.eu` | `10.0.0.4:8080` | Keycloak Identity Provider | +| 10 | `japan.ghostnet.selfhost.eu` | `10.0.0.23:80` | Japanese Web App | +| 12 | `vault.ghostnet.selfhost.eu` | `10.0.0.47:8080` | Vaultwarden Password Manager | + +--- + +## 8. Betriebs- & Diagnosekommandos + +### Fail2Ban-Status + +```bash +# Gesamtstatus der aktiven Jails +podman exec fail2ban fail2ban-client status + +# Spezifischen Jail prüfen +podman exec fail2ban fail2ban-client status npm-scanner +podman exec fail2ban fail2ban-client status npm-badbots +``` + +### Filter mit echten Logs testen + +```bash +podman exec fail2ban fail2ban-regex \ + /remotelogs/npm/proxy-host-10_access.log \ + /config/fail2ban/filter.d/npm-scanner.conf +``` + +### nftables-Regeln & aktive Bans auf dem Host verifizieren + +```bash +nft list ruleset | grep -A 10 "table inet f2b-table" +``` + +### Manuelle Sperre / Freigabe + +```bash +# IP manuell sperren +podman exec fail2ban fail2ban-client set npm-scanner banip + +# IP manuell freigeben +podman exec fail2ban fail2ban-client set npm-scanner unbanip +``` + +--- + +## 9. Sicherheits- & Betriebsregeln für Administrierende + +1. **Kein generisches Statuscode-Banning:** Generische HTTP `4xx`- oder `5xx`-Fehler dürfen nicht als pauschales Ban-Kriterium verwendet werden. +2. **Keine verfrühten Upgrades:** Die NPM-Version ist auf `2.11.1` festgeschrieben. Upgrades müssen separat in einer Testumgebung evaluiert werden. +3. **Privilegien-Minimierung:** Der Fail2Ban-Container wird strikt ohne `--privileged` betrieben (`NET_ADMIN` und `NET_RAW` reichen aus). +4. **Whitelist-Pflicht:** Das Subnetz `10.0.0.0/24` sowie `127.0.0.1/8` müssen in allen Jails in `ignoreip` hinterlegt bleiben, um Aussperrungen zu verhindern. +5. **Syntax-Check vor Reload:** Jede Änderung an Fail2Ban-Konfigurationen ist vorab mit `podman exec fail2ban fail2ban-client -t` auf Gültigkeit zu prüfen. + +--- + +## 10. Backup & Disaster Recovery + +Es existiert ein vollständiges Proxmox LXC Snapshot-Backup von CT 103: + +* **Backup-Datei:** `/var/lib/vz/dump/vzdump-lxc-103-2026_08_31-19_11_10.tar.zst` + +Vor strukturellen Änderungen an `nftables` oder den Podman Quadlets ist stets ein neuer Proxmox LXC-Snapshot zu erstellen. + +--- + +## 11. Änderungsverlauf + +| Datum | Version | Geändert von | Beschreibung | +| --- | --- | --- | --- | +| 2026-08-28 | 0.1 | spektr | Erstellung der ersten Baseline-Drafts. | +| 2026-09-05 | 0.9 | spektr | Implementierung Fail2Ban Container & Test-Setup (F2B-01). | +| 2026-09-07 | 1.0 | spektr | Korrektur Action-Syntax (`port="80,443"`), Behebung RegEx-Fehler (`npm-badbots`), E2E-Validierung in nftables abgeschlossen (F2B-02). Finales SOP erstellt. |