Add: Reverse Proxy specification.

This commit is contained in:
2026-09-07 16:08:12 +02:00
parent 8c581330b3
commit a42cacd5b5
4 changed files with 326 additions and 36 deletions
+1 -5
View File
@@ -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. |
| 2026-08-24 | 1.1 | spektr / Assistant | Detaillierung der BIOS-ReBAR-Settings, Netinst-CLI-Schritte, Post-Installation & Abnahmekriterien hinzugefügt. |
+10 -30
View File
@@ -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
```
---
+1 -1
View File
@@ -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
---
+314
View File
@@ -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`<br> |
| 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`<br> |
| LXC Features | `nesting=1`, `keyctl=1`<br> |
| 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 <HOST>]` 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 <HOST>\]
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 <HOST>\] .* "[^"]*(?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>
# IP manuell freigeben
podman exec fail2ban fail2ban-client set npm-scanner unbanip <IP>
```
---
## 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. |