Dokumente vereinheitlicht.
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
# Local operator context for Codex; never commit machine-specific memory.
|
||||
.codex/LOCAL_MEMORY.md
|
||||
@@ -0,0 +1,7 @@
|
||||
# Ghostnet.AI project context
|
||||
|
||||
Before infrastructure work, read `.codex/LOCAL_MEMORY.md` if it exists. It contains dated local observations and access hints; verify live state before making system changes. Keep secrets and private key material out of that file.
|
||||
|
||||
For read-only access to the KI server, use the tested SSH profile `ghostnet-ai-agent`, which logs in as the unprivileged account `ghost-agent` on `10.0.0.90`. On this workstation, invoke it as `ssh -F ~/.ssh/config ghostnet-ai-agent` because the system-wide SSH client configuration currently has an ownership/permissions error. Do not assume sudo access or make server changes without an explicit user request.
|
||||
|
||||
The KI server at `10.0.0.90` is deliberately a fresh base system. The operator plans to install the LLM application stack in a later Ansible sprint. Do not install applications or change server configuration as part of documentation review or access checks unless the operator explicitly requests that work.
|
||||
@@ -0,0 +1,56 @@
|
||||
# Ghostnet.AI Infrastruktur
|
||||
|
||||
Dokumentation für die Infrastruktur eines privaten Homelabs mit öffentlich erreichbaren Webdiensten, einem WireGuard-Zugang und einem dedizierten KI-Server. Dieses Repository hält Architekturentscheidungen, den belegten Betriebsstand und Verfahren für Einrichtung, Betrieb und Sicherheitsabnahme fest.
|
||||
|
||||
> **Projektstand: 19.09.2026.** Die Dokumentationsrevisionen sind zusammengeführt. Mehrere Sicherheitsmaßnahmen und technische Abnahmen stehen noch aus. Der KI-Server ist derzeit ein frisch eingerichtetes Basissystem; sein LLM-Anwendungsstack soll in einem späteren Sprint mit Ansible installiert werden.
|
||||
|
||||
## Überblick
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
Internet --> Router[Fritzbox]
|
||||
Router -->|HTTP/HTTPS| NPM[Nginx Proxy Manager]
|
||||
Router -->|WireGuard| VPN[wg-easy]
|
||||
NPM --> Apps[Webdienste in eigenen LXCs]
|
||||
VPN --> LAN[Heimnetz]
|
||||
LAN --> PVE[Proxmox und Service-LXCs]
|
||||
LAN --> AI[KI-Server]
|
||||
NPM -.-> AI
|
||||
```
|
||||
|
||||
Der Reverse Proxy und das VPN-Gateway laufen in getrennten Proxmox-LXCs. Weitere Webdienste befinden sich in eigenen LXCs. Der physische KI-Server ist für lokale Inferenz und darauf aufbauende Anwendungen vorgesehen. Die gestrichelte Verbindung zum KI-Server beschreibt einen **geplanten** Veröffentlichungsweg für LLM-Anwendungen; die Dienste sind dort noch nicht installiert.
|
||||
|
||||
Die drei vorgesehenen VPN-Netzwerkrollen sind **Familie** (gesamtes Heimnetz), **Server Admin** (bestätigte Server und Service-LXCs) und **LLM Admin** (nur KI-Server). Ihre serverseitige Durchsetzung ist noch nicht abgenommen. Anwendungsanmeldung, SSH-Schlüssel und API-Schlüssel bleiben zusätzliche, eigenständige Zugangskontrollen.
|
||||
|
||||
## Aktueller Stand
|
||||
|
||||
| Bereich | Belegter Stand | Nächster Nachweis oder Schritt |
|
||||
| --- | --- | --- |
|
||||
| KI-Server | Debian-Basissystem und getrennte SSH-Konten; lesender Teilabgleich am 18.09.2026 | LLM-Anwendungsstack später mit Ansible einrichten und abnehmen |
|
||||
| VPN | wg-easy v15.4.0 auf CT 105 aktiv; ein externer Laptop-Teiltest liegt vor | Rollenrechte serverseitig umsetzen und mit erlaubten sowie gesperrten Zielen testen |
|
||||
| Reverse Proxy | NPM auf CT 103 dokumentiert; Fail2Ban laut Betreiber fest gepinnt und wieder in Betrieb | Effektive Jails, Sperren und Wiederanlauf prüfen |
|
||||
| Identität | Keycloak/OIDC laut Betreiber produktiv für Vaultwarden | Öffentlich erreichbare Keycloak-Administration sperren und den OIDC-Login erneut prüfen |
|
||||
|
||||
Der [Dokumentationsindex](docs/GNAI-000-DOC_Index.md) enthält die datierten Quellen, offenen Angaben und Abnahmegrenzen. Er ist die maßgebliche Übersicht für den aktuellen Projektstand. Eine Zielbeschreibung in diesem README oder den Architekturdokumenten ist kein Nachweis für eine bereits wirksame Konfiguration.
|
||||
|
||||
## Dokumentation lesen
|
||||
|
||||
| Einstieg | Inhalt |
|
||||
| --- | --- |
|
||||
| [Dokumentationsindex und Projektstand](docs/GNAI-000-DOC_Index.md) | Dokumentenübersicht, bestätigte Entscheidungen und offene Befunde |
|
||||
| [Zielarchitektur](docs/GNAI-003-INFRA_Architecture.md) | Komponenten, Datenwege und geplante Sicherheitszonen |
|
||||
| [Zugriffsmodell](docs/GNAI-004-SEC_Access-Control.md) | Rollen, Zugriffsmatrix und Authentifizierung |
|
||||
| [Basissystem](docs/GNAI-001-INFRA_BaseSystem.md) und [Benutzer, Netz und SSH](docs/GNAI-002-INFRA_Users.md) | KI-Server-Basis und zugehörige Prüfungen |
|
||||
| [Reverse Proxy und Fail2Ban](docs/GNAI-005-SEC_Reverse-Proxy.md) | Konfiguration, Keycloak-Korrektur und ausstehende Abnahme |
|
||||
| [WireGuard-Gateway](docs/GNAI-006-SEC_VPN.md) | Gateway-Aufbau, Ist-Stand und Rollen-Firewall |
|
||||
| [Client-Verwaltung](docs/GNAI-006-SEC_VPN_Client-Management.md) | Profile ausgeben, ändern, widerrufen und Rollen prüfen |
|
||||
| [Windows 11](docs/GNAI-006-SEC_VPN_Clients_Windows11.md) und [Linux](docs/GNAI-006-SEC_VPN_Clients_Linux.md) | Einrichtung und Nutzung auf Endgeräten |
|
||||
| [WireGuard-Implementation-Log](docs/GNAI-006-SEC_VPN_Implementation-Log.md) | Historie, Tests und Korrekturen früherer Befunde |
|
||||
|
||||
## Arbeiten mit dem Repository
|
||||
|
||||
Dieses Repository enthält derzeit Dokumentation und noch keine Ansible-Rollen oder ausführbare Bereitstellung des KI-Anwendungsstacks. Vor einer Infrastrukturänderung den Ist-Stand am betroffenen Host prüfen, die passende Fachanleitung lesen und die dort genannten Abnahmeschritte dokumentieren. Der KI-Server soll bis zum geplanten Ansible-Sprint abgesehen von den eingerichteten Benutzerzugängen ein Basissystem bleiben.
|
||||
|
||||
WireGuard-Profile enthalten private Schlüssel. Sie gehören nicht in Git, Ausgaben oder freigegebene Dokumente. Das lokale Verzeichnis `docs/GNAI-006-profiles/` schließt Profil-Dateien über eine eigene `.gitignore` aus; es ist kein Verteiler- oder Backup-Ort für Zugangsdaten.
|
||||
|
||||
Änderungen am Projektstand sollten zuerst im zuständigen Fachdokument mit Datum und Beleg erfasst werden. Anschließend den [Index](docs/GNAI-000-DOC_Index.md) und diese README aktualisieren, wenn sich eine übergreifende Aussage geändert hat.
|
||||
@@ -0,0 +1,62 @@
|
||||
# Ghostnet.AI – Dokumentationsindex und Projektstand
|
||||
|
||||
**Stand:** 2026-09-19
|
||||
**Status:** Revisionen zusammengeführt; Sicherheitsumsetzung und technische Endabnahme offen
|
||||
|
||||
## 1. Dokumente und Zielgruppen
|
||||
|
||||
| Dokument | Zweck / Zielgruppe |
|
||||
| --- | --- |
|
||||
| [GNAI-001-INFRA_BaseSystem.md](GNAI-001-INFRA_BaseSystem.md) | Hardware und Debian-Installation; Intermediate IT |
|
||||
| [GNAI-002-INFRA_Users.md](GNAI-002-INFRA_Users.md) | Benutzer, statisches Hostnetz, Resolver und SSH; Intermediate IT |
|
||||
| [GNAI-003-INFRA_Architecture.md](GNAI-003-INFRA_Architecture.md) | Gesamtzielarchitektur und Inventar; Intermediate IT |
|
||||
| [GNAI-004-SEC_Access-Control.md](GNAI-004-SEC_Access-Control.md) | verbindliches Rollen- und Zugriffsziel; Intermediate IT |
|
||||
| [GNAI-005-SEC_Reverse-Proxy.md](GNAI-005-SEC_Reverse-Proxy.md) | NPM/Fail2Ban und Keycloak-Korrekturverfahren; Intermediate IT |
|
||||
| [GNAI-006-SEC_VPN.md](GNAI-006-SEC_VPN.md) | wg-easy-Installation/Konfiguration in Proxmox LXC; Intermediate IT |
|
||||
| [GNAI-006-SEC_VPN_Client-Management.md](GNAI-006-SEC_VPN_Client-Management.md) | neue eigenständige GUI-SOP für Ausgabe, Änderungen und Widerruf; Intermediate IT |
|
||||
| [GNAI-006-SEC_VPN_Clients_Windows11.md](GNAI-006-SEC_VPN_Clients_Windows11.md) | offizieller Windows-Client, Import und Verwendung; Junior IT |
|
||||
| [GNAI-006-SEC_VPN_Clients_Linux.md](GNAI-006-SEC_VPN_Clients_Linux.md) | Debian, Arch/CachyOS, Fedora/Kinoite; Junior IT |
|
||||
| [GNAI-006-SEC_VPN_Implementation-Log.md](GNAI-006-SEC_VPN_Implementation-Log.md) | historische v14/v15-Umsetzung und Evidenzkorrekturen; Intermediate IT |
|
||||
|
||||
## 2. Verbindliche, bestätigte Entscheidungen
|
||||
|
||||
NPM ist `.10`, WireGuard `.15`, Proxmox `.2`, KI-Server `.90`, Fritzbox `.1`, jeweils im Heimnetz `10.0.0.0/24`. Server/LXCs verwenden statische Adressen bis `.99`, Client-DHCP `.100–.200`. Der aktuelle Bereich ist keine VLAN-Isolation und keine automatische Server-Admin-ACL.
|
||||
|
||||
Familie darf das gesamte Heimnetz erreichen; Server Admins Proxmox, Service-LXCs und KI-Server; LLM Admins ausschließlich KI-Server. Profile werden durch Administratoren pro Gerät erstellt und geschützt verteilt. Serverseitige Firewall Allowed IPs sollen die Rechte erzwingen. Per-Client Firewall ist aber derzeit deaktiviert. wg-easy-GUI-Zugriff ist für Familie und Server Admin vorgesehen; HTTPS ist ein offener Umsetzungsvorschlag.
|
||||
|
||||
wg-easy läuft rootful in CT 105 als Podman-Quadlet mit v15.4.0 und host-Netz im LXC. Ein lesender SSH-Abgleich am 18.09.2026 bestätigte aktives `wg-easy`/`nftables`, IPv4-Forwarding, eine breite VPN→LAN-Regel und MASQUERADE in `iptables-legacy`; Details und Grenzen stehen im [Implementation-Log](GNAI-006-SEC_VPN_Implementation-Log.md). MASQUERADE wird mangels Rückroute gebraucht. Ein nftables-Reload mit `flush ruleset` kann dynamische Regeln entfernen; Wiederanlauf muss abgenommen werden.
|
||||
|
||||
Der KI-Server heißt laut lesendem SSH-Abgleich vom 18.09.2026 `ghostnet-ki`; die Konten sind `ghost`, `debugofen` und das neu angelegte `ghost-agent`. `admin` existiert auf diesem Host nicht; der WireGuard-LXC verwendet separat `admin`. `ghostnet.ki` mit Punkt ist höchstens ein lokal angelegter SSH-Alias. OIDC ist laut Betreiber produktiv nur für Vaultwarden; weitere Dienste sind geplant.
|
||||
|
||||
Die getrennten Schlüsselzugänge für `ghost` und `ghost-agent` wurden am 19.09.2026 erfolgreich getestet. Der persönliche Login wurde vom Betreiber interaktiv bestätigt; der Agentenlogin wurde technisch gegen Benutzername und Hostname geprüft.
|
||||
|
||||
Der KI-Server ist laut Betreiber frisch eingerichtet. Die LLM-Anwendungen sollen erst in einem späteren Sprint mit Ansible installiert werden. Bis dahin beschreiben GNAI-003 und GNAI-004 für diesen Host ein Zielbild; der lesende SSH-Abgleich betraf nur Basisbetrieb und Zugänge.
|
||||
|
||||
## 3. Sicherheitsbefunde mit Priorität
|
||||
|
||||
| Befund | dokumentiertes Verfahren / Status |
|
||||
| --- | --- |
|
||||
| Keycloak-Administration öffentlich erreichbar, externe Anmeldung möglich | [GNAI-005](GNAI-005-SEC_Reverse-Proxy.md): Adminpfad-Schutz, interner Adminzugang, externe Sperrtests und Vaultwarden-OIDC-Prüfung; noch nicht angewendet |
|
||||
| VPN-Zielrechte nur im lokalen Profil | [GNAI-006](GNAI-006-SEC_VPN.md) und [GUI-SOP](GNAI-006-SEC_VPN_Client-Management.md): Per-Client Firewall, Gateway-INPUT-Regeln und negative Tests; noch nicht angewendet |
|
||||
| Fail2Ban-Image auf `1.1.0-r2-ls43` fest gepinnt; Container läuft wieder | [GNAI-005](GNAI-005-SEC_Reverse-Proxy.md): Pin umgesetzt; effektives Image, Jails, kontrollierte Bans sowie Dienst-/LXC-Wiederanlauf noch abzunehmen |
|
||||
| HTTP-Client-User-Agents werden bewusst gebannt | [GNAI-005](GNAI-005-SEC_Reverse-Proxy.md): mögliche legitime Treffer und rollen-/routingabhängiger VPN-Ausweichweg dokumentiert |
|
||||
|
||||
## 4. Noch erforderliche Angaben
|
||||
|
||||
| Frage / fehlender Nachweis | Grund |
|
||||
| --- | --- |
|
||||
| Aktualisiert selfHOST den VPN-Eintrag nach einem WAN-IP-Wechsel zuverlässig? | Am 18.09.2026 stimmte `vpn.ghostnet.selfhost.eu` mit der ausgehenden IPv4 des Gateways überein; `vpn.ghostnet.dyndns.eu` zeigte auf eine andere IPv4. Profile verwenden `selfhost.eu`. Ein einzelner Abgleich belegt keinen dauerhaften DynDNS-Betrieb. |
|
||||
| Gehört Altpeer Laptop-FullAdmin künftig Familie oder Server Admin? | neue Zielrechte und Gateway-INPUT-Freigaben hängen davon ab. |
|
||||
| Welche Verwaltungsgeräte dürfen lokal auf die GUI und welcher interne Adminhostname soll verwendet werden? | VPN-Rollen ordnen lokale LAN-Quellen nicht automatisch zu. |
|
||||
| Welchen OIDC-Issuer/Realm nutzt Vaultwarden und wo terminiert auth-HTTPS tatsächlich? | NPM-SSL-Optionen aus, externer HTTPS-Login möglich; Realm-Sperren dürfen den produktiven Login nicht unbeabsichtigt stören. |
|
||||
| Welcher Dienst erzeugt `/etc/resolv.conf` auf dem KI-Server tatsächlich? | `networking` verwaltet die statische Schnittstelle; die Datei trägt einen dhcpcd-Kommentar, obwohl dhcpcd beim Abgleich nicht aktiv war. Vor einer DNS-Änderung den Erzeugungsweg prüfen. |
|
||||
|
||||
Es werden keine Werte für diese offenen Angaben angenommen. Die betreffenden Verfahren sind entsprechend eingeschränkt oder als Vorschlag markiert.
|
||||
|
||||
## 5. Validierung und Abschluss
|
||||
|
||||
Bei der Dokumentationskonsolidierung wurden keine Serverkonfigurationen geändert, keine VPN-Praxisprüfungen nachgeholt und keine Keycloak-Sperre live bestätigt. Aussagen zum Ist-Stand beruhen auf den protokollierten Betreiberangaben und Tests; sie sind keine neue Live-Inventur.
|
||||
|
||||
Am 18.09.2026 wurden WireGuard-LXC und KI-Server ergänzend lesend per SSH geprüft. Der KI-Server-Teilabgleich bestätigt Hostname, Konten, Netzkonfiguration, Debian-Version, CPU, RAM, zwei Navi-21-GPUs und SSD-Partitionierung; BIOS, ROCm und die Anwendungsdienste wurden dabei nicht abgenommen. Details stehen in [GNAI-001](GNAI-001-INFRA_BaseSystem.md) und [GNAI-002](GNAI-002-INFRA_Users.md).
|
||||
|
||||
Die WireGuard-Evidenz bleibt der Teiltest vom 12.09.2026: CachyOS-Laptop von WAN, Handshake, Ping auf Gateway/Proxmox und direkter IPv4-Internetpfad bestanden; KI-Server war ausgeschaltet. Neue Rollen, weitere Clientvarianten, Gateway-GUI-Zugriff, WAN-/IPv6-Isolation, Neustart und Restore sind noch nicht abgenommen. GNAI-006 ist erst nach Klärung der offenen Werte, Umsetzung und dokumentierter Abnahme technisch abgeschlossen.
|
||||
@@ -2,15 +2,26 @@
|
||||
|
||||
**Dokumenten-ID:** GNAI-001-INFRA
|
||||
**Titel:** Initialisierung und OS-Installation: LLM-Server (Phase 1)
|
||||
**Version:** 1.1
|
||||
**Status:** Architekturentscheidung
|
||||
**Vorgänger / Referenzen:** -
|
||||
**Status:** Installationsanleitung mit lesendem Teilabgleich; vollständige Abnahme offen
|
||||
**Referenzen:** -
|
||||
|
||||
---
|
||||
|
||||
## Änderungsverlauf
|
||||
|
||||
| Datum | Version | Autor | Beschreibung der Änderung |
|
||||
| --- | --- | --- | --- |
|
||||
| 2026-08-24 | 1.0 | spektr | Erstellung des Initial-Dokuments (Hardware & OS) |
|
||||
| 2026-08-24 | 1.1 | spektr | Detaillierung der BIOS-ReBAR-Settings, Netinst-CLI-Schritte, Post-Installation & Abnahmekriterien hinzugefügt. |
|
||||
| 2026-09-16 | 1.2 | spektr | Benutzer- und Netzwerkaufgaben nach GNAI-002 verlagert; ungesicherte Downloadpfade und Domainvorgabe entfernt. |
|
||||
| 2026-09-18 | 1.3 | spektr | GPU-Abnahme auf nachweisbare Geräteerkennung begrenzt; Firmwarepaket präzisiert. |
|
||||
| 2026-09-19 | 1.4 | spektr | Getrennte SSH-Zugänge für `ghost` und `ghost-agent` als erfolgreich getestet übernommen. |
|
||||
|
||||
---
|
||||
|
||||
## 1. Zweck und Geltungsbereich
|
||||
|
||||
Dieses Dokument beschreibt den standardisierten Prozess für die Hardware-Konfiguration, BIOS-Einstellung, Betriebssystem-Installation und Basis-Härtung von LLM-Servern (Large Language Model). Ziel ist die Gewährleistung einer reproduzierbaren, fehlerfreien und performanten Basis für die spätere KI-Anwendungssoftware.
|
||||
Dieses Dokument beschreibt Hardware, BIOS und Debian-Installation des KI-Servers. Benutzer, statische Netzkonfiguration und SSH-Härtung werden in [GNAI-002](GNAI-002-INFRA_Users.md) eingerichtet. Die Schritte sind eine Anleitung, kein Nachweis ihrer Ausführung auf dem bestehenden Host.
|
||||
|
||||
---
|
||||
|
||||
@@ -45,7 +56,7 @@ Vor der Betriebssystem-Installation sind folgende Schritte im BIOS (Aufrufen via
|
||||
* Navigieren zu: `Advanced` -> `CPU Configuration` -> **Intel Virtualization Technology** -> `Enabled`.
|
||||
* Navigieren zu: `Advanced` -> `PCI Configuration`:
|
||||
* **Above 4G Decoding:** `Enabled`
|
||||
* **Re-Size BAR Support:** `Enabled` *(Kritisch für AMD ROCm Multi-GPU-Performance!)*
|
||||
* **Re-Size BAR Support:** `Enabled`; tatsächliche GPU-Zuordnung nach der Installation prüfen. Aus der BIOS-Option allein folgt noch kein nachgewiesener ROCm-Leistungsgewinn.
|
||||
|
||||
---
|
||||
|
||||
@@ -53,17 +64,13 @@ Vor der Betriebssystem-Installation sind folgende Schritte im BIOS (Aufrufen via
|
||||
|
||||
### 3.1 Vorbereitung des Installationsmediums (am Admin-PC)
|
||||
|
||||
1. **Debian ISO herunterladen:**
|
||||
```bash
|
||||
curl -L -O https://cdimage.debian.org/debian-cd/current-minimal/amd64/iso-cd/debian-netinst.iso
|
||||
```
|
||||
1. **Debian ISO herunterladen:** Die gewünschte Debian-Version und die passende `amd64`-Netinst-ISO auf [Debian CD Images](https://cdimage.debian.org/debian-cd/) auswählen. ISO und `SHA512SUMS` aus demselben Release-Verzeichnis herunterladen; Dateinamen nicht aus dieser Anleitung ableiten.
|
||||
|
||||
2. **Checksum verifizieren:**
|
||||
```bash
|
||||
curl -O https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/SHA512SUMS
|
||||
sha512sum --ignore-missing -c SHA512SUMS
|
||||
```
|
||||
*Erwartete Ausgabe:* `debian-netinst.iso: OK` (Treffen Fehler auf, Download wiederholen).
|
||||
Erwartet wird eine `OK`-Zeile für die tatsächlich heruntergeladene ISO. Bei einem Fehler Download und Prüfsummenquelle kontrollieren.
|
||||
|
||||
3. **Bootfähigen USB-Stick erstellen:**
|
||||
* [Ventoy](https://www.ventoy.net) auf dem USB-Stick installieren.
|
||||
@@ -83,15 +90,15 @@ Vor der Betriebssystem-Installation sind folgende Schritte im BIOS (Aufrufen via
|
||||
* **Tastaturlayout:** `Deutsch`
|
||||
|
||||
3. **Netzwerk & Hostname:**
|
||||
* **Hostname:** `ghostnet-ai-node-01` (oder entsprechend Vorgabe des IP-Plans).
|
||||
* **Domain-Name:** `ghost.net`
|
||||
* **Hostname:** `ghostnet-ki` (auf dem bestehenden KI-Server am 18.09.2026 per `hostnamectl` bestätigt).
|
||||
* **Domain-Name:** Nur eine tatsächlich konfigurierte lokale Domain eintragen; andernfalls leer lassen. `ghostnet.ki` ist in dieser Dokumentation lediglich ein optionaler SSH-Alias.
|
||||
* **Netzwerk:** Per DHCP konfigurieren lassen. *(Feste IP wird nach der Installation vergeben).*
|
||||
|
||||
4. **Benutzerverwaltung:**
|
||||
* **Root-Passwort:** Starkes Passwort aus dem Passwort-Manager eintragen.
|
||||
* **Neuer Benutzer:**
|
||||
* Vollständiger Name: `Admin`
|
||||
* Benutzername: `gnaiadmin`
|
||||
* Benutzername: vor der Installation festlegen. Der bestehende KI-Server verwendet `ghost` als initiales Administrationskonto; `admin` ist dort nicht vorhanden.
|
||||
* Passwort: Sicheres Kennwort vergeben.
|
||||
|
||||
5. **Partitionierung (Manuell / Geführt):**
|
||||
@@ -120,62 +127,17 @@ Vor der Betriebssystem-Installation sind folgende Schritte im BIOS (Aufrufen via
|
||||
|
||||
---
|
||||
|
||||
### 3.3 Post-Installation & Basis-Härtung (Erst-Setup via CLI)
|
||||
### 3.3 Grundlegende Werkzeuge und Firmware
|
||||
|
||||
Nach dem Neustart als `root` am Terminal anmelden und folgende Schritte ausführen:
|
||||
|
||||
#### 1. Sudo-Rechte für den Admin-User einrichten
|
||||
Für die AMD-GPUs ist in Debian 13 das Paket [`firmware-amd-graphics`](https://packages.debian.org/trixie/firmware-amd-graphics) aus `non-free-firmware` vorgesehen. Das breitere Metapaket `firmware-linux-nonfree` zieht dieses Paket bereits als Abhängigkeit nach sich und wird für diesen Schritt nicht zusätzlich benötigt. Die folgende Anweisung gehört zu einer Neuinstallation oder zum späteren Ansible-Sprint, nicht zu diesem Dokumentationsabgleich:
|
||||
|
||||
```bash
|
||||
apt update && apt install -y sudo
|
||||
usermod -aG sudo gnaiadmin
|
||||
```
|
||||
|
||||
#### 2. Netzwerk auf Statische IP umstellen
|
||||
|
||||
Datei `/etc/network/interfaces` anpassen (Beispiel-IP an den lokalen Netzwerkplan anpassen):
|
||||
|
||||
```bash
|
||||
nano /etc/network/interfaces
|
||||
```
|
||||
|
||||
Inhalt anpassen/ergänzen:
|
||||
|
||||
```text
|
||||
auto enp8s0
|
||||
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
|
||||
```
|
||||
|
||||
Netzwerk neustarten: `systemctl restart networking`
|
||||
|
||||
#### 3. Grundlegende Admin-Tools & Firmware installieren
|
||||
|
||||
Da AMD RX 6900 XT GPUs verwendet werden, müssen die Unfree-Firmware-Pakete vorbereitet werden:
|
||||
|
||||
```bash
|
||||
# Non-free Repository aktivieren
|
||||
apt install -y software-properties-common
|
||||
apt-add-repository non-free-firmware -y
|
||||
# Vorher prüfen, ob die Debian-Paketquellen die Komponente non-free-firmware enthalten.
|
||||
apt update
|
||||
|
||||
# Grundlegende Tools und GPU-Firmware installieren
|
||||
apt install -y curl wget git htop tmux pciutils firmware-amd-graphics firmware-linux-nonfree
|
||||
apt install -y curl wget git htop tmux pciutils firmware-amd-graphics
|
||||
```
|
||||
|
||||
#### 4. SSH-Schlüssel hinterlegen (Remote-Zugriff)
|
||||
|
||||
Wechsle zum Admin-User:
|
||||
|
||||
```bash
|
||||
su - gnaiadmin
|
||||
mkdir -p ~/.ssh
|
||||
chmod 700 ~/.ssh
|
||||
nano ~/.ssh/authorized_keys # Public-Key des Admin-PCs einfügen
|
||||
chmod 600 ~/.ssh/authorized_keys
|
||||
```
|
||||
Für Sudo, Netzwerk und SSH mit [GNAI-002](GNAI-002-INFRA_Users.md) fortfahren. Vor Änderungen auf einem laufenden Host die dort dokumentierte Netzverwaltung prüfen.
|
||||
|
||||
---
|
||||
|
||||
@@ -184,16 +146,13 @@ chmod 600 ~/.ssh/authorized_keys
|
||||
Vor der Übergabe an das KI-Team (Phase 2) muss das System folgende Punkte bestehen:
|
||||
|
||||
* **RAM-Check:** `free -h` zeigt mindestens ~62 GB RAM an.
|
||||
* **GPU-Erkennung:** `lspci | grep -i vga` listet **beide** AMD RX 6900 XT Grafikkarten auf.
|
||||
* **Netzwerk:** Der Server ist via SSH (`ssh gnaiadmin@<IP>`) vom Admin-PC erreichbar.
|
||||
* **Storage:** `df -h /` zeigt die vollständige ~2 TB Partition an.
|
||||
* **Re-Size BAR:** Prüfen mit `dmesg | grep -i BAR`. Es sollten Einträge vorhanden sein, die auf erfolgreiche Zuordnung hinweisen (ReBAR active).
|
||||
* **GPU-Erkennung:** `lspci -nn | grep -Ei 'vga|display|3d'` listet **zwei** AMD-Grafikgeräte auf. Das genaue Kartenmodell anhand des Hardwareinventars oder der Geräte selbst prüfen; die PCI-Familienkennung allein genügt dafür nicht.
|
||||
* **Netzwerk:** Der Server ist nach GNAI-002 unter `10.0.0.90` erreichbar. Die getrennten SSH-Zugänge für `ghost` und `ghost-agent` wurden am 19.09.2026 erfolgreich getestet.
|
||||
* **Storage:** `lsblk -f` zeigt die vorgesehene Partitionierung der 2-TB-SSD; `df -h /` zeigt die nutzbare Dateisystemgröße (in binären Einheiten kleiner als 2 TB).
|
||||
* **Re-Size BAR:** BIOS-Einstellung und zugewiesene PCIe-BAR-Größen getrennt prüfen; ein bloßer `dmesg | grep -i BAR`-Treffer gilt nicht als Funktions- oder Leistungsnachweis.
|
||||
|
||||
---
|
||||
|
||||
## 5. Dokumentation der Änderungen
|
||||
## 5. Lesender Teilabgleich des bestehenden Hosts am 18.09.2026
|
||||
|
||||
| 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. |
|
||||
Per SSH wurden Debian 13.6, Hostname `ghostnet-ki`, Intel Core i5-13600K, 62 GiB nutzbarer RAM und zwei AMD Navi-21-GPUs mit PCI-ID `1002:73bf` beobachtet. `lsblk` zeigt eine 1,8-TiB-NVMe mit EFI-, ext4-Root- und Swap-Partition; `df -h /` zeigte 1,8 TiB Dateisystemgröße. `lspci` bestätigt die Gerätefamilie, aber weder das genaue Kartenmodell noch ROCm-Funktion und ReBAR-Leistung. BIOS-Version, XMP, Firmwarestand und Restore wurden nicht geprüft.
|
||||
|
||||
@@ -2,21 +2,33 @@
|
||||
|
||||
**Dokumenten-ID:** GNAI-002-INFRA
|
||||
**Titel:** Benutzerverwaltung, SSH-Härtung & Netzwerkkonfiguration (Phase 2)
|
||||
**Version:** 1.0
|
||||
**Status:** Betriebsanleitung; tatsächliche Netzverwaltung und Konten vor Anwendung prüfen
|
||||
|
||||
---
|
||||
|
||||
## Änderungsverlauf
|
||||
|
||||
| Datum | Version | Autor | Beschreibung der Änderung |
|
||||
| --- | --- | --- | --- |
|
||||
| 2026-08-26 | 1.0 | spektr | Erstellung des Dokuments (Benutzer, Netzwerkkonfiguration, SSH-Härtung) |
|
||||
| 2026-09-15 | 1.1 | spektr | Kontenbestand, DNS-Verwaltung und SSH-Dienstnamen präzisiert; doppelte Basisschritte bereinigt. |
|
||||
| 2026-09-16 | 1.2 | spektr | Tatsächliche Konten, Gruppen, Netz- und SSH-Konfiguration sowie Grenzen des Login-Tests dokumentiert. |
|
||||
| 2026-09-18 | 1.3 | spektr | Workstation-spezifische Schlüsselpfade und Host-Fingerprint in den lokalen Arbeitskontext verlagert. |
|
||||
| 2026-09-19 | 1.4 | spektr | Persönlichen Login `ghost` und Agentenlogin `ghost-agent` als erfolgreich getestet dokumentiert. |
|
||||
|
||||
---
|
||||
|
||||
## 1. Zweck und Geltungsbereich
|
||||
|
||||
Dieses Dokument beschreibt die Erstellung von Systembenutzern mit Berechtigungen, die Härtung des SSH-Dienstes (Abschaltung von Root-Login und Passwort-Authentifizierung), die Umstellung auf eine statische IP-Adresse sowie die Konfiguration des SSH-Zugriffs von Admin-Workstations auf LLM-Servern.
|
||||
Dieses Dokument beschreibt Benutzer, statische IP und SSH des KI-Servers. Der lesend geprüfte Kontenbestand am 18.09.2026 lautet `ghost`, `debugofen`, `ghost-agent`; `admin` existiert auf diesem Host nicht. Die folgenden Befehle sind für Neuinstallation oder gezielte Änderung gedacht und ersetzen keine Prüfung des vorhandenen Systems. Der WireGuard-LXC besitzt ein separates Konto `admin`.
|
||||
|
||||
---
|
||||
|
||||
## 2. Voraussetzungen & Berechtigungen
|
||||
|
||||
* Bereits installiertes Debian-Grundsystem gemäß **GNAI-INFRA-001**.
|
||||
* Bereits installiertes Debian-Grundsystem gemäß [GNAI-001](GNAI-001-INFRA_BaseSystem.md).
|
||||
* Root-Zugriff oder Benutzer mit `sudo`-Rechten.
|
||||
* Admin-Workstation mit lokal installierter SSH-Suite (`ssh-keygen`, `ssh-copy-id`).
|
||||
* Admin-Workstation mit lokal installierter SSH-Suite (`ssh`, `ssh-keygen`); für den bestehenden Host ist die lokale Konsole oder ein bereits berechtigter Zugang zur Schlüsselaufnahme nötig.
|
||||
|
||||
---
|
||||
|
||||
@@ -35,29 +47,32 @@ apt update && apt install -y sudo
|
||||
|
||||
#### 2. Benutzer anlegen & Berechtigungen vergeben
|
||||
|
||||
> **Wichtig:** Beim Anlegen von Benutzern immer `adduser` verwenden (interaktive Eingabe von Passwort und Benutzerdaten). Falls versehentlich `userdel` benötigt wird, zwingend die Option `-r` nutzen, um das Home-Verzeichnis mit aufzuräumen (`sudo userdel -r <username>`).
|
||||
Vor dem Anlegen prüfen, ob das Konto bereits existiert (`getent passwd <username>`). Konten und Home-Verzeichnisse nur nach Prüfung ihrer Daten und Berechtigungen entfernen.
|
||||
|
||||
Neuen Benutzer anlegen und zur `sudo`-Gruppe hinzufügen:
|
||||
Nur bei einer **Neuinstallation** einen vorher festgelegten Administrationsbenutzer anlegen und zur `sudo`-Gruppe hinzufügen. Auf dem bestehenden KI-Server besitzen `ghost` und `debugofen` bereits sudo-Gruppenmitgliedschaft. Das folgende Beispiel mit `ghost` dort nicht ausführen:
|
||||
|
||||
```bash
|
||||
# Beispiel für Benutzer 'ghost' oder 'debugofen'
|
||||
sudo adduser debugofen
|
||||
sudo usermod -aG sudo debugofen
|
||||
# Nur auf einem neuen System ausführen.
|
||||
sudo adduser ghost
|
||||
sudo usermod -aG sudo ghost
|
||||
```
|
||||
|
||||
Weitere Konten nur nach Rollenentscheidung anlegen. Die sudo-Gruppenmitgliedschaft ist pro Konto ausdrücklich festzulegen; auf dem bestehenden Host keine bereits vorhandenen Konten erneut anlegen.
|
||||
|
||||
---
|
||||
|
||||
### 3.2 Statische Netzwerkkonfiguration (Server-Seite)
|
||||
|
||||
#### 1. Netzschnittstelle ermitteln & anpassen
|
||||
|
||||
Primäre Netzwerkschnittstelle anzeigen lassen (z. B. `enp8s0`):
|
||||
Primäre Netzwerkschnittstelle und zuständigen Netzwerkdienst ermitteln (z. B. `enp8s0`):
|
||||
|
||||
```bash
|
||||
ip addr show
|
||||
systemctl is-active networking NetworkManager systemd-networkd dhcpcd
|
||||
```
|
||||
|
||||
Datei bearbeiten: `/etc/network/interfaces`:
|
||||
Nur falls `ifupdown` den Host tatsächlich verwaltet, `/etc/network/interfaces` bearbeiten. Bei NetworkManager, systemd-networkd oder dhcpcd deren Konfiguration verwenden; die Schnittstelle darf nicht von mehreren Diensten zugleich verwaltet werden.
|
||||
|
||||
```bash
|
||||
sudo nano /etc/network/interfaces
|
||||
@@ -78,98 +93,42 @@ iface enp8s0 inet static
|
||||
dns-nameservers 10.0.0.1 1.1.1.1
|
||||
```
|
||||
|
||||
#### 2. DNS-Resolver prüfen/anpassen
|
||||
#### 2. DNS-Resolver prüfen
|
||||
|
||||
Datei überprüfen `/etc/resolv.conf`:
|
||||
|
||||
```bash
|
||||
sudo nano /etc/resolv.conf
|
||||
```
|
||||
|
||||
Sicherstellen, dass folgende Nameserver eingetragen sind:
|
||||
|
||||
```text
|
||||
nameserver 10.0.0.1
|
||||
nameserver 1.1.1.1
|
||||
```
|
||||
`/etc/resolv.conf` kann von einem Netzwerk- oder Resolverdienst erzeugt werden. Den aktiven Dienst und die wirksamen Nameserver prüfen (`readlink -f /etc/resolv.conf`, `cat /etc/resolv.conf`); Änderungen in dessen Konfiguration vornehmen. Die aktuelle Solladresse des Heimnetz-DNS ist `10.0.0.1`.
|
||||
|
||||
#### 3. Netzwerkdienst neustarten & Funktion prüfen
|
||||
|
||||
```bash
|
||||
sudo systemctl restart networking
|
||||
sudo systemctl restart networking # nur bei ifupdown und mit Konsolenzugang
|
||||
ip -4 addr
|
||||
ping -c 4 google.com
|
||||
```
|
||||
|
||||
*(Tritt ein Konfigurationskonflikt auf, das System einmal per `sudo reboot` neustarten).*
|
||||
Vor einem Remote-Neustart einen Rückweg über Konsole/Proxmox sicherstellen. Ein Reboot behebt keine widersprüchliche Netzkonfiguration.
|
||||
|
||||
---
|
||||
|
||||
### 3.3 SSH-Key-Generierung & Übertragung (Workstation-Seite)
|
||||
### 3.3 SSH-Schlüssel und getrennte Konten
|
||||
|
||||
Die folgenden Schritte werden auf der **lokalen Workstation** ausgeführt.
|
||||
Für persönliche und automatisierte Zugriffe getrennte Konten und klar benannte Schlüsselpaare verwenden. Auf dem bestehenden KI-Server sind `ghost` und `ghost-agent` getrennt; `ghost-agent` hat keine sudo-Gruppenmitgliedschaft. Schlüsseldateien, lokale SSH-Aliase und der auf dieser Workstation bekannte Hostschlüssel-Fingerprint sind nur im lokalen, nicht versionierten Arbeitskontext vermerkt. Private Schlüssel und Passphrasen gehören weder in diese Dokumentation noch in ein Serverinventar. Ein Kommentar wie `@ghostnet-ki` im Public Key ist nur ein Label; die Zuordnung erfolgt über den Schlüsselinhalt und das jeweilige `authorized_keys`.
|
||||
|
||||
#### 1. Ed25519 SSH-Schlüsselpaar erzeugen
|
||||
Neue öffentliche Schlüssel auf dem bestehenden Host über eine bereits berechtigte Sitzung oder die lokale Konsole in das **richtige Konto** unter `~/.ssh/authorized_keys` eintragen; bestehende Schlüssel dabei erhalten. Verzeichnis auf `700`, Datei auf `600` und Eigentümer auf das Zielkonto setzen. Passwort-SSH ist bereits deaktiviert, daher ist `ssh-copy-id` ohne bestehenden Schlüsselzugang hier kein Wiederherstellungsverfahren.
|
||||
|
||||
Vor Erstverbindung den Hostschlüssel-Fingerprint aus einer vertrauenswürdigen Konsole abgleichen. Die lokalen SSH-Aliase müssen auf `10.0.0.90`, das jeweils richtige Konto und Schlüsseldatei zeigen; `IdentitiesOnly yes` und strikte Hostschlüsselprüfung verwenden. Die folgenden Beispiele setzen entsprechend eingerichtete Aliase auf der Admin-Workstation voraus:
|
||||
|
||||
```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
|
||||
ssh ghostnet-ai-ghost 'id -un; hostnamectl --static'
|
||||
ssh ghostnet-ai-agent 'id -un; hostnamectl --static'
|
||||
```
|
||||
|
||||
#### 2. Public Keys auf den Server übertragen
|
||||
|
||||
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
|
||||
|
||||
```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`)
|
||||
|
||||
Die Datei `~/.ssh/config` auf der Workstation erstellen/bearbeiten, um Kurznamen für Verbindungen zu nutzen:
|
||||
|
||||
```bash
|
||||
nano ~/.ssh/config
|
||||
```
|
||||
|
||||
Inhalt eintragen:
|
||||
|
||||
```text
|
||||
Host *
|
||||
AddKeysToAgent yes
|
||||
IdentitiesOnly yes
|
||||
|
||||
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
|
||||
```
|
||||
Für `ghost` ist auf der aktuellen Workstation eine Passphrase-Eingabe am Terminal erforderlich, sofern der Schlüssel nicht bereits im SSH-Agenten entsperrt wurde. Beide Profile sind getestet: `ghost-agent` wurde am 19.09.2026 erneut technisch geprüft; der Betreiber bestätigte am selben Tag den erfolgreichen interaktiven Login als `ghost`.
|
||||
|
||||
---
|
||||
|
||||
### 3.4 SSH-Dienst härten (Server-Seite)
|
||||
|
||||
Sobald der SSH-Key-Login erfolgreich getestet wurde, wird die Passwort-Authentifizierung aus Sicherheitsgründen serverseitig komplett deaktiviert.
|
||||
Nur auf einem **neu eingerichteten System** nach erfolgreichem SSH-Key-Test die Passwort-Authentifizierung deaktivieren. Auf dem bestehenden KI-Server ist das folgende Drop-in bereits vorhanden; es wurde am 18.09.2026 lesend geprüft.
|
||||
|
||||
#### 1. Drop-in-Konfiguration für SSH erstellen
|
||||
|
||||
@@ -203,23 +162,23 @@ PubkeyAuthentication yes
|
||||
sudo sshd -t
|
||||
|
||||
# Wenn sshd -t keine Fehler ausgibt, Dienst neustarten
|
||||
sudo systemctl restart sshd
|
||||
sudo systemctl restart ssh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Abnahmekriterien (Checkliste für den Junior-Admin)
|
||||
|
||||
* [ ] **Benutzerprüfung:** Der Benutzer kann sich mit `sudo` administrative Rechte verschaffen (`whoami` nach `sudo` ergibt `root`).
|
||||
* [ ] **Benutzerprüfung:** `ghost` und `debugofen` können ihre vorgesehenen sudo-Rechte nutzen; `ghost-agent` bleibt ohne sudo-Zuweisung.
|
||||
* [ ] **Netzwerk:** Server ist unter der statischen IP `10.0.0.90` erreichbar. Ausgehender Datenverkehr funktioniert (`ping google.com`).
|
||||
* [ ] **SSH-Alias:** Der Login von der Workstation über `ssh ghostnet.ki` funktioniert ohne Passworteingabe.
|
||||
* [x] **SSH-Aliase:** `ghostnet-ai-ghost` meldet `ghost`, `ghostnet-ai-agent` meldet `ghost-agent`. Beide Zugänge wurden am 19.09.2026 bestätigt. Die Passphrase des persönlichen Schlüssels ist keine Server-Passwortanmeldung.
|
||||
* [ ] **Root-Sperre:** Direct-Login als Root per SSH wird abgelehnt (`ssh root@10.0.0.90` -> *Permission denied*).
|
||||
* [ ] **Passwort-Sperre:** Login-Versuch ohne hinterlegten SSH-Key wird direkt abgelehnt (keine Passwort-Aufforderung mehr).
|
||||
|
||||
---
|
||||
|
||||
## 5. Dokumentation der Änderungen
|
||||
## 5. Lesender Ist-Abgleich am 18.09.2026
|
||||
|
||||
| Datum | Version | Geändert von | Beschreibung der Änderung |
|
||||
| --- | --- | --- | --- |
|
||||
| 2026-08-26 | 1.0 | spektr | Erstellung des Dokuments (Benutzer, Netzwerkkonfiguration, SSH-Härtung) |
|
||||
`ghost` (UID 1000) und `debugofen` (UID 1001) gehören zur Gruppe `sudo`; `ghost-agent` (UID 1002) gehört nicht dazu. Der technische Login als `ghost-agent` und der vom Betreiber interaktiv geprüfte Login als `ghost` funktionieren mit ihren jeweils eigenen Schlüsseln. Die Prüfung belegt die Kontentrennung und den Schlüsselzugang, aber keine noch offenen sudo-, Root-Sperr- oder Negativtests.
|
||||
|
||||
`enp8s0` hat `10.0.0.90/24`, die Default-Route führt über `10.0.0.1`. `networking` und `ssh` sind aktiv und aktiviert. `/etc/network/interfaces` enthält die statische Konfiguration; `/etc/resolv.conf` nennt `10.0.0.1` und `1.1.1.1` und trägt einen dhcpcd-Generierungskommentar. Ein aktuell laufender `dhcpcd`-Dienst wurde nicht beobachtet; vor Resolveränderungen die tatsächliche Verwaltung erneut prüfen. Das SSH-Drop-in deaktiviert Root-, Passwort- und Keyboard-Interactive-Anmeldung und aktiviert Public-Key-Anmeldung.
|
||||
|
||||
@@ -2,9 +2,19 @@
|
||||
|
||||
**Dokumenten-ID:** GNAI-003-INFRA
|
||||
**Titel:** Homelab / LLM-Infrastruktur – Zielarchitektur
|
||||
**Version:** 1.0
|
||||
**Status:** Architekturentscheidung
|
||||
**Vorgänger / Referenzen:** GNAI-001-INFRA, GNAI-002-INFRA
|
||||
**Status:** Zielarchitektur; bestätigter Teilstand und offene Umsetzung separat ausgewiesen
|
||||
**Vorgänger / Referenzen:** [Basisinstallation](GNAI-001-INFRA_BaseSystem.md), [Benutzer/SSH](GNAI-002-INFRA_Users.md), [Zugriffskonzept](GNAI-004-SEC_Access-Control.md), [Reverse Proxy](GNAI-005-SEC_Reverse-Proxy.md), [WireGuard](GNAI-006-SEC_VPN.md)
|
||||
|
||||
---
|
||||
|
||||
## Änderungsverlauf
|
||||
|
||||
| Datum | Version | Autor | Beschreibung |
|
||||
| --- | --- | --- | --- |
|
||||
| 2026-08-28 | 1.0 | spektr | Erstellung der Zielarchitektur |
|
||||
| 2026-09-15 | 1.1 | spektr| Adressplan, Rollenmodell, OIDC-Ist und offene Sicherheitsbefunde ergänzt. |
|
||||
| 2026-09-16 | 1.2 | spektr | Bestätigten Fail2Ban-Pin und noch offene Funktionsabnahme ergänzt. |
|
||||
| 2026-09-18 | 1.3 | spektr | Tatsächlichen KI-Server-Hostnamen übernommen; frischen Basisstand und späteren Ansible-Sprint vom Zielbild getrennt. |
|
||||
|
||||
---
|
||||
|
||||
@@ -16,6 +26,8 @@ Es handelt sich ausdrücklich um eine **technische Spezifikation und kein Instal
|
||||
|
||||
Die Architektur baut auf dem in **GNAI-001-INFRA** beschriebenen Debian-basierten LLM-Server und der in **GNAI-002-INFRA** beschriebenen SSH-/Benutzer-Härtung auf.
|
||||
|
||||
Der KI-Server ist laut Betreiber am 18.09.2026 frisch eingerichtet. Sein LLM-Anwendungsstack soll in einem späteren Sprint mit Ansible installiert werden. `llama.cpp`, LiteLLM, OpenWebUI und GPT Researcher in diesem Dokument sind **geplante Komponenten**, keine bereits installierten Dienste.
|
||||
|
||||
---
|
||||
|
||||
## 2. Architekturprinzipien
|
||||
@@ -28,7 +40,7 @@ Die Infrastruktur folgt diesen Grundsätzen:
|
||||
4. **Anwendungsidentität über Keycloak:** Webanwendungen verwenden OIDC zur zentralen Authentifizierung.
|
||||
5. **LLM-API als dedizierte Applikationsschnittstelle:** Direkter Zugriff auf `llama.cpp` aus dem Internet ist nicht vorgesehen; die öffentliche LLM-Schnittstelle wird durch LiteLLM bereitgestellt.
|
||||
6. **Defense in Depth:** Reverse Proxy, Fail2Ban, Firewall-Regeln, MFA, Patchmanagement, Monitoring und Backups ergänzen sich.
|
||||
7. **Least Privilege:** Zugriffe werden pro Rolle, Peer, Host und Dienst eingeschränkt.
|
||||
7. **Least Privilege:** Server Admins und LLM Admins erhalten passende Serverrechte; Familie ist ausdrücklich für das gesamte Heimnetz freigegeben. Netzwerkrechte werden pro Peer serverseitig durchgesetzt.
|
||||
8. **Isolation:** Öffentlich exponierte Infrastruktur und einzelne Backend-Dienste bleiben logisch bzw. durch eigene LXCs getrennt.
|
||||
|
||||
---
|
||||
@@ -44,19 +56,37 @@ Der Proxmox-Server bildet die Virtualisierungs- und Isolationsschicht.
|
||||
| Proxmox VE | `10.0.0.2` | Virtualisierungs-/Managementhost |
|
||||
| Reverse Proxy LXC | `10.0.0.10` | einziger öffentlicher HTTP(S)-Entry-Point |
|
||||
| WireGuard LXC | `10.0.0.15` | VPN-/Managementzugang |
|
||||
| LLM Server | gemäß IP-Plan, aktuell `10.0.0.90` | KI-Inferenz und LLM-Dienste |
|
||||
| LLM Server | `10.0.0.90`, Hostname `ghostnet-ki` | KI-Inferenz und LLM-Dienste |
|
||||
|
||||
Die Service-LXCs (z. B. Nextcloud, Gitea, Vaultwarden, Keycloak etc.) verbleiben jeweils in eigenen LXCs und werden nicht in den Reverse-Proxy-LXC zusammengelegt.
|
||||
|
||||
### Adressplanung und aktuelles Serviceinventar
|
||||
|
||||
Heimnetz `10.0.0.0/24`, Fritzbox/Gateway/DNS `.1`. Statische Server-/LXC-Adressen sind bis `.99` vorgesehen; DHCP vergibt `.100–.200` an Clients. Die `.90` ist dem physischen KI-Server vorbehalten. Das ist eine Belegungsordnung innerhalb desselben Netzes, keine VLAN-/Firewall-Isolation.
|
||||
|
||||
| Host / Service | Quellenstand | Status der Angabe |
|
||||
| --- | --- | --- |
|
||||
| Proxmox | `10.0.0.2` | Betreiber bestätigt |
|
||||
| Keycloak | `10.0.0.4:8080` | Betreiber bestätigt NPM-Backend |
|
||||
| NPM / wg-easy | `10.0.0.10` / `10.0.0.15` | Betreiber bestätigt |
|
||||
| Jellyfin | `10.0.0.11:8096` | GNAI-005-Inventar, vor Freigabe abgleichen |
|
||||
| Nextcloud | `10.0.0.12:8080` | GNAI-005-Inventar, vor Freigabe abgleichen |
|
||||
| Gitea | `10.0.0.17:3000` | GNAI-005-Inventar, vor Freigabe abgleichen |
|
||||
| Japanese Web App | `10.0.0.23:80` | GNAI-005-Inventar, vor Freigabe abgleichen |
|
||||
| Vaultwarden | `10.0.0.47:8080` | GNAI-005-Inventar; OIDC-Nutzung vom Betreiber bestätigt |
|
||||
| KI-Server | `10.0.0.90` | Betreiber bestätigt |
|
||||
|
||||
Neue LXCs im Inventar ergänzen. Der ursprüngliche Bereich `.4–.40` war geschätzt und ist keine gültige Grenze. Lokales Gästenetz, mögliche separate Servernetze, Routing und VLAN-Unterstützung gehören in einen späteren Netzwerk-Sprint; es gibt hierfür noch keine beschlossenen Netzadressen. Automatische Broadcast-/Multicast-Geräteerkennung über WireGuard wird nicht vorausgesetzt.
|
||||
|
||||
### 3.2 Perimeter
|
||||
|
||||
Die Fritzbox 7530 bildet den Internet-Perimeter.
|
||||
|
||||
Aus dem Internet sollen grundsätzlich nur die für den öffentlichen Betrieb erforderlichen Weiterleitungen existieren:
|
||||
|
||||
- TCP 80 → Reverse Proxy LXC
|
||||
- TCP 443 → Reverse Proxy LXC
|
||||
- UDP auf dem festgelegten WireGuard-Port → WireGuard LXC
|
||||
- TCP 80 → Reverse Proxy LXC `10.0.0.10`
|
||||
- TCP 443 → Reverse Proxy LXC `10.0.0.10`
|
||||
- UDP 51820 → WireGuard LXC `10.0.0.15`
|
||||
|
||||
Managementdienste wie Proxmox Web UI oder SSH werden **nicht direkt aus dem Internet veröffentlicht**.
|
||||
|
||||
@@ -128,7 +158,7 @@ Der LLM-Server basiert auf der in **GNAI-001-INFRA** dokumentierten Debian-Basis
|
||||
|
||||
### 6.1 LLM-Inferenz
|
||||
|
||||
`llama.cpp` stellt die eigentliche lokale Modell-Inferenz bereit.
|
||||
`llama.cpp` soll die eigentliche lokale Modell-Inferenz bereitstellen.
|
||||
|
||||
Grundsatz:
|
||||
|
||||
@@ -138,7 +168,7 @@ Der Zugriff erfolgt intern über die dafür vorgesehene API-Schicht.
|
||||
|
||||
### 6.2 LiteLLM
|
||||
|
||||
LiteLLM bildet die standardisierte OpenAI-kompatible API- und Policy-Schicht vor `llama.cpp`.
|
||||
LiteLLM soll die standardisierte OpenAI-kompatible API- und Policy-Schicht vor `llama.cpp` bilden.
|
||||
|
||||
Verantwortlichkeiten:
|
||||
|
||||
@@ -151,17 +181,7 @@ Verantwortlichkeiten:
|
||||
|
||||
Zielpfad:
|
||||
|
||||
```text
|
||||
Internet Client
|
||||
↓ HTTPS
|
||||
NPM
|
||||
↓
|
||||
LiteLLM
|
||||
↓ internes Container-/Host-Netz
|
||||
llama.cpp
|
||||
↓
|
||||
GPU(s)
|
||||
```
|
||||
Im Zielbild verbindet sich ein externer Client per HTTPS mit NPM. NPM leitet an LiteLLM weiter; LiteLLM nutzt llama.cpp über das interne Container-/Hostnetz. Die Inferenz soll auf den GPUs laufen. Dieser Pfad ist auf dem frisch eingerichteten KI-Server noch nicht umgesetzt.
|
||||
|
||||
---
|
||||
|
||||
@@ -176,20 +196,17 @@ WireGuard ist die dedizierte Zugangsschicht für privilegierte Netzwerkzugriffe.
|
||||
- WireGuard-Peer-Authentifizierung ausschließlich über kryptografische Schlüssel
|
||||
- kein OIDC für die eigentliche WireGuard-Peer-Authentifizierung
|
||||
|
||||
### 7.2 Rollen
|
||||
### 7.2 Rollen und VPN-Betrieb
|
||||
|
||||
**Full Admin**
|
||||
| Rolle | Zielrechte |
|
||||
| --- | --- |
|
||||
| Familie (Brüder) | gesamtes Heimnetz einschließlich PCs/Clients; Serververwaltung nach Dienstanmeldung |
|
||||
| Server Admin | Proxmox, Service-LXCs und KI-Server; NPM und wg-easy eingeschlossen |
|
||||
| LLM Admin | ausschließlich KI-Server `10.0.0.90` |
|
||||
|
||||
- Proxmox Management
|
||||
- LLM-Server Management
|
||||
- weitere ausdrücklich freigegebene Managementziele
|
||||
Profile werden pro Gerät vom Administrator erstellt und verteilt. Benutzer benötigen für den Profilbezug keine GUI-Anmeldung. Serverseitige **Firewall Allowed IPs** in wg-easy sollen die Zielrechte durchsetzen; clientseitige **Allowed IPs** steuern Split-Tunneling. Per-Client Firewall ist aktuell deaktiviert, Rollenisolierung nicht abgenommen. Gateway-GUI/SSH benötigen zusätzlich passende INPUT-Regeln. Die alte Full-Admin-Bezeichnung wird nicht automatisch einer der neuen Rollen gleichgesetzt.
|
||||
|
||||
**LLM Admin**
|
||||
|
||||
- ausschließlich LLM-Server Management
|
||||
- insbesondere SSH und ggf. ausgewählte Managementschnittstellen
|
||||
|
||||
Die WireGuard-Konfiguration ist peer-basiert. `AllowedIPs` und zusätzliche Firewall-Regeln werden gemeinsam verwendet; ein VPN-Peer erhält nicht automatisch vollständigen Zugriff auf das LAN.
|
||||
Das Gateway nutzt MASQUERADE für VPN→LAN; die Fritzbox besitzt keine Rückroute zum VPN-Netz. LAN-Dienste sehen dadurch die Quelladresse des Gateways. Die serverseitige Peer-Zielkontrolle muss vor NAT greifen. Installation, Hooks und Abnahme stehen in GNAI-006.
|
||||
|
||||
---
|
||||
|
||||
@@ -199,17 +216,9 @@ Keycloak ist die zentrale Identitäts- und Authentifizierungsplattform für die
|
||||
|
||||
Vorgesehenes Modell:
|
||||
|
||||
```text
|
||||
Browser
|
||||
↓ HTTPS
|
||||
NPM
|
||||
↓
|
||||
Web Service
|
||||
↓ OIDC
|
||||
Keycloak
|
||||
```
|
||||
Der Browser erreicht den Webdienst über HTTPS und NPM. Der Webdienst bindet Keycloak für den OIDC-Anmeldeprozess ein; Anwendung und Identitätsquelle behalten getrennte Aufgaben.
|
||||
|
||||
Die Webservices nutzen OIDC zur Benutzeridentifikation und Authentifizierung.
|
||||
Webservices sollen OIDC nutzen, soweit die jeweilige Anwendung daran angebunden wird. Laut Betreiber ist derzeit nur Vaultwarden produktiv an Keycloak/OIDC angebunden.
|
||||
|
||||
Die Keycloak-Administrationsoberfläche und administrative Managementschnittstellen sollen nicht öffentlich zugänglich sein und werden über das Managementnetz bereitgestellt.
|
||||
|
||||
@@ -221,7 +230,7 @@ Die Keycloak-Administrationsoberfläche und administrative Managementschnittstel
|
||||
|
||||
SSH auf dem LLM-Server wird ausschließlich schlüsselbasiert betrieben.
|
||||
|
||||
Aus **GNAI-INFRA-002** übernimmt die Zielkonfiguration insbesondere:
|
||||
Aus **GNAI-002-INFRA** übernimmt die Zielkonfiguration insbesondere:
|
||||
|
||||
- `PermitRootLogin no`
|
||||
- `PasswordAuthentication no`
|
||||
@@ -245,9 +254,7 @@ Die Infrastruktur unterscheidet mindestens drei Vertrauensklassen:
|
||||
|
||||
Zugang über:
|
||||
|
||||
```text
|
||||
HTTPS → NPM
|
||||
```
|
||||
HTTPS über NPM.
|
||||
|
||||
Authentifizierung erfolgt je nach Anwendung über:
|
||||
|
||||
@@ -258,9 +265,7 @@ Authentifizierung erfolgt je nach Anwendung über:
|
||||
|
||||
Zugang über:
|
||||
|
||||
```text
|
||||
WireGuard → Zielsystem
|
||||
```
|
||||
WireGuard zum freigegebenen Zielsystem.
|
||||
|
||||
Zusätzliche Dienstauthentifizierung bleibt erhalten, z. B. SSH Public Keys oder Proxmox-Authentifizierung.
|
||||
|
||||
@@ -299,7 +304,7 @@ Die Zielarchitektur sieht folgende komplementäre Schutzschichten vor:
|
||||
|
||||
## 12. Nicht Teil dieser Spezifikation
|
||||
|
||||
Folgende Punkte sind Architekturentscheidungen vorbehalten und werden in Implementierungsdokumenten konkretisiert:
|
||||
Folgende konkrete Werte und Verfahren werden in den Fachdokumenten geführt. Einige sind bereits festgelegt, andere dort ausdrücklich als offen markiert:
|
||||
|
||||
- konkrete WireGuard-Subnetze und Peer-Adressen
|
||||
- konkrete Firewall-Regelsätze
|
||||
@@ -323,7 +328,7 @@ Die Architektur gilt als korrekt umgesetzt, wenn mindestens folgende Eigenschaft
|
||||
- `llama.cpp` ist nicht direkt aus dem Internet erreichbar.
|
||||
- Öffentliche Webservices terminieren an NPM.
|
||||
- Fail2Ban befindet sich zusammen mit NPM im Reverse-Proxy-LXC.
|
||||
- Full-Admin- und LLM-Admin-WireGuard-Peers besitzen unterschiedliche, restriktive Zugriffsprofile.
|
||||
- Familie-, Server-Admin- und LLM-Admin-Peers besitzen die beschlossenen, serverseitig durchgesetzten Zugriffsprofile.
|
||||
- Webanwendungen authentifizieren Benutzer über Keycloak/OIDC.
|
||||
- Die LLM-API wird über LiteLLM bereitgestellt und über API-Key geschützt.
|
||||
- Administrative Weboberflächen von Keycloak sind nicht öffentlich.
|
||||
@@ -331,8 +336,6 @@ Die Architektur gilt als korrekt umgesetzt, wenn mindestens folgende Eigenschaft
|
||||
|
||||
---
|
||||
|
||||
## 14. Änderungsverlauf
|
||||
## 14. Umsetzungsstand
|
||||
|
||||
| Datum | Version | Geändert von | Beschreibung |
|
||||
| --- | --- | --- | --- |
|
||||
| 2026-08-28 | 1.0 | spektr | Erstellung der Zielarchitektur |
|
||||
Die Architektur-Abnahmekriterien in Abschnitt 13 sind Sollkriterien und keine bestätigte Abnahme. Der aktuelle Projektstand und die priorisierten Befunde stehen im [Dokumentationsindex](GNAI-000-DOC_Index.md); technische Nachweise und offene Prüfungen werden in GNAI-005 und GNAI-006 geführt. Backendisolation und lokale Netzwerksegmentierung sind ebenfalls noch nachzuweisen.
|
||||
|
||||
@@ -2,9 +2,19 @@
|
||||
|
||||
**Dokumenten-ID:** GNAI-004-SEC
|
||||
**Titel:** Homelab / LLM-Infrastruktur – Sicherheits-, Authentifizierungs- und Zugriffskonzept
|
||||
**Version:** 1.0
|
||||
**Status:** Architekturentscheidung
|
||||
**Vorgänger / Referenzen:** GNAI-003-INFRA
|
||||
**Status:** Verbindliches Zielmodell; technische Durchsetzung teilweise offen
|
||||
**Vorgänger / Referenzen:** [Architektur](GNAI-003-INFRA_Architecture.md), [Gateway](GNAI-006-SEC_VPN.md), [GUI-SOP](GNAI-006-SEC_VPN_Client-Management.md), [Reverse Proxy](GNAI-005-SEC_Reverse-Proxy.md)
|
||||
|
||||
---
|
||||
|
||||
## Änderungsverlauf
|
||||
|
||||
| Datum | Version | Autor | Beschreibung |
|
||||
| --- | --- | --- | --- |
|
||||
| 2026-08-28 | 1.0 | spektr | Erstellung des Sicherheits- und Zugriffskonzepts. |
|
||||
| 2026-09-15 | 1.1 | spektr | Familie, Server Admin und LLM Admin getrennt; serverseitige Zielrechte, NAT und Umsetzungsdefizite dokumentiert; OIDC-Ist präzisiert. |
|
||||
| 2026-09-16 | 1.2 | spektr | Fail2Ban-Pin `1.1.0-r2-ls43` und wieder laufenden Container als Ist-Stand übernommen; technische Abnahme bleibt in GNAI-005 geführt. |
|
||||
| 2026-09-18 | 1.3 | spektr | KI-Anwendungsdienste als Zielbild und bestehende Fail2Ban-Jails als dokumentierten Ist-Stand eingeordnet. |
|
||||
|
||||
---
|
||||
|
||||
@@ -25,66 +35,27 @@ Ziel ist Least Privilege bei gleichzeitig überschaubarer Administration.
|
||||
|
||||
## 2. Rollenmodell
|
||||
|
||||
### 2.1 Full Admin
|
||||
### 2.1 Familie
|
||||
|
||||
Vollständiger privilegierter Infrastrukturzugriff.
|
||||
Familienmitglieder (Betreiber und Bruder) dürfen das gesamte Heimnetz `10.0.0.0/24` einschließlich gewöhnlicher PCs und Clients erreichen. Das ist eine bewusste Vollzugriffsentscheidung für die Netzwerkebene. Proxmox, SSH und andere Anwendungen behalten eigene Authentifizierung und Autorisierung. Zugriff auf wg-easy und NPM-Administration ist vorgesehen.
|
||||
|
||||
**Netzwerkzugang:**
|
||||
### 2.2 Server Admin
|
||||
|
||||
- WireGuard
|
||||
Server Admins dürfen Proxmox `10.0.0.2`, aktuelle Service-LXCs und KI-Server `10.0.0.90` erreichen. NPM und wg-easy zählen zu den Service-LXCs. Allgemeine Heimnetz-PCs/Clients gehören nicht zu dieser Freigabe. Serverseitig eine Liste bestätigter Hosts pflegen; der statische Adressbereich bis `.99` ist keine pauschale Zugriffsfreigabe.
|
||||
|
||||
**Erlaubte Zielbereiche:**
|
||||
### 2.3 LLM Admin
|
||||
|
||||
- Proxmox Management
|
||||
- LLM Server
|
||||
- weitere explizit freigegebene Managementsysteme
|
||||
LLM Admins dürfen ausschließlich KI-Server `10.0.0.90` erreichen. Proxmox, andere Service-LXCs, wg-easy/NPM und gewöhnliche Heimnetz-PCs sind gesperrt. Netzwerkzugriff auf den Host ersetzt keine SSH-/Anwendungsrechte. SSH bleibt schlüsselbasiert, ohne Passwort- oder Root-Login.
|
||||
|
||||
**Zusätzliche Authentifizierung:**
|
||||
Die drei Gruppen sind VPN-Netzwerkrollen. Alte Full-Admin-Peers müssen ausdrücklich Familie oder Server Admin zugeordnet werden. Jeder Peer gehört zu einem einzelnen Gerät und einer dokumentierten Rolle.
|
||||
|
||||
- Proxmox-eigene Authentifizierung und 2FA, sofern konfiguriert
|
||||
- SSH Public Keys für SSH
|
||||
- Anwendungsspezifische Credentials bei Web-UIs
|
||||
|
||||
WireGuard ersetzt die eigentliche Dienstauthentifizierung nicht.
|
||||
|
||||
---
|
||||
|
||||
### 2.2 LLM Admin
|
||||
|
||||
Administration des LLM-Servers ohne allgemeine Proxmox-/LAN-Administration.
|
||||
|
||||
**Netzwerkzugang:**
|
||||
|
||||
- WireGuard
|
||||
|
||||
**Erlaubte Zielbereiche:**
|
||||
|
||||
- LLM-Server
|
||||
- SSH
|
||||
- weitere ausdrücklich für den LLM-Betrieb freigegebene Managementschnittstellen
|
||||
|
||||
**Nicht erlaubt:**
|
||||
|
||||
- Proxmox Management
|
||||
- allgemeiner Zugriff auf andere Service-LXCs
|
||||
- allgemeiner Zugriff auf das LAN
|
||||
|
||||
**SSH:**
|
||||
|
||||
- Public-Key-Authentifizierung
|
||||
- kein Passwort-Login
|
||||
|
||||
---
|
||||
|
||||
### 2.3 LLM User
|
||||
### 2.4 LLM User (Anwendungsrolle)
|
||||
|
||||
Kein privilegierter Netzwerkzugang.
|
||||
|
||||
**Zugang:**
|
||||
|
||||
```text
|
||||
HTTPS → NPM → LiteLLM
|
||||
```
|
||||
HTTPS über NPM zur LiteLLM-API.
|
||||
|
||||
**Authentifizierung:**
|
||||
|
||||
@@ -109,20 +80,19 @@ Ein normaler LLM User erhält **keinen WireGuard-Peer**, sofern für einen konkr
|
||||
|
||||
## 3. Zugriffsmatrix
|
||||
|
||||
| Ziel | Full Admin | LLM Admin | LLM User | Öffentlich |
|
||||
| Ziel | Familie | Server Admin | LLM Admin | LLM User / öffentlich |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| Proxmox Web UI | ✅ WireGuard | ❌ | ❌ | ❌ |
|
||||
| Proxmox SSH | ✅ WireGuard + SSH-Key | ❌ | ❌ | ❌ |
|
||||
| LLM Server SSH | ✅ WireGuard + SSH-Key | ✅ WireGuard + SSH-Key | ❌ | ❌ |
|
||||
| `llama.cpp` direkt | intern/admin nach Bedarf | intern/admin nach Bedarf | ❌ | ❌ |
|
||||
| LiteLLM API | ✅ | ✅ | ✅ HTTPS + API-Key | ✅ HTTPS |
|
||||
| OpenWebUI | ✅ | ✅ optional | ✅ HTTPS + OIDC | ✅ HTTPS |
|
||||
| Nextcloud | ✅ | ✅ optional | ✅ HTTPS + OIDC | ✅ HTTPS |
|
||||
| Gitea | ✅ | ✅ optional | ✅ HTTPS + OIDC | ✅ HTTPS |
|
||||
| Keycloak OIDC-Endpunkte | ✅ | ✅ | ✅ für Login | ✅ nur erforderliche Endpunkte |
|
||||
| Keycloak Admin | ✅ WireGuard | ❌ | ❌ | ❌ |
|
||||
| NPM Admin | ✅ WireGuard | ❌ | ❌ | ❌ |
|
||||
| Fail2Ban Management | ✅ intern/admin | ggf. LLM-intern falls separat erforderlich | ❌ | ❌ |
|
||||
| Heimnetz-PCs / DHCP-Clients | erlaubt | gesperrt | gesperrt | gesperrt |
|
||||
| Proxmox UI/SSH | erlaubt + Dienstauthentifizierung | erlaubt + Dienstauthentifizierung | gesperrt | gesperrt |
|
||||
| Service-LXCs / NPM / wg-easy | erlaubt + Dienstauthentifizierung | erlaubt + Dienstauthentifizierung | gesperrt | nur veröffentlichte Anwendungen |
|
||||
| KI-Server SSH/Management | erlaubt + Dienstauthentifizierung | erlaubt + Dienstauthentifizierung | erlaubt + Dienstauthentifizierung | gesperrt |
|
||||
| Keycloak Administration | intern, nach Dienstberechtigung | intern, nach Dienstberechtigung | gesperrt | Soll: gesperrt; Ist: öffentlich erreichbar |
|
||||
| benötigte OIDC-Endpunkte | anwendungsbezogen | anwendungsbezogen | anwendungsbezogen | öffentlich für Login |
|
||||
| LiteLLM API | nach API-Policy | nach API-Policy | nach API-Policy | Soll: HTTPS + individueller API-Key |
|
||||
| OpenWebUI / weitere Webanwendungen | nach Anwendungsrechten | nach Anwendungsrechten | nach Anwendungsrechten | Soll: HTTPS und geeignete Anmeldung |
|
||||
| llama.cpp / Datenbanken | nur nach Backend-/Dienstpolicy | nur nach Backend-/Dienstpolicy | nur KI-Server-bezogen nach Bedarf | nicht direkt öffentlich |
|
||||
|
||||
Das ist die Sollmatrix. Per-Client Firewall ist aktuell deaktiviert; Keycloak-Admin-Exposure ist durch einen externen Betreiber-Test bestätigt. Keine Sollfreigabe wird damit als bereits sicher implementiert behauptet.
|
||||
|
||||
---
|
||||
|
||||
@@ -149,15 +119,9 @@ Keycloak ist die zentrale Identitätsquelle für webbasierte Benutzeranwendungen
|
||||
|
||||
Ziel:
|
||||
|
||||
```text
|
||||
Benutzer
|
||||
↓
|
||||
Keycloak
|
||||
↓ OIDC
|
||||
Nextcloud / Gitea / OpenWebUI / weitere Services
|
||||
```
|
||||
Benutzer melden sich an der zentralen Keycloak-Identitätsquelle an. Die vorgesehenen Anwendungen binden diese per OIDC ein.
|
||||
|
||||
Administrative Keycloak-Funktionen bleiben auf das Managementnetz beschränkt.
|
||||
Administrative Keycloak-Funktionen müssen auf interne berechtigte Zugriffe beschränkt werden. Ist: externe Admin-Anmeldung möglich, Korrektur in GNAI-005 dokumentiert. Laut Betreiber wird OIDC produktiv nur für Vaultwarden genutzt; Nextcloud, Gitea, OpenWebUI und weitere Dienste sind geplant.
|
||||
|
||||
---
|
||||
|
||||
@@ -167,15 +131,7 @@ Die LLM-API ist ein anwendungsbezogener Dienst und wird deshalb nicht durch eine
|
||||
|
||||
Ziel:
|
||||
|
||||
```text
|
||||
Client
|
||||
↓ HTTPS
|
||||
NPM
|
||||
↓
|
||||
LiteLLM
|
||||
↓
|
||||
llama.cpp
|
||||
```
|
||||
Der Client erreicht LiteLLM per HTTPS über NPM; LiteLLM nutzt intern llama.cpp.
|
||||
|
||||
Die Autorisierung erfolgt über API-Keys.
|
||||
|
||||
@@ -194,11 +150,7 @@ SSH wird auf dem LLM-Server schlüsselbasiert betrieben.
|
||||
|
||||
Zusätzliche Schutzschicht:
|
||||
|
||||
```text
|
||||
WireGuard
|
||||
+
|
||||
SSH Public Key
|
||||
```
|
||||
WireGuard-Zielberechtigung und eigener SSH-Public-Key-Login.
|
||||
|
||||
Passwort- und Root-Login über SSH bleiben deaktiviert.
|
||||
|
||||
@@ -206,29 +158,17 @@ Passwort- und Root-Login über SSH bleiben deaktiviert.
|
||||
|
||||
## 5. Netzwerk-Autorisierung
|
||||
|
||||
WireGuard-Peers werden nicht pauschal für das gesamte LAN freigeschaltet.
|
||||
Familie erhält ausdrücklich Heimnetz-Vollzugriff. Server Admins und LLM Admins erhalten nur die beschlossenen Zielhosts. Die **serverseitigen Firewall Allowed IPs** in wg-easy sollen diese Rechte durchsetzen, während clientseitige Allowed IPs nur Routing festlegen. Ein Benutzer darf die Serverbeschränkung nicht durch Änderungen an seinem lokalen Profil umgehen können. Für Gateway-eigene Dienste wird die INPUT-Chain separat geprüft und anhand zugeordneter VPN-Quellen begrenzt.
|
||||
|
||||
Zugriff ist mindestens nach folgendem Muster zu definieren:
|
||||
Aktuell fehlt die Per-Client-Durchsetzung. Negative Tests müssen mit absichtlich erweitertem Client-Routing und aktivem Zielservice stattfinden. Normale LLM-Anwendungsnutzer erhalten keinen Managementpeer. Geräteprofile werden durch Administratoren erstellt und geschützt verteilt. Die GUI ist für Familie und Server Admins vorgesehen.
|
||||
|
||||
```text
|
||||
Full Admin
|
||||
→ Proxmox
|
||||
→ LLM Server
|
||||
→ explizit freigegebene Managementziele
|
||||
|
||||
LLM Admin
|
||||
→ LLM Server
|
||||
→ explizit freigegebene Managementziele
|
||||
|
||||
LLM User
|
||||
→ kein Management-VPN
|
||||
```
|
||||
|
||||
`AllowedIPs` und Firewall-Regeln bilden gemeinsam die technische Durchsetzung.
|
||||
MASQUERADE wird mangels Rückroute verwendet; es verbirgt gegenüber LAN-Diensten die ursprüngliche Peer-IP. Zielkontrolle muss daher am VPN-Gateway vor NAT erfolgen. Lokale LAN-Quellen lassen sich nicht allein durch die VPN-Rolle gruppengenau zuordnen; hierfür sind zusätzliche Regeln/Identitäten nötig.
|
||||
|
||||
---
|
||||
|
||||
## 6. Public vs. Private Exposure
|
||||
## 6. Vorgesehene öffentliche und private Erreichbarkeit
|
||||
|
||||
Die folgende Einordnung ist das Zielmodell. LiteLLM und die Webanwendungen auf dem KI-Server werden erst im späteren Ansible-Sprint eingerichtet.
|
||||
|
||||
### Öffentlich
|
||||
|
||||
@@ -268,7 +208,7 @@ Nicht vorgesehen ist ein pauschales Blocking aller HTTP-Fehlercodes.
|
||||
|
||||
Insbesondere soll ein allgemeiner `404` nicht automatisch als Angriff gewertet werden.
|
||||
|
||||
Die finalen Jails werden serviceorientiert entworfen und getrennt validiert.
|
||||
Die vorhandenen NPM-Jails sind in [GNAI-005](GNAI-005-SEC_Reverse-Proxy.md) dokumentiert. Ihre Funktion nach dem Image-Pin sowie Neustart und Wiederanlauf müssen noch abgenommen werden.
|
||||
|
||||
---
|
||||
|
||||
@@ -343,47 +283,18 @@ Die Zielarchitektur soll sicherstellen, dass ein kompromittierter Bestandteil m
|
||||
|
||||
Beispiele:
|
||||
|
||||
```text
|
||||
Kompromittiertes Webkonto
|
||||
≠ Proxmox-Zugriff
|
||||
|
||||
Gestohlener LLM-API-Key
|
||||
≠ SSH-Zugriff
|
||||
|
||||
Kompromittierter LLM-Container
|
||||
≠ WireGuard-Admin
|
||||
|
||||
LLM-Admin-WireGuard-Peer
|
||||
≠ Proxmox-Admin
|
||||
|
||||
Öffentlicher NPM-Dienst
|
||||
≠ direkter Zugriff auf interne Backendports
|
||||
```
|
||||
| Ereignis / Berechtigung | darf keinen automatischen Zugriff geben auf |
|
||||
| --- | --- |
|
||||
| kompromittiertes Webkonto | Proxmox |
|
||||
| gestohlener API-Key | SSH |
|
||||
| kompromittierter LLM-Container | WireGuard-Administration |
|
||||
| LLM-Admin-Peer | Proxmox-Netzwerkzugang |
|
||||
| öffentliche NPM-Verbindung | direkte interne Backendports |
|
||||
|
||||
Das Sicherheitsmodell basiert damit nicht auf einem einzelnen „Security-Programm“, sondern auf der Kombination mehrerer voneinander unabhängiger Kontrollen.
|
||||
|
||||
---
|
||||
|
||||
## 11. Offene Implementierungsdetails
|
||||
## 11. Umsetzungsnachweise
|
||||
|
||||
Die folgenden Punkte werden erst in den jeweiligen Umsetzungs-SOPs festgelegt:
|
||||
|
||||
- WireGuard-VPN-Adressraum
|
||||
- Peer-IP-Zuweisungen
|
||||
- Firewall-Regeln für Full Admin / LLM Admin
|
||||
- konkrete `wg-easy`-Containerkonfiguration
|
||||
- NPM- und Fail2Ban-Netzwerke
|
||||
- konkrete Fail2Ban-Filter/Jails
|
||||
- LiteLLM-Key-/Quota-Modell
|
||||
- Keycloak-Realm-/Client-/Role-Struktur
|
||||
- DNS-Namen
|
||||
- IPv6-Regelsatz
|
||||
- Logging-/Alerting-Strategie
|
||||
|
||||
---
|
||||
|
||||
## 12. Änderungsverlauf
|
||||
|
||||
| Datum | Version | Geändert von | Beschreibung |
|
||||
| --- | --- | --- | --- |
|
||||
| 2026-08-28 | 1.0 | spektr | Erstellung des Sicherheits- und Zugriffskonzepts. |
|
||||
Dieses Dokument definiert die Zugriffsziele. Der [Dokumentationsindex](GNAI-000-DOC_Index.md) bündelt den aktuellen Projektstand. Konkrete Gateway-Regeln und Rollentests stehen in [GNAI-006](GNAI-006-SEC_VPN.md), der Keycloak-Adminpfad und Fail2Ban in [GNAI-005](GNAI-005-SEC_Reverse-Proxy.md). Offene Zielrechte gelten bis zu ihrer technischen Abnahme nicht als durchgesetzt.
|
||||
|
||||
@@ -1,41 +1,54 @@
|
||||
# Technical Architecture Specification
|
||||
# Betriebs- und Sicherheitsdokumentation – Reverse Proxy
|
||||
|
||||
**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
|
||||
**Dokumenten-ID:** GNAI-005-SEC
|
||||
**Titel:** Reverse Proxy und Fail2Ban – Konfiguration, Betrieb und Sicherheitsabnahme
|
||||
**Status:** NPM aktiv; Fail2Ban laut Betreiber fest gepinnt und wieder in Betrieb; Keycloak-Admin-Exposure bestätigt, Korrektur offen
|
||||
**Vorgänger / Referenzen:** [Architektur](GNAI-003-INFRA_Architecture.md), [Zugriffskonzept](GNAI-004-SEC_Access-Control.md), [WireGuard](GNAI-006-SEC_VPN.md)
|
||||
|
||||
---
|
||||
|
||||
## Änderungsverlauf
|
||||
|
||||
| Datum | Version | Autor | 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. |
|
||||
| 2026-09-14 | 1.1 | spektr | Proxmox-Host-Version auf PVE 9.2.11 aktualisiert (Host-Update). |
|
||||
| 2026-09-15 | 1.2 | spektr | Version/Tabellen korrigiert; bestätigte Keycloak-Exposure und TLS-Widerspruch dokumentiert; Korrekturverfahren, Fail2Ban-Upgrade/Pin und bewusste HTTP-Client-Sperren ergänzt. |
|
||||
| 2026-09-16 | 1.3 | spektr | Fail2Ban-Image auf `1.1.0-r2-ls43` fest gepinnt; wieder laufenden Container bestätigt; verbleibende Funktions- und Wiederanlauftests getrennt ausgewiesen. |
|
||||
| 2026-09-18 | 1.4 | spektr | Wirkung der LAN-Freigaben auf VPN-Verkehr hinter MASQUERADE unmittelbar an der Port-Matrix erläutert. Zweck als Betriebs- und Sicherheitsdokumentation geklärt; veraltete Image-Digests aus dem Verfahren entfernt. |
|
||||
|
||||
---
|
||||
|
||||
## 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`).
|
||||
Dieses Dokument hält Konfiguration, Betrieb und Sicherheitsabnahme des zentralen Reverse Proxy und des logbasierten Fail2Ban auf Proxmox LXC 103 (`reverse-proxy`) fest. Angaben zum laufenden Zustand beruhen auf den jeweils datierten Betreiberbestätigungen und Tests; eine neue Live-Prüfung von CT 103 fand bei dieser Revision nicht statt.
|
||||
|
||||
**Umfang dieses Dokuments:**
|
||||
|
||||
* Betrieb von Nginx Proxy Manager (NPM) als zentraler Ingress-Controller
|
||||
* Containerisiertes Fail2Ban als IPS mit nftables-Integration auf dem LXC
|
||||
* Containerisiertes Fail2Ban für logbasierte temporäre Sperren mit nftables-Integration auf dem LXC; kein allgemeines Netzwerk-IPS
|
||||
* Log-Parsing-Regeln und Filterdefinitionen für das NPM-spezifische Access-Log-Format
|
||||
* Gehärtete Firewall-Baseline und Zugriffssteuerung
|
||||
|
||||
---
|
||||
|
||||
## 2. System- Baseline (LXC 103)
|
||||
## 2. System-Baseline (LXC 103)
|
||||
|
||||
| Parameter | Wert |
|
||||
| --- | --- |
|
||||
| Container-ID | CT 103 |
|
||||
| Hostname | `reverse-proxy`<br> |
|
||||
| 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`<br> |
|
||||
| LXC Features | `nesting=1`, `keyctl=1`<br> |
|
||||
| Proxmox Host | Proxmox VE 8.4.21 (Kernel `6.8.12-23-pve`) |
|
||||
| Netzwerkkonfiguration | `10.0.0.10/24`, Gateway `10.0.0.1`, Bridge `vmbr0` |
|
||||
| LXC Features | `nesting=1`, `keyctl=1` |
|
||||
| Proxmox Host | Proxmox VE 9.2.11 |
|
||||
|
||||
*Hinweis zur Proxmox-Firewall:* Proxmox Cluster- und Node-Firewalls sind deaktiviert (`enable 0`). Die Paketfilterung erfolgt exklusiv lokal über `nftables` innerhalb des LXC.
|
||||
*Hinweis zur Proxmox-Firewall:* Laut bisheriger Implementierungsdokumentation sind Proxmox Cluster- und Node-Firewalls deaktiviert (`enable 0`); bei Änderungen den tatsächlichen Zustand prüfen. Die dokumentierte Filter-Baseline liegt lokal im LXC unter `nftables`. Effektive Regeln und weitere Netfilter-Tabellen vor Änderungen live prüfen.
|
||||
|
||||
---
|
||||
|
||||
@@ -75,6 +88,8 @@ table inet filter {
|
||||
| 22 | TCP | OpenSSH Management | Nur LAN (`10.0.0.0/24`) |
|
||||
| 3000 | TCP | NPM Node.js Backend | Intern / Nicht exponiert |
|
||||
|
||||
`10.0.0.0/24` in den Freigaben für 22/81 umfasst auch die Gateway-Adresse `10.0.0.15`. Durch das aktuelle VPN-MASQUERADE erscheinen VPN-Clients bei NPM unter dieser Adresse. Die Port-Matrix beschreibt deshalb **keine** bereits wirksame VPN-Rollentrennung; diese muss am Gateway vor NAT umgesetzt und getestet werden.
|
||||
|
||||
---
|
||||
|
||||
## 4. Container-Infrastruktur (Podman Quadlets)
|
||||
@@ -112,7 +127,7 @@ WantedBy=multi-user.target
|
||||
### 4.2 Fail2Ban IPS Quadlet
|
||||
|
||||
* **Datei:** `/etc/containers/systemd/fail2ban.container`
|
||||
* **Image:** `lscr.io/linuxserver/fail2ban:latest`
|
||||
* **Image, aktueller Ist-Stand:** `lscr.io/linuxserver/fail2ban:1.1.0-r2-ls43` *(fest gepinnt)*. Der Betreiber bestätigt, dass der Container nach der Umstellung wieder läuft. Der Image-Build enthält Fail2Ban 1.1.0; der Build-Suffix `r2-ls43` bezeichnet den LinuxServer-Image-Stand.
|
||||
* **Capabilities:** `NET_ADMIN`, `NET_RAW` *(kein `--privileged`)*
|
||||
|
||||
```ini
|
||||
@@ -122,7 +137,7 @@ Wants=network-online.target
|
||||
After=network-online.target
|
||||
|
||||
[Container]
|
||||
Image=lscr.io/linuxserver/fail2ban:latest
|
||||
Image=lscr.io/linuxserver/fail2ban:1.1.0-r2-ls43
|
||||
ContainerName=fail2ban
|
||||
Network=host
|
||||
AddCapability=NET_ADMIN
|
||||
@@ -233,7 +248,7 @@ Blockade bekannter Angriffs-Scanner und Reconnaissance-Tools.
|
||||
|
||||
## 7. Aktive Proxy Hosts
|
||||
|
||||
Aktuell im Nginx Proxy Manager konfigurierte und aktive Routen:
|
||||
Routen aus dem bisherigen Quelleninventar; Keycloak-Backend vom Betreiber erneut bestätigt. Bei Freigaben den tatsächlichen Bestand prüfen. Diese Tabelle beweist weder TLS-Konfiguration noch OIDC-Anbindung jeder Anwendung:
|
||||
|
||||
| ID | Hostname | Backend-Ziel | Dienst |
|
||||
| --- | --- | --- | --- |
|
||||
@@ -248,6 +263,8 @@ Aktuell im Nginx Proxy Manager konfigurierte und aktive Routen:
|
||||
|
||||
## 8. Betriebs- & Diagnosekommandos
|
||||
|
||||
Die folgenden Befehle auf CT 103 als root ausführen oder mit sudo ergänzen. Platzhalterwerte vor Verwendung ersetzen.
|
||||
|
||||
### Fail2Ban-Status
|
||||
|
||||
```bash
|
||||
@@ -276,11 +293,14 @@ nft list ruleset | grep -A 10 "table inet f2b-table"
|
||||
### Manuelle Sperre / Freigabe
|
||||
|
||||
```bash
|
||||
# Gewählte IP eintragen, Platzhalter nicht unverändert verwenden.
|
||||
BAN_IP="<ZU-SPERRENDE-IP>"
|
||||
|
||||
# IP manuell sperren
|
||||
podman exec fail2ban fail2ban-client set npm-scanner banip <IP>
|
||||
podman exec fail2ban fail2ban-client set npm-scanner banip "$BAN_IP"
|
||||
|
||||
# IP manuell freigeben
|
||||
podman exec fail2ban fail2ban-client set npm-scanner unbanip <IP>
|
||||
podman exec fail2ban fail2ban-client set npm-scanner unbanip "$BAN_IP"
|
||||
```
|
||||
|
||||
---
|
||||
@@ -288,7 +308,7 @@ 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.
|
||||
2. **Geprüfte Upgrades:** NPM ist im Quellenstand auf `2.11.1` festgeschrieben. Fail2Ban ist auf `1.1.0-r2-ls43` festgeschrieben. Beide Pins regelmäßig auf Updates prüfen; Änderungen mit Backup, Tests und Rückfallplan durchführen.
|
||||
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.
|
||||
@@ -297,18 +317,106 @@ podman exec fail2ban fail2ban-client set npm-scanner unbanip <IP>
|
||||
|
||||
## 10. Backup & Disaster Recovery
|
||||
|
||||
Es existiert ein vollständiges Proxmox LXC Snapshot-Backup von CT 103:
|
||||
Im bisherigen Quellenstand ist ein Proxmox-vzdump-Backup von CT 103 dokumentiert:
|
||||
|
||||
* **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.
|
||||
Vor strukturellen Änderungen an nftables, Proxy-Konfiguration oder Quadlets ein aktuelles konsistentes Proxmox-Backup erstellen. Ein Snapshot kann ergänzen, ersetzt aber kein unabhängiges Backup. Der genannte Archivpfad ist historischer Quellenstand, kein Nachweis eines aktuellen oder getesteten Backups.
|
||||
|
||||
---
|
||||
|
||||
## 11. Änderungsverlauf
|
||||
## 11. Keycloak: bestätigte öffentliche Administration und Korrekturverfahren
|
||||
|
||||
| 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. |
|
||||
### 11.1 Bestätigter Ist-Stand
|
||||
|
||||
Der Betreiber konnte **von extern** `https://auth.ghostnet.selfhost.eu/admin` öffnen und sich anmelden. Das widerspricht GNAI-004. Die Korrektur wurde bei dieser Dokumentationsrevision noch nicht auf dem System durchgeführt.
|
||||
|
||||
| NPM-Einstellung | Betreiberangabe |
|
||||
| --- | --- |
|
||||
| Domain | `auth.ghostnet.selfhost.eu` |
|
||||
| Backend | HTTP, `10.0.0.4:8080` |
|
||||
| Access List | Publicly Accessible; keine Listen definiert |
|
||||
| Custom Locations | keine |
|
||||
| Optionen | Cache Assets, Block Common Exploits, Websocket Support |
|
||||
| SSL-Einstellungen | alle aus |
|
||||
|
||||
Custom Config enthält aktuell:
|
||||
|
||||
```nginx
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Host $host;
|
||||
```
|
||||
|
||||
**TLS-Widerspruch:** Externer HTTPS-Login funktionierte, obwohl für diesen Proxy Host SSL als ausgeschaltet angegeben ist. Effektiven Listener, Zertifikat und vHost-Zuordnung prüfen, bevor eine vollständige HTTPS-Bereitstellung behauptet wird. Auf CT 103 etwa:
|
||||
|
||||
```bash
|
||||
sudo podman exec nginx-proxy-manager nginx -t
|
||||
sudo ss -lntp
|
||||
sudo grep -REn 'auth\.ghostnet\.selfhost\.eu|listen|ssl_certificate|location|allow|deny' \
|
||||
/opt/nginx-proxy-manager/data/nginx/proxy_host/
|
||||
```
|
||||
|
||||
Generierte Dateien nur lesen, nicht direkt ändern; NPM würde Änderungen überschreiben. `Block Common Exploits` ersetzt keine Administrative-Pfadbeschränkung. Die vorhandenen X-Forwarded-Header ebenfalls in der effektiven Nginx-Konfiguration prüfen. Unvertrauenswürdige Client-Header dürfen nicht zur Quelle einer Managementfreigabe werden.
|
||||
|
||||
### 11.2 Sofortschutz für den öffentlichen Adminpfad
|
||||
|
||||
1. Aktuelle Proxy-Einstellungen sichern. Über Proxmox-Konsole Zugriff auf Keycloak behalten und einen funktionierenden internen Administrationsweg prüfen; mögliche Redirects auf den öffentlichen Namen beachten.
|
||||
2. Im NPM den Proxy Host **auth.ghostnet.selfhost.eu → Advanced** öffnen. Im server-Kontext zusätzlich folgenden Schutz ergänzen, ohne bestehende Konfiguration blind zu ersetzen:
|
||||
|
||||
```nginx
|
||||
location ~* ^/admin(?:/|$) {
|
||||
deny all;
|
||||
}
|
||||
```
|
||||
|
||||
Der Schutz sperrt `/admin`, `/admin/` und darunterliegende Admin-API-/GUI-Pfade auf diesem Proxy Host für alle Quellen, auch LAN. Das ist ein vorläufiger Schutz des öffentlichen Hosts; der dauerhafte interne Adminzugang wird separat eingerichtet. Bestehende Regex-Locations und `^~`-Locations auf Prioritätskonflikte prüfen.
|
||||
3. Speichern. NPM-Status und `nginx -t` prüfen. Die aktive Konfiguration kontrollieren, damit der Block sowohl für HTTP als auch für den tatsächlich verwendeten HTTPS-Listener greift. Keine Wirkung nur aufgrund eines gespeicherten Textfelds annehmen.
|
||||
4. Aus einem fremden Netz mit deaktiviertem VPN `/admin`, `/admin/` und `/admin/master/console/` prüfen; Erwartung **403**, keine nutzbare Administration. IPv4 und vorhandenes IPv6 separat prüfen. Kontrollierte Admin-API-Zugriffe müssen ebenfalls gesperrt sein. HTTP darf nicht weiterhin Zugriff erlauben.
|
||||
5. Vaultwarden-Login einschließlich tatsächlichem Keycloak-Redirect und Tokenaustausch prüfen. Bei Änderungen nicht den gesamten auth-Host hinter eine Access List setzen, da öffentliches OIDC weiter benötigt wird.
|
||||
|
||||
Auf der Admin-Oberfläche können schematisch Redirects vorkommen; für Prüfungen HTTP-Status **und Redirectziel** festhalten. Ein 302 auf eine Admin-Anmeldung ist keine erfolgreiche Sperre. Der öffentliche Adminpfad wird erst nach externem Gegencheck als korrigiert geführt.
|
||||
|
||||
### 11.3 Dauerhafte Trennung
|
||||
|
||||
Einen internen Admin-Proxy Host mit separat bestätigtem Hostnamen, Zertifikat und interner Namensauflösung planen. Netzwerkzugang nur für Familie und Server Admins erlauben, am Gateway vor NAT durchsetzen und direkte Backend-Erreichbarkeit berücksichtigen. Bei Keycloak `hostname-admin`/Frontend-Hostname passend zur **installierten Version** konfigurieren. Ein Adminhostname allein schützt die Admin-REST-API auf dem öffentlichen Frontend nicht; öffentliche Pfade weiterhin sperren. [Hostname-Konfiguration](https://www.keycloak.org/server/hostname)
|
||||
|
||||
Auch den tatsächlichen Administrationsrealm erfassen. Falls das `master` ist, `/realms/master/` ebenfalls ausschließlich intern bereitstellen. Zuerst Vaultwardens produktiven OIDC-Issuer prüfen, damit ein pauschaler Realm-Block dessen Anmeldung nicht unbemerkt unterbricht. Public benötigt geeignete Anwendungsrealm-Endpunkte und Ressourcen. Health/Metrics/Managementport nicht veröffentlichen. [Keycloak-Proxy-Pfade](https://www.keycloak.org/server/reverseproxy)
|
||||
|
||||
Aktuell bestätigt ist nur Vaultwarden-OIDC. Zusätzliche Dienste sind geplant. Die tatsächliche lokale Realm-/Client-Struktur und der interne Adminhostname bleiben offen.
|
||||
|
||||
## 12. Fail2Ban: fester Image-Pin und verbleibende Abnahme
|
||||
|
||||
Der Betreiber bestätigt am 16.09.2026 die Umstellung auf:
|
||||
|
||||
```ini
|
||||
Image=lscr.io/linuxserver/fail2ban:1.1.0-r2-ls43
|
||||
```
|
||||
|
||||
Der Fail2Ban-Container läuft nach der Umstellung wieder. Damit ist die frühere Abweichung durch den beweglichen Tag `latest` behoben. Der Tag bezeichnet den LinuxServer-Container-Build; die darin enthaltene Anwendung meldet Fail2Ban v1.1.0. Das ist nicht mit einem Upstream-Upgrade auf Fail2Ban 1.1.1 gleichzusetzen.
|
||||
|
||||
Für die technische Abnahme sind noch Nachweise zu erfassen; aus „läuft wieder“ werden keine weitergehenden Testergebnisse abgeleitet:
|
||||
|
||||
1. Effektiven Image-Namen und Anwendungsversion prüfen: `podman inspect fail2ban --format '{{.ImageName}}'` sowie `podman exec fail2ban fail2ban-client --version`.
|
||||
2. Konfiguration und Jails prüfen: `podman exec fail2ban fail2ban-client -t`, `fail2ban-client status` und Status der NPM-Jails.
|
||||
3. Kontrollierte HTTP-/HTTPS-Treffer bis zum Ban auslösen, Eintrag im nftables-Regelsatz verifizieren und Test-IP anschließend wieder freigeben.
|
||||
4. Dienstneustart und später LXC-/Host-Neustart prüfen; danach Containerstatus, Jails und Filter erneut kontrollieren.
|
||||
5. Laufenden Image-Digest und ein aktuelles konsistentes Backup als Rückfallstand festhalten. Ein Digest-Pin kann nach Manifest-/Architekturprüfung den Tag-Pin zusätzlich härten.
|
||||
|
||||
Upstream-Anwendung und Container-Build bleiben getrennte Versionsachsen. Vor einem späteren Upgrade sind LinuxServer-Release, enthaltene Fail2Ban-Version, Architektur und lokale Filter/Jails erneut zu prüfen. [Fail2Ban-Releases](https://github.com/fail2ban/fail2ban/releases), [LinuxServer-Images](https://docs.linuxserver.io/images/docker-fail2ban/)
|
||||
|
||||
## 13. Bewusste Betriebsentscheidung: generische HTTP-Clients bleiben gesperrt
|
||||
|
||||
**Entscheidung des Betreibers:** `python-requests` und `go-http-client` verbleiben im npm-badbots-Filter. Legitimer automatisierter Verkehr kann dadurch nach dem konfigurierten Schwellwert ebenfalls einen Ban auslösen. User-Agent ist keine starke Authentifizierung; er kann geändert werden. Dieser Filter ist eine zusätzliche Heuristik, keine vollständige Abuse-Erkennung.
|
||||
|
||||
Bei Bedarf darf ein berechtigter Nutzer einen erlaubten Dienst über WireGuard verwenden. Voraussetzung sind passende Rollenrechte, Routing und ein tatsächlich interner Zielpfad; nur das Aktivieren des VPN umgeht eine öffentliche Route nicht automatisch. Mit dem bestehenden MASQUERADE sieht NPM VPN→LAN-Verkehr typischerweise von `10.0.0.15`, das im LAN-ignoreip liegt. Ein öffentlicher Hostname kann weiterhin zur WAN-IP auflösen und direkt benutzt werden; DNS-/Zielpfad und NPM-Quelladresse im Log prüfen.
|
||||
|
||||
LLM Admins dürfen nur `.90` erreichen und haben keinen allgemeinen NPM-/LXC-Zugriff. API-Clients ohne passende VPN-Rolle bekommen durch diese Ausweichoption keine zusätzlichen Rechte. Bei Supportfällen diese bewusste Ban-Entscheidung ausdrücklich mitprüfen.
|
||||
|
||||
## 14. Noch offene Abnahme
|
||||
|
||||
| Befund | Abschlussnachweis |
|
||||
| --- | --- |
|
||||
| Keycloak Admin extern nutzbar | externe Sperre von GUI und API über tatsächliche HTTP/HTTPS-/IPv6-Pfade, interner Adminzugang und Vaultwarden-OIDC weiter funktionsfähig |
|
||||
| TLS-Zuordnung des auth-Hosts unklar | effektiver Listener, Zertifikat, Redirects und Backend-Pfad dokumentiert |
|
||||
| Fail2Ban auf `1.1.0-r2-ls43` gepinnt und Container wieder laufend | effektives Image und Version dokumentiert; Jail-/Filter-/Ban-/Dienstneustart-/Reboottests bestanden |
|
||||
|
||||
+225
-187
@@ -1,87 +1,121 @@
|
||||
# Standard Operating Procedure & Technical Architecture Specification
|
||||
# Technische Architekturbeschreibung – WireGuard-Gateway
|
||||
|
||||
**Dokumenten-ID:** GNAI-006-SEC
|
||||
**Dokumenten-ID:** GNAI-006-SEC
|
||||
**Status:** Dokumentation bereinigt; technische Umsetzung und Abnahme teilweise offen
|
||||
**Referenzen:** [Zielarchitektur](GNAI-003-INFRA_Architecture.md), [Zugriffskonzept](GNAI-004-SEC_Access-Control.md), [GUI-SOP](GNAI-006-SEC_VPN_Client-Management.md), [Implementation-Log](GNAI-006-SEC_VPN_Implementation-Log.md)
|
||||
|
||||
**Titel:** Homelab / Infrastructure – WireGuard VPN Gateway (LXC) Setup & Access Control
|
||||
|
||||
**Version:** 1.4
|
||||
## Änderungsverlauf
|
||||
|
||||
**Status:** In Umsetzung (Schritt 1–7 fertig, Step 5/6 ✅ User, Step 8/9 offen)
|
||||
| Datum | Version | Autor | Änderung |
|
||||
| --- | --- | --- | --- |
|
||||
| 2026-09-09 | 1.0–1.5 | spektr | Aufbau und Migration von v14 auf v15; historische Details im Implementation-Log |
|
||||
| 2026-09-15 | 2.0 | spektr | Rollen Familie/Server Admin/LLM Admin; bestätigtes LXC und Hooks; NAT-Abhängigkeit; v15-Bereinigung; getrennte SOPs und belastbarer Abnahmestatus |
|
||||
| 2026-09-18 | 2.1 | spektr | Lesenden Gateway-Abgleich, iptables-legacy-Befund und DNS-Abgleich ergänzt; Betriebshinweise entsprechend korrigiert. |
|
||||
|
||||
**Vorgänger / Referenzen:** GNAI-003-INFRA, GNAI-004-SEC
|
||||
## 1. Zweck und dokumentierter Stand
|
||||
|
||||
**Client-Dokus (Benutzeranleitung):**
|
||||
* [GNAI-006-SEC_VPN_Clients_Linux.md](GNAI-006-SEC_VPN_Clients_Linux.md) – Linux (KDE Plasma, z. B. CachyOS)
|
||||
* [GNAI-006-SEC_VPN_Clients_Windows11.md](GNAI-006-SEC_VPN_Clients_Windows11.md) – Windows 11
|
||||
Das Gateway ermöglicht administrativen und familiären Fernzugriff auf das Heimnetz. WireGuard authentifiziert Geräte durch Schlüssel; die Zielsysteme verlangen weiterhin ihre eigene Anmeldung. Ein Peer wird pro Gerät vergeben. Eine gemeinsame Konfiguration für mehrere gleichzeitig verwendete Geräte ist nicht vorgesehen.
|
||||
|
||||
**Änderungsvorschlag Draft:** Hostname, Testmatrix und PASSWORD_HASH-Format gemäß Umsetzung korrigiert (siehe Changelog)
|
||||
Das WireGuard-Gateway läuft bereits. Die nachfolgende Installation beschreibt seinen reproduzierbaren Aufbau; neue Sicherheitsmaßnahmen sind als **Soll** gekennzeichnet. Grundlage sind die Quellen, die Tests vom 12.09.2026, die vom Betreiber bereitgestellte Konfiguration und der lesende Gateway-Abgleich vom 18.09.2026. Es wurden keine Systemkonfigurationen geändert und keine neuen Client- oder Rollentests durchgeführt.
|
||||
|
||||
---
|
||||
**Wesentliche offene Umsetzung:** Per-Client Firewall ist deaktiviert. Die bisherige breite Forward-Regel erzwingt keine Rollenisolierung. HTTPS für die wg-easy-GUI ist noch nicht eingerichtet. Der dokumentierte Endpoint `vpn.ghostnet.selfhost.eu` stimmte am 18.09.2026 mit der ausgehenden IPv4 des Gateways überein; die DynDNS-Aktualisierung nach einem Adresswechsel ist noch nicht nachgewiesen.
|
||||
|
||||
## 1. Zweck & Geltungsbereich
|
||||
## 2. Architektur und Adressplan
|
||||
|
||||
Dieses Dokument beschreibt die verbindliche Einrichtung, Härtung und Verifikation des WireGuard-VPN-Gateways auf einem dedizierten Proxmox LXC-Container (CT 105, IP `10.0.0.15/24`). Das System dient als primäre Management-Zugangsschicht für administrative Zugriffe aus dem Internet (z. B. via Mobilfunk) unter strikter Einhaltung des Sicherheits- und Rollenmodells aus GNAI-004-SEC.
|
||||
|
||||
---
|
||||
|
||||
## 2. System-Baseline & Netzwerkarchitektur
|
||||
|
||||
| Parameter | Wert |
|
||||
| Komponente | Adresse / Konfiguration |
|
||||
| --- | --- |
|
||||
| Container-ID | CT 105 |
|
||||
| Hostname | `wireguard` |
|
||||
| Betriebssystem | Debian GNU/Linux 13 (Trixie) |
|
||||
| Proxmox VE | 9.2.11 |
|
||||
| Unprivileged | Ja (mit `/dev/net/tun` Passthrough, `c 10:200`) |
|
||||
| IP-Adresse LXC | `10.0.0.15/24` (Gateway: `10.0.0.1`) |
|
||||
| VPN Subnetz | `10.8.0.0/24` |
|
||||
| Listening Port | `51820/UDP` (Portweiterleitung auf Fritzbox 7530 an `10.0.0.15`) |
|
||||
| DNS | Subdomain `vpn.ghostnet.selfhost.eu` (A-Record beim Domain-DNS-Anbieter → WAN-IP) als `WG_HOST` |
|
||||
| Container Engine | Podman 5.4.2, Quadlet (`/etc/containers/systemd/wg-easy.container`) |
|
||||
| VPN Management | wg-easy (`ghcr.io/wg-easy/wg-easy:latest`), UI auf `http://10.0.0.15:51821` (LAN-only) |
|
||||
| Firewall | nftables, strikte INPUT policy `drop` |
|
||||
| Routing | Split-Tunneling, `ip_forward=1` persistent |
|
||||
| Fritzbox 7530 | `10.0.0.1`, Gateway, DNS und DynDNS-Updater |
|
||||
| Proxmox / Mediaserver | `10.0.0.2` |
|
||||
| NPM, CT 103 | `10.0.0.10`; TCP 80/443 öffentlich, TCP 81 administrativ |
|
||||
| WireGuard, CT 105 | `10.0.0.15/24`, Hostname `wireguard` |
|
||||
| KI-Server | `10.0.0.90`, Hostname `ghostnet-ki` |
|
||||
| Statischer Server-/LXC-Adressbereich | bis `.99`; konkrete Belegung siehe GNAI-003 |
|
||||
| DHCP-Clients | `10.0.0.100–10.0.0.200` |
|
||||
| VPN-Netz / Gateway | `10.8.0.0/24` / `10.8.0.1` |
|
||||
| WireGuard-Port | UDP 51820 |
|
||||
| wg-easy-GUI, Ist | `http://10.0.0.15:51821` |
|
||||
|
||||
### Rollen- & Zugriffsmatrix (gemäß GNAI-004-SEC)
|
||||
Die Fritzbox leitet **TCP 80/443 an `10.0.0.10`** und **UDP 51820 an `10.0.0.15`** weiter. NPM ist nicht am WireGuard-Datenpfad beteiligt. Es gibt keine Fritzbox-Rückroute zum VPN-Netz; wg-easy verwendet deshalb MASQUERADE auf dem LAN-Ausgang.
|
||||
|
||||
* **Full Admin Profil (Admin-Laptop):**
|
||||
* **VPN-IP:** `10.8.0.2/32`
|
||||
* **AllowedIPs Client-Seitig:** `10.0.0.0/24` (Split-Tunneling)
|
||||
* **Erlaubte Ziele:** Proxmox (`10.0.0.2`), LLM-Server (`10.0.0.90`), NPM Admin (`10.0.0.10:81`), Service-LXCs
|
||||
```mermaid
|
||||
flowchart TD
|
||||
W["Externe Clients"] --> F["Fritzbox 7530"]
|
||||
F -->|"TCP 80/443"| N["NPM · 10.0.0.10"]
|
||||
F -->|"UDP 51820"| V["wg-easy · 10.0.0.15"]
|
||||
N --> A["Öffentliche Anwendungen"]
|
||||
V --> R["Peer-Firewall · Soll; NAT · Ist"]
|
||||
R --> S["Proxmox, LXCs und KI-Server"]
|
||||
R -->|"nur Familie"| C["Heimnetz-PCs und Clients"]
|
||||
```
|
||||
|
||||
* **LLM Admin Profil (Android-Mobilgerät):**
|
||||
* **VPN-IP:** `10.8.0.3/32`
|
||||
* **AllowedIPs Client-Seitig:** `10.0.0.90/32`
|
||||
* **Erlaubte Ziele:** Exklusiv LLM-Server (`10.0.0.90`, z. B. SSH Port 22)
|
||||
Die Adressgruppierung im selben `/24` bildet keine Netzwerksegmentierung. Server-, Heim- und Gästenetz können später in einem eigenen Netzwerk-Sprint durch separate Netze, Routing und passende Hardware geordnet werden. Für diesen Sprint werden weder neue Subnetze noch VLAN-IDs angenommen.
|
||||
|
||||
> **Hinweis wg-easy / AllowedIPs (Umsetzung 2026-09-09):** Die **serverseitige** `AllowedIPs`-Eintragung wird von wg-easy hartkodiert als `client.address/32` (`/app/lib/WireGuard.js`, `__saveConfig()`) – korrekt für diese Architektur (Peer kommt nur aus seiner eigenen VPN-IP). Das **clientseitige Routing** (Split-Tunneling) wird in den heruntergeladenen Profilen aus der Env-Variable **`WG_ALLOWED_IPS`** generiert (`/app/lib/WireGuard.js`, `getClientConfiguration()`). Default von wg-easy wäre `0.0.0.0/0, ::/0` (Full-Tunnel!) – **umgestellt auf Split-Tunnel** via `/opt/wg-easy/environment`:
|
||||
>
|
||||
> ```
|
||||
> WG_ALLOWED_IPS=10.0.0.0/24,10.8.0.0/24,10.0.0.2/32,10.0.0.10/32,10.0.0.90/32
|
||||
> ```
|
||||
>
|
||||
> ⚠️ **Android-Limitierung:** WireGuard für Android akzeptiert in `AllowedIPs` nur `/32`-Einträge (keine `/24`-CIDRs). Die zusätzlichen `/32`-Einträge (Fritzbox, Proxmox, NPM, LLM-Server) existieren daher **ausschließlich** für Android-LLMAdmin; Laptop-FullAdmin nutzt die `/24`-Netzwerke. Konsequenz: Neue LAN-Hosts müssen **beide** Einträge pflegen (CIDR + `/32`) – kein per-Client-Override in wg-easy möglich (eine Env-Variable für alle Profile).
|
||||
### 2.1 Rollen und Durchsetzung
|
||||
|
||||
---
|
||||
| Rolle | Erlaubte Ziele | Client-Routing und serverseitige Firewall |
|
||||
| --- | --- | --- |
|
||||
| Familie | gesamtes Heimnetz einschließlich PCs und Clients | Heimnetz `10.0.0.0/24`; Zugriff auf das Gateway zusätzlich nach Bedarf explizit festlegen |
|
||||
| Server Admin | Proxmox, aktuelle Service-LXCs und KI-Server; wg-easy-GUI eingeschlossen | einzelne freigegebene Hostadressen aus dem Inventar; kein pauschales Heimnetz-`/24` |
|
||||
| LLM Admin | KI-Server `10.0.0.90` | `10.0.0.90/32`; keine Freigabe für Proxmox, NPM oder wg-easy |
|
||||
|
||||
## 3. Schritt-für-Schritt Einrichtung & Deployment
|
||||
Diese Vorgaben erlauben Netzwerkzugriff auf die genannten Hosts. Anwendungs-, SSH- und Betriebssystemrechte werden separat vergeben. Ein statischer Adressbereich ist kein ausreichender Nachweis, dass jede Adresse darin ein Server ist: Erweiterungen benötigen einen Inventareintrag und die passende Peer-Freigabe.
|
||||
|
||||
> Statuslegenden: ✅ erledigt (2026-09-09, Agent-Session) · ⏳ offen · 👤 User-Aktion
|
||||
**Soll:** In wg-easy die Per-Client Firewall aktivieren und für jeden Peer **Firewall Allowed IPs** ausdrücklich setzen. **Allowed IPs** im exportierten Profil steuert weiter das Split-Tunnel-Routing. **Server Allowed IPs** bezeichnet die Netze, die der Server zum Peer routet; für ein einzelnes Endgerät bleibt das dessen eigene VPN-IP `/32`. Diese drei Felder dürfen nicht miteinander verwechselt werden. [Client-Felder](https://wg-easy.github.io/wg-easy/latest/guides/clients/)
|
||||
|
||||
### 1. LXC Container & TUN-Device auf Proxmox konfigurieren ✅
|
||||
Die Funktion ist laut offizieller Dokumentation experimentell. Abnahme muss absichtliche Erweiterungen der clientseitigen AllowedIPs auf gesperrte Ziele einschließen. Insbesondere muss der Zugriff auf **lokale Gateway-Dienste** geprüft werden, da dieser die INPUT- statt FORWARD-Chain durchläuft. [Per-Client Firewall](https://wg-easy.github.io/wg-easy/latest/guides/admin/)
|
||||
|
||||
Unprivileged Debian 13 LXC (CT 105), IP `10.0.0.15/24`. In `/etc/pve/lxc/105.conf` auf Proxmox:
|
||||
## 3. Installation im Proxmox-LXC
|
||||
|
||||
### 3.1 LXC erstellen und Netzwerk konfigurieren
|
||||
|
||||
In Proxmox ein unprivileged Debian-13-LXC mit diesen Werten erstellen:
|
||||
|
||||
| Parameter | bestätigter Wert |
|
||||
| --- | --- |
|
||||
| CT-ID / Hostname | 105 / `wireguard` |
|
||||
| Betriebssystem / Architektur | Debian 13 Trixie / amd64 |
|
||||
| CPU / RAM / Swap | 1 Core / 512 MiB / 512 MiB |
|
||||
| RootFS | 4 GiB, `local-lvm` |
|
||||
| Features | `nesting=1,keyctl=1` |
|
||||
| Netz | `eth0`, `vmbr0`, `10.0.0.15/24`, Gateway `10.0.0.1` |
|
||||
| Start / Zeitzone | `onboot: 1` / `Europe/Berlin` |
|
||||
| Proxmox-Version, Quellenstand | 9.2.11; bei Reproduktion installierte Version festhalten |
|
||||
|
||||
Auf dem Proxmox-Host in `/etc/pve/lxc/105.conf` ergänzen, ohne vorhandene Einträge doppelt anzulegen:
|
||||
|
||||
```text
|
||||
lxc.cgroup2.devices.allow: c 10:200 rwm
|
||||
lxc.mount.entry: /dev/net/tun dev/net/tun none bind,create=file
|
||||
```
|
||||
|
||||
Verifikation: `ls -l /dev/net/tun` im Container zeigt Character Device `c 10 200`. ✅ (vorhanden seit Podman-Setup)
|
||||
Nach einer Änderung CT 105 neu starten. Im LXC prüfen:
|
||||
|
||||
### 2. Firewall (nftables) & IP-Forwarding ✅
|
||||
```bash
|
||||
ls -l /dev/net/tun
|
||||
ip -4 addr show eth0
|
||||
ip -4 route show
|
||||
```
|
||||
|
||||
Strikte INPUT policy `drop`, öffentlich nur WireGuard UDP `51820`, Management-Ports nur aus dem LAN, Forward-Chain für Split-Tunneling via `wg0`.
|
||||
WireGuard im Kernel verwendet ein WireGuard-Netzinterface. TUN ist Teil der bestätigten LXC-Baseline und unterstützt mögliche Userspace-Implementierungen; sein Vorhandensein allein beweist keine funktionierende WireGuard-Kernelunterstützung. Fehlende Kernelmodule werden auf dem **Proxmox-Host** untersucht, nicht durch pauschale SYS_MODULE- oder privileged-Freigaben im LXC ersetzt.
|
||||
|
||||
### 3.2 Pakete, Administrator und persistente Verzeichnisse
|
||||
|
||||
Im LXC als root bzw. mit sudo installieren:
|
||||
|
||||
```bash
|
||||
sudo apt update
|
||||
sudo apt install podman nftables iptables iproute2 procps curl sudo openssh-server
|
||||
sudo install -d -m 700 /opt/wg-easy/data
|
||||
sudo install -d -m 755 /etc/containers/systemd
|
||||
sudo install -m 600 /dev/null /opt/wg-easy/environment
|
||||
```
|
||||
|
||||
Der letzte Befehl ist ausschließlich für eine **Neuinstallation**: ein vorhandenes Environment-File nicht überschreiben. Dokumentiert ist Podman 5.4.2. Die durch Debian bereitgestellte Version mit `podman --version` festhalten und Quadlet-Unterstützung prüfen.
|
||||
|
||||
Den Benutzer `admin` nur anlegen, wenn er noch nicht existiert. SSH-Key hinterlegen und Rechte testen. Für die SSH-Härtung die allgemeinen Prüfschritte aus [GNAI-002](GNAI-002-INFRA_Users.md) auf diesen LXC übertragen; dessen KI-Server-Konten und Netzwerte nicht übernehmen. Im bestehenden WireGuard-LXC ist `admin ALL=(ALL) NOPASSWD: ALL` eingerichtet; das ist der bestätigte Ist-Stand und keine allgemeine Vorgabe für alle LLM-Benutzer. Änderungen an SSH immer mit einer offenen zweiten Sitzung oder Proxmox-Konsole absichern.
|
||||
|
||||
### 3.3 IP-Forwarding
|
||||
|
||||
`/etc/sysctl.d/99-ipforward.conf`:
|
||||
|
||||
@@ -89,86 +123,87 @@ Strikte INPUT policy `drop`, öffentlich nur WireGuard UDP `51820`, Management-P
|
||||
net.ipv4.ip_forward=1
|
||||
```
|
||||
|
||||
`/etc/nftables.conf` (geladen, SSH-Funktionalität nach Load verifiziert):
|
||||
Anwenden und prüfen:
|
||||
|
||||
```bash
|
||||
sudo sysctl --system
|
||||
sysctl net.ipv4.ip_forward
|
||||
```
|
||||
|
||||
Erwartet: `net.ipv4.ip_forward = 1`. Die bestätigten LXC-Routen sind:
|
||||
|
||||
```text
|
||||
default via 10.0.0.1 dev eth0 proto kernel onlink
|
||||
10.0.0.0/24 dev eth0 proto kernel scope link src 10.0.0.15
|
||||
10.8.0.0/24 dev wg0 proto kernel scope link src 10.8.0.1
|
||||
```
|
||||
|
||||
Die VPN-Route entsteht erst mit dem Interface. Bei Neuinstallation vor dem ersten wg-easy-Start ist sie noch nicht vorhanden.
|
||||
|
||||
### 3.4 nftables-Baseline: Ist und erforderliche Erweiterung
|
||||
|
||||
Die Quellen dokumentieren folgende Baseline in `/etc/nftables.conf`. Ein lesender Live-Abgleich der entscheidenden INPUT- und FORWARD-Regeln am 18.09.2026 bestätigt weiterhin die breite VPN→LAN-Freigabe; das vollständige Regelwerk ist im [Implementation-Log](GNAI-006-SEC_VPN_Implementation-Log.md) nicht als neue Gesamtabnahme ausgewiesen:
|
||||
|
||||
```nft
|
||||
#!/usr/sbin/nft -f
|
||||
|
||||
flush ruleset
|
||||
|
||||
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
|
||||
icmp type { echo-request, echo-reply, destination-unreachable, time-exceeded } accept
|
||||
udp dport 51820 accept
|
||||
ip saddr 10.0.0.0/24 tcp dport { 22, 51821 } accept
|
||||
limit rate 4/second burst 8 packets log prefix "nft-input-dropped: "
|
||||
drop
|
||||
}
|
||||
chain forward {
|
||||
type filter hook forward priority filter; policy drop;
|
||||
ct state invalid drop
|
||||
ct state established,related accept
|
||||
iifname "wg0" ip daddr 10.0.0.0/24 ct state new accept
|
||||
oifname "wg0" ip saddr 10.0.0.0/24 ip daddr 10.8.0.0/24 ct state new accept
|
||||
drop
|
||||
}
|
||||
chain output {
|
||||
type filter hook output priority accept;
|
||||
}
|
||||
chain input {
|
||||
type filter hook input priority filter; policy drop;
|
||||
iifname "lo" accept
|
||||
ct state invalid drop
|
||||
ct state established,related accept
|
||||
icmp type { echo-request, echo-reply, destination-unreachable, time-exceeded } accept
|
||||
udp dport 51820 accept
|
||||
ip saddr 10.0.0.0/24 tcp dport { 22, 51821 } accept
|
||||
limit rate 4/second burst 8 packets log prefix "nft-input-dropped: "
|
||||
drop
|
||||
}
|
||||
chain forward {
|
||||
type filter hook forward priority filter; policy drop;
|
||||
ct state invalid drop
|
||||
ct state established,related accept
|
||||
iifname "wg0" ip daddr 10.0.0.0/24 ct state new accept
|
||||
oifname "wg0" ip saddr 10.0.0.0/24 ip daddr 10.8.0.0/24 ct state new accept
|
||||
drop
|
||||
}
|
||||
chain output {
|
||||
type filter hook output priority filter; policy accept;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Verifikation: ✅ SSH aus LAN erreichbar, WAN-Regeln per `nft list ruleset` kontrolliert, `ip_forward=1` aktiv und persistent.
|
||||
**Diese Baseline ist keine fertige Rollen-Firewall.** Die breite FORWARD-Freigabe muss gemeinsam mit Per-Client Firewall getestet werden. Die INPUT-Regel erlaubt LAN-Quellen, aber noch keine neuen Verbindungen von VPN-Quellen `10.8.0.x` auf TCP 22/51821. Für Familie und Server Admins muss am Gateway eine ausdrückliche INPUT-Freigabe anhand ihrer zugewiesenen VPN-IP oder einer gepflegten Peer-IP-Menge hinzukommen. LLM Admins dürfen diese Ports auch nach einer lokalen Routingänderung nicht erreichen. Die Rollenzuordnung vorhandener Peers ist noch offen; daher wird keine angeblich fertige IP-Regel erfunden.
|
||||
|
||||
> **Hinweis:** Die wg-easy-`PostUp`-Regeln in `wg0.conf` (iptables MASQUERADE/FORWARD/INPUT-ACCEPT für 51820) sind mit der nftables-Config redundant, kollidieren aber nicht (iptables-FORWARD-ACCEPT ist breiter als die nftables-Forward-Rules, die maßgeblich bleiben). Optional über `WG_POST_UP`/`WG_PRE_DOWN` leerbaren lassen – Entscheidung offen.
|
||||
`flush ruleset` löscht dynamisch angelegte nftables-/iptables-nft-Regeln. Der Live-Abgleich am 18.09.2026 zeigte jedoch wg-easy-Hooks in **iptables-legacy**; diese werden durch einen nftables-Flush nicht automatisch mit gelöscht. Beide Regelwerke und ihre gemeinsame Wirkung müssen nach Reload oder Neustart geprüft werden. Bei einer Neuinstallation zuerst die Baseline laden, danach wg-easy starten. Im laufenden Betrieb vor einem Reload Regelzustand sichern und Änderung über die Proxmox-Konsole ausführen. Dauerhafte Regeln und dynamische Regeln brauchen eine getestete Start-/Reload-Reihenfolge; diese Abnahme steht noch aus.
|
||||
|
||||
### 3. SSH-Härtung & Admin-User (gemäß GNAI-004-SEC) ✅
|
||||
|
||||
* User `admin` (uid 1000), sudoers `admin ALL=(ALL) NOPASSWD: ALL`
|
||||
* `PermitRootLogin no` – SSH-Zugriff ausschließlich über `admin` mit SSH-Key
|
||||
* Drop-in `/etc/ssh/sshd_config.d/99-security.conf`:
|
||||
|
||||
```text
|
||||
PermitRootLogin no
|
||||
PasswordAuthentication no
|
||||
KbdInteractiveAuthentication no
|
||||
PubkeyAuthentication yes
|
||||
PermitEmptyPasswords no
|
||||
```bash
|
||||
sudo nft -c -f /etc/nftables.conf
|
||||
sudo nft -f /etc/nftables.conf
|
||||
sudo systemctl enable nftables.service
|
||||
sudo nft list ruleset
|
||||
```
|
||||
|
||||
Verifikation: ✅ Key-Login als `admin`, `sudo` passwortlos, `/root/.ssh/authorized_keys` existierte nie (kein root-Key Cleanup nötig).
|
||||
Diese Befehle sind Installationsschritte, keine Empfehlung zum ungeprüften Reload einer laufenden Umgebung. IPv6 im LXC und am Perimeter separat prüfen. `DISABLE_IPV6=true` in wg-easy ersetzt keine Prüfung der IPv6-Erreichbarkeit anderer Dienste.
|
||||
|
||||
### 4. Podman Quadlet für wg-easy ✅
|
||||
### 3.5 Rootful Podman-Quadlet
|
||||
|
||||
Installiert: `podman` 5.4.2.
|
||||
|
||||
**Wichtige Umsetzungsentscheidungen (Abweichungen vom ursprünglichen Draft):**
|
||||
|
||||
1. **bcrypt statt Argon2:** wg-easy verifiziert das UI-Passwort mit **bcryptjs (Salt-Rounds 12)** über `PASSWORD_HASH`. Argon2-Hashes werden nicht akzeptiert.
|
||||
2. **Passwort-Rotation 2026-09-09:** Das initial generierte UI-Passwort wurde nach der Session nicht übergeben → **rotiert** (neuer bcrypt-Hash im Environment-File, Login-API HTTP 200 verifiziert). **Klartext liegt ausschließlich in 1Password** (Eintrag `ghostnet/wg-easy-ui`); auf dem LXC und im Repo existiert nur der Einweg-Hash.
|
||||
2. **EnvironmentFile statt Environment=:** Der bcrypt-Hash enthält `$`-Zeichen (`$2a$12$…`), die im Quadlet-`Environment=`-Format fehleranfällig escaped werden müssen. Sauberer Weg: `EnvironmentFile=`.
|
||||
3. **Unit-Name:** Quadlet generiert `wg-easy.service` (nicht `wg-easy.container.service`).
|
||||
|
||||
`/opt/wg-easy/environment` (`chmod 600`, Owner root):
|
||||
Bestätigter `/opt/wg-easy/environment`-Stand aus dem v15-Hauptdokument; bei Installation mit dem tatsächlichen Environment abgleichen:
|
||||
|
||||
```ini
|
||||
WG_HOST=vpn.ghostnet.selfhost.eu
|
||||
WG_PORT=51820
|
||||
WG_DEFAULT_ADDRESS=10.8.0.x
|
||||
WG_DEFAULT_DNS=10.0.0.1
|
||||
ALLOW_CONFIG_CHANGE=true
|
||||
PASSWORD_HASH=$2a$12$<60-zeichen- bcrypt-hash>
|
||||
INSECURE=true
|
||||
DISABLE_IPV6=true
|
||||
DISABLE_VERSION_CHECK=true
|
||||
```
|
||||
|
||||
`/etc/containers/systemd/wg-easy.container`:
|
||||
`INSECURE=true` erlaubt derzeit HTTP. Die VPN-Konfiguration und Administratoranmeldung liegen in v15 in der SQLite-Datenbank, nicht in den alten v14-Variablen `WG_HOST`, `WG_ALLOWED_IPS` oder `PASSWORD_HASH`. Ein fester Image-Pin verhindert unkontrollierte Versionswechsel; eine dauerhafte Aussage über den veränderlichen `latest`-Tag wird nicht vorausgesetzt. [Konfiguration](https://wg-easy.github.io/wg-easy/latest/advanced/config/optional-config/)
|
||||
|
||||
Bestätigter `/etc/containers/systemd/wg-easy.container`:
|
||||
|
||||
```ini
|
||||
[Container]
|
||||
Image=ghcr.io/wg-easy/wg-easy:latest
|
||||
Image=ghcr.io/wg-easy/wg-easy:15.4.0
|
||||
ContainerName=wg-easy
|
||||
Network=host
|
||||
AddCapability=NET_ADMIN
|
||||
@@ -183,101 +218,104 @@ Restart=on-failure
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
> **Sicherheitshinweis:** Der aktive bcrypt-Hash des wg-easy-UI-Passworts wird **bewusst nicht** in diesem Dokument abgelegt (Secrets nicht in Docs). Der aktuelle Wert liegt ausschließlich in `/opt/wg-easy/environment` auf dem LXC (chmod 600). Passwort-Rotation: neuen bcrypt-Hash (Rounds 12, z. B. `npx bcryptjs -r 12 "<passwort>"`) generieren, Datei aktualisieren, `systemctl restart wg-easy.service`.
|
||||
`Network=host` bezieht sich auf den Netzwerknamespace des LXC, nicht auf den Proxmox-Host. Das Quadlet läuft rootful im LXC. Quadlet generiert **`wg-easy.service`**; die generierte Unit wird nicht direkt bearbeitet oder wie eine normale statische Unit enabled.
|
||||
|
||||
Verifikation: ✅ `podman ps` zeigt `wg-easy` mit host-Netzwerk; `wg0` up mit `10.8.0.1/24`, `ListenPort 51820`; UI `http://10.0.0.15:51821` HTTP 200 (localhost & LAN-IP).
|
||||
```bash
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl start wg-easy.service
|
||||
sudo systemctl status wg-easy.service
|
||||
sudo podman ps
|
||||
sudo journalctl -u wg-easy.service -n 100 --no-pager
|
||||
```
|
||||
|
||||
### 5. Perimeter-Portweiterleitung Fritzbox 7530 👤 (User) ✅
|
||||
Nach Quadlet-Änderungen `daemon-reload` und `restart` ausführen. Autostart von LXC, nftables und wg-easy sowie persistentes Forwarding gemeinsam durch einen geplanten Reboot testen. Die bisherige Dokumentation ist kein Nachweis dieser vollständigen Wiederanlaufprüfung.
|
||||
|
||||
Portweiterleitung **UDP `51820` → `10.0.0.15`** auf der Fritzbox 7530 einrichten.
|
||||
## 4. wg-easy erstmalig konfigurieren
|
||||
|
||||
Verifikation: `tcpdump -i eth0 udp port 51820` auf dem LXC während Handshake-Versuch aus dem WAN.
|
||||
1. Aus dem vertrauenswürdigen LAN `http://10.0.0.15:51821` öffnen. Im vorhandenen System ist der Wizard bereits abgeschlossen.
|
||||
2. Bei Neuinstallation Administrator-Benutzername und Passwort im Wizard setzen. Zugangsdaten im Passwortmanager hinterlegen; keine Secrets in Dokumente kopieren.
|
||||
3. Für Neuinstallation **kein vorhandenes v14-Backup importieren**. Der historische v14→v15-Import ist ausschließlich im Implementation-Log dokumentiert.
|
||||
4. Als Host `vpn.ghostnet.selfhost.eu` und als Port `51820` eintragen; vor Ausgabe neuer Profile DNS-Auflösung und aktuelle WAN-IP erneut vergleichen.
|
||||
5. Interface-Adressraum `10.8.0.0/24`, Gateway `10.8.0.1` und IPv4-Betrieb prüfen. In Admin Panel → Interface das LAN-Ausgangsgerät `eth0` prüfen.
|
||||
6. Neue Client-Defaults so wählen, dass neue Peers keine ungeprüften Vollzugriffsrechte erhalten. Für jede Freigabe gilt die separate GUI-SOP; ein Default ist keine Rollenzuordnung.
|
||||
7. DNS rollenabhängig setzen: Familie kann die Fritzbox `10.0.0.1` über das Heimnetz erreichen. Server Admins und LLM Admins verwenden zunächst System-DNS, sofern keine gesonderte DNS-Freigabe beschlossen wird. Historischer Laptop-DNS `10.0.0.1` ist kein pauschaler neuer Default.
|
||||
8. Per-Client Firewall für die neue Rollenpolitik aktivieren und abnehmen. Vor Aktivierung vorhandene Peers erfassen, Änderungen über LAN durchführen und unzugeordnete Peers während der Umstellung gesperrt halten.
|
||||
|
||||
**Status: ✅ erledigt (2026-09-09, User); End-to-End-Verifikation offen (Step 8/9).**
|
||||
[Offizieller Setup-Ablauf](https://wg-easy.github.io/wg-easy/latest/guides/setup/)
|
||||
|
||||
### 6. DNS-Subdomain 👤 (User)
|
||||
### 4.1 Bestätigte Server-Hooks und NAT-Abhängigkeit
|
||||
|
||||
**Korrektur 2026-09-09:** Der A-Record gehört **nicht** in den Nginx Proxy Manager (NPM 10.0.0.10 – der verwaltet nur HTTP(S)-Proxy-Hosts, für UDP 51820 nutzlos) und nicht ins selfhost.eu-Web-Portal (Instanzen-Hosting, keine DNS-Zone). Die Zone `ghostnet.selfhost.eu` wird beim **DNS-Anbieter/Registrar der Domain** gepflegt – dort, wo `jellyfin./nextcloud./…` bereits existieren.
|
||||
PreUp und PreDown sind leer. Bestätigter PostUp:
|
||||
|
||||
Eintrag anlegen: `vpn` → Typ **A – IPv4** → Ziel **WAN-IP** (`93.208.161.126` laut `getent` am 2026-09-09). DNS kann keine Ports tragen – der Port steht in der Client-Config (`Endpoint = vpn.ghostnet.selfhost.eu:51820`).
|
||||
```bash
|
||||
iptables -t nat -A POSTROUTING -s {{ipv4Cidr}} -o {{device}} -j MASQUERADE; iptables -A INPUT -p udp -m udp --dport {{port}} -j ACCEPT; iptables -A FORWARD -i wg0 -j ACCEPT; iptables -A FORWARD -o wg0 -j ACCEPT;
|
||||
```
|
||||
|
||||
> ⚠️ **WAN-IP-Check offen:** Falls die WAN-IP dynamisch ist (Fritzbox-Übersicht → „statische IP“ prüfen), veraltet der A-Record bei IP-Wechsel → DynDNS nötig. Bestehende Subdomains laufen bereits auf `93.208.161.126`.
|
||||
Bestätigter PostDown:
|
||||
|
||||
**Status: ✅ erledigt (2026-09-09).** Verifikation: `vpn.ghostnet.selfhost.eu` → `93.208.161.126` (getent + nslookup, 17:22). Hinweis: expliziter A-Record war **nicht nötig** – eine bestehende **Wildcard-DynDNS-Zuordnung** `*.ghostnet.selfhost.eu` → WAN-IP lag bereits vor (exakter Eintrag schlägt vor Wildcard; gleicher Wert → harmlos, redundanter Eintrag kann optional entfernt werden). DynDNS vorhanden → Statisch-Check entfällt.
|
||||
```bash
|
||||
iptables -t nat -D POSTROUTING -s {{ipv4Cidr}} -o {{device}} -j MASQUERADE; iptables -D INPUT -p udp -m udp --dport {{port}} -j ACCEPT; iptables -D FORWARD -i wg0 -j ACCEPT; iptables -D FORWARD -o wg0 -j ACCEPT;
|
||||
```
|
||||
|
||||
### 7. Peers erzeugen ✅
|
||||
Das sind wg-easy-Templates; nicht unverändert als Terminalbefehle ausführen. Prüfen, dass die Platzhalter auf `10.8.0.0/24`, `eth0` und `51820` aufgelöst werden. MASQUERADE wird beibehalten, solange keine getestete Rückroute eingerichtet ist. Das Entfernen aller Hooks würde den dokumentierten LAN-Zugriff gefährden. Die ACCEPT-Regeln sind breit; ihre Reihenfolge und Wirkung mit den Per-Client-Regeln müssen geprüft werden.
|
||||
|
||||
Peers über die wg-easy-API erstellt (UI unter `http://10.0.0.15:51821`, Login `POST /api/session`):
|
||||
```bash
|
||||
sudo podman exec wg-easy iptables -V
|
||||
sudo podman exec wg-easy iptables -S
|
||||
sudo podman exec wg-easy iptables -t nat -S
|
||||
sudo nft list ruleset
|
||||
sudo iptables-legacy -S FORWARD
|
||||
sudo iptables-legacy -t nat -S POSTROUTING
|
||||
sudo podman exec wg-easy wg show wg0
|
||||
```
|
||||
|
||||
| Peer | VPN-IP | Client-UUID | Erlaubte Ziele (clientseitiges Routing) |
|
||||
| --- | --- | --- | --- |
|
||||
| Laptop-FullAdmin | `10.8.0.2` | `2e9ed910-36dc-4fbd-8694-8d904670ea19` | `10.0.0.0/24`, `10.8.0.0/24` |
|
||||
| Android-LLMAdmin | `10.8.0.3` | `2009acd2-19cf-4e5e-a93a-7b05eb05fc12` | `10.0.0.90/32` (+ `10.8.0.0/24`) |
|
||||
Mit iptables-nft werden Regeln in nftables sichtbar; bei iptables-legacy zusätzlich dessen eigenen Zustand berücksichtigen. Der Standardaufruf `iptables -S` zeigte am 18.09.2026 nur die nft-Ansicht und warnte vor vorhandenen Legacy-Tabellen. Ein ACCEPT in einer Base-Chain garantiert keine Freigabe gegenüber anderen Base-Chains; ein DROP ist abschließend. Eine pauschale Aussage „kein Konflikt“ ist deshalb kein Ersatz für Regel- und Verkehrstests. [nftables-Verarbeitung](https://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains)
|
||||
|
||||
Server-Config `wg0.conf` enthält beide Peers mit `PresharedKey`; serverseitig `AllowedIPs = 10.8.0.2/32` bzw. `10.8.0.3/32` (wg-easy-Hardcode, siehe Hinweis in Sektion 2).
|
||||
## 5. HTTPS und Erreichbarkeit der Verwaltungs-GUI
|
||||
|
||||
Verifikation ausstehend: ⏳ heruntergeladene Client-Profile auf clientseitige `AllowedIPs` (aus `WG_ALLOWED_IPS`) und `Endpoint vpn.ghostnet.selfhost.eu:51820` kontrollieren (abhängig von Step 5/6). Hinweis: `WG_PERSISTENT_KEEPALIVE` ist nicht gesetzt (Default `0`) – bei NAT/Router-Wechsel-Problemen auf `25` setzen.
|
||||
**Ist:** HTTP auf TCP 51821, laut Baseline nur aus LAN-Quellen. **Soll:** Zugriff nur für Familie und Server Admins; Administrator erstellt und verteilt alle Profile.
|
||||
|
||||
### 8. Split-Tunneling-Routing verifizieren ⏳ (Konfig gesetzt, End-to-End offen)
|
||||
HTTPS über einen internen, zugriffsbeschränkten NPM-Proxy Host ist eine mögliche Erweiterung. Hostname, Zertifikatsverfahren und interne Namensauflösung sind noch festzulegen. Keine öffentliche Freigabe allein wegen HTTPS oder eines internen DNS-Namens annehmen. Bei Proxy-Betrieb den direkten Port 51821 auf die benötigten Quellen begrenzen und LLM-Admin-Zugriffe über den Gateway-INPUT-Pfad separat sperren. Hinter einem HTTP-Backend-Proxy kann `INSECURE=true` weiterhin nötig sein; externe TLS-Terminierung verschlüsselt den NPM→wg-easy-Pfad nicht automatisch.
|
||||
|
||||
✅ **Erledigt (2026-09-09):** `WG_ALLOWED_IPS` in `/opt/wg-easy/environment` gesetzt (Split-Tunnel statt wg-easy-Default Full-Tunnel), `wg-easy.service` neu gestartet, Env im Container verifiziert.
|
||||
MASQUERADE lässt LAN-Dienste VPN-Verkehr unter der Quelladresse `10.0.0.15` sehen. Eine NPM-Freigabe für diese Adresse unterscheidet Familie, Server Admin und LLM Admin nicht. Rollentrennung muss vor NAT am Gateway funktionieren. Eine pauschale LAN-Freigabe gewährt außerdem lokalen Heimnetz-Clients Zugriff; eine gruppengenaue Beschränkung lokaler Geräte erfordert zusätzliche Zuordnung oder Authentifizierung und ist noch offen.
|
||||
|
||||
⏳ **Offen (abhängig von Step 5/6 + Endgerät):**
|
||||
## 6. Betrieb, Backup und Wiederherstellung
|
||||
|
||||
* Heruntergeladenes Profil Laptop-FullAdmin: `AllowedIPs = 10.0.0.0/24,10.8.0.0/24,…` + `Endpoint vpn.ghostnet.selfhost.eu:51820` prüfen, LAN-Hosts durch VPN erreichbar, Internet-Traffic bleibt **außerhalb** des Tunnels
|
||||
* Android-LLMAdmin: Routing nur auf `10.0.0.90` (LLM-Server) + VPN-Subnetz; andere LAN-Hosts nicht über VPN erreichbar
|
||||
* DNS `10.0.0.1` via `WG_DEFAULT_DNS` (nur innerhalb Tunnelsolutions relevant – prüfen, ob Android DNS-Einstellung akzeptiert)
|
||||
| Artefakt | Zweck |
|
||||
| --- | --- |
|
||||
| `/etc/pve/lxc/105.conf` | LXC-Konfiguration auf Proxmox |
|
||||
| `/etc/containers/systemd/wg-easy.container` | Quadlet |
|
||||
| `/opt/wg-easy/environment` | allgemeine Container-Schalter, root, Modus 600 |
|
||||
| `/opt/wg-easy/data/wg-easy.db` | v15-Konfiguration, Clients und Secrets |
|
||||
| `/opt/wg-easy/data/wg0.conf` | erzeugte Serverkonfiguration; nicht manuell bearbeiten |
|
||||
| `/etc/nftables.conf` | lokale Firewall |
|
||||
| `/etc/sysctl.d/99-ipforward.conf` | Forwarding |
|
||||
|
||||
### 9. Penetrationstest & Ingress-Verifikation über Mobilfunk ⏳
|
||||
Vor Änderungen ein konsistentes Proxmox-Backup erstellen. Ein Snapshot allein ist kein unabhängiges Backup. Für ein Dateibackup wg-easy in einem Wartungsfenster stoppen, **das gesamte Datenverzeichnis** einschließlich etwaiger SQLite-WAL-Dateien sowie Quadlet, Environment, Firewall und sysctl sichern; anschließend Dienst wieder starten. Backups enthalten PrivateKeys und PresharedKeys und sind entsprechend zu schützen. Wiederherstellung einschließlich Rollenregeln, NAT, externem Handshake und gesperrten Zielen testen. Restore kann inzwischen widerrufene Peers wieder aktivieren; Widerrufsliste abgleichen.
|
||||
|
||||
Deaktiviere WLAN auf beiden Testgeräten (reiner 4G/5G-Pfad), VPN aktivieren:
|
||||
## 7. Abnahme und Evidenz
|
||||
|
||||
* **Android (LLM Admin):** `ping 10.0.0.90` muss antworten; `ping 10.0.0.2` (Proxmox) muss durch Firewall/DROP-Regeln fehlschlagen
|
||||
* **Laptop (Full Admin):** `ssh` auf `10.0.0.90` und Proxmox GUI `https://10.0.0.2:8006` müssen funktionieren
|
||||
* Zusätzlich: WAN-Ingress ohne VPN – `51821` (wg-easy UI) und `22` (SSH) aus dem Internet **nicht** erreichbar
|
||||
| Prüfung | Ergebnis / Status |
|
||||
| --- | --- |
|
||||
| Laptop-Handshake von WAN | bestanden am 12.09.2026 |
|
||||
| Laptop → `10.8.0.1` und Ping `10.0.0.2` | bestanden am 12.09.2026 |
|
||||
| Laptop-Internet bleibt direkt | IPv4-Test bestanden am 12.09.2026 |
|
||||
| Zugriff auf KI-Server | offen; im letzten Test ausgeschaltet |
|
||||
| Proxmox-GUI / SSH-Diensttests | offen; Ping ersetzt keinen Diensttest |
|
||||
| Familie → Heimnetz-PC | offen, einschließlich Host-Firewall und Authentifizierung |
|
||||
| Server Admin → Server erlaubt, DHCP-Client gesperrt | offen, Per-Client Firewall noch aus |
|
||||
| LLM Admin → KI-Server erlaubt, Proxmox/NPM/Gateway-GUI gesperrt | offen, auch bei erweiterten lokalen AllowedIPs prüfen |
|
||||
| WAN → TCP 22/51821 und IPv6-Exposure | offen |
|
||||
| Reboot / Firewall-Reload / Restore | offen |
|
||||
|
||||
**Status: offen, gemeinsam mit User durchführen**
|
||||
Tests von einem fremden Netz ausführen, nicht nur aus dem Heimnetz. Für Isolation zuerst sicherstellen, dass das gesperrte Ziel von einem erlaubten Peer tatsächlich erreichbar ist. Handshake und VPN-Routen prüfen, dann bewusst clientseitiges Routing zu einem gesperrten Ziel ergänzen. Timeout allein ist ohne aktiven Zielservice und nachvollziehbare Firewallwirkung kein ausreichender Isolationsnachweis. Ergebnisse mit Datum, Quellnetz, Peer, Ziel, Port und Regelzählern dokumentieren; Secrets auslassen.
|
||||
|
||||
---
|
||||
## 8. Offene Angaben und Abschlussbedingungen
|
||||
|
||||
## 4. Penetrationsprüfungs- & Testmatrix
|
||||
|
||||
| Test-Szenario | Quellnetz | Ziel-IP / Dienst | Erwartetes Ergebnis | Status |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| WAN Ingress UDP Scan | Internet (Mobilfunk) | WAN-IP:51820 UDP | WireGuard Handshake kommt zustande | Ausstehend |
|
||||
| LLM Admin Isolation | Mobilfunk (Android) | `10.0.0.2:8006` (Proxmox) | **DROP / TIMEOUT** | Ausstehend |
|
||||
| LLM Admin SSH Access | Mobilfunk (Android) | `10.0.0.90:22` (LLM Server) | **SUCCESS** | Ausstehend |
|
||||
| Full Admin Access | Mobilfunk (Laptop) | `10.0.0.2:8006` (Proxmox) | **SUCCESS** | Ausstehend |
|
||||
| Full Admin SSH Access | Mobilfunk (Laptop) | `10.0.0.90:22` (`ghostnet.ki`) | **SUCCESS** | Ausstehend |
|
||||
| UI Ingress-Isolation | Internet (Mobilfunk) | WAN-IP:51821 (wg-easy UI) | **DROP / TIMEOUT** | Ausstehend |
|
||||
| SSH Ingress-Isolation | Internet (Mobilfunk) | WAN-IP:22 (LXC) | **DROP / TIMEOUT** | Ausstehend |
|
||||
|
||||
---
|
||||
|
||||
## 5. Umsetzungszustand (Stand: 2026-09-09)
|
||||
|
||||
| # | Schritt | Status |
|
||||
| --- | --- | --- |
|
||||
| 1 | LXC + TUN-Device | ✅ |
|
||||
| 2 | nftables + ip_forward | ✅ |
|
||||
| 3 | SSH-Härtung / admin-User | ✅ |
|
||||
| 4 | wg-easy Quadlet + wg0 | ✅ |
|
||||
| 5 | Fritzbox Portforward UDP 51820 | ✅ User (2026-09-09; E2E-Check offen) |
|
||||
| 6 | DNS `vpn.ghostnet.selfhost.eu` (via Wildcard-DynDNS + Redundanz-A-Record) | ✅ User (2026-09-09, Auflösung verifiziert) |
|
||||
| 7 | Peers Laptop-FullAdmin / Android-LLMAdmin | ✅ |
|
||||
| 8 | Split-Tunnel-Konfig (`WG_ALLOWED_IPS`) | ✅ (End-to-End-Verifikation ⏳ mit Step 9) |
|
||||
| 9 | Penetrationstest Mobilfunk | ⏳ |
|
||||
|
||||
Details & Entscheidungen: siehe `GNAI-006-SEC_VPN_Implementation-Log.md`.
|
||||
|
||||
---
|
||||
|
||||
## Changelog
|
||||
|
||||
| Version | Datum | Änderung |
|
||||
| --- | --- | --- |
|
||||
| 1.0 | – | Erster Draft |
|
||||
| 1.1 | 2026-09-09 | Umsetzung dokumentiert: Hostname `wireguard` (nicht `wireguard-gateway`); Testmatrix auf „Ausstehend“ (keine Tests über Mobilfunk gelaufen); `PASSWORD_HASH` = bcrypt (wg-easy/bcryptjs), nicht Argon2; Quadlet mit `EnvironmentFile=`; nftables-Konfig & ip_forward dokumentiert; wg-easy-allowedIPs-Limitation vermerkt; Umsetzungszustand-Tabellen & Implementation-Log ergänzt |
|
||||
| 1.2 | 2026-09-09 | Split-Tunneling konkretisiert: clientseitige AllowedIPs kommen aus Env-Variable `WG_ALLOWED_IPS` (Default `0.0.0.0/0` = Full-Tunnel!); `WG_ALLOWED_IPS` in `/opt/wg-easy/environment` gesetzt, Container neu gestartet, Env im Container verifiziert; Android-/24-Limitierung dokumentiert (nur `/32`-Einträge); Schritt 8 in „Konfig gesetzt / End-to-End offen“ zerlegt; `WG_PERSISTENT_KEEPALIVE`-Hinweis ergänzt |
|
||||
| 1.3 | 2026-09-09 | DNS-Korrektur: A-Record gehört beim **Domain-DNS-Anbieter** (nicht NPM/selfhost.eu-Portal – NPM ist nur HTTP-Proxy); Fritzbox-Portforward ✅ erledigt; WAN-IP `93.208.161.126` per `getent` verifiziert; Statisch/DynDNS-Check als offen vermerkt |
|
||||
| 1.4 | 2026-09-09 | DNS ✅ (Wildcard-DynDNS war bereits ausreichend; Redundanz-A-Record harmlos, Auflösung verifiziert); **zwei Client-Einrichtungsdocs** ergänzt (Linux/KDE, Windows 11) und im Header referenziert |
|
||||
| Punkt | erforderliche Klärung / Umsetzung |
|
||||
| --- | --- |
|
||||
| VPN-DynDNS | Am 18.09.2026 löste `vpn.ghostnet.selfhost.eu` zur ausgehenden Gateway-IPv4 `93.208.161.126` auf; `vpn.ghostnet.dyndns.eu` zeigte auf `83.169.40.234`. Profile nutzen den selfhost-Namen. Automatische Aktualisierung nach WAN-IP-Wechsel und tatsächliche Fritzbox-DynDNS-Einstellung noch prüfen. |
|
||||
| Vorhandene Peers | `Laptop-FullAdmin` (`10.8.0.2`) und `Android-LLMAdmin` (`10.8.0.3`) sind historisch. Laptop der neuen Familie-/Server-Admin-Rolle ausdrücklich zuordnen; Android bleibt außerhalb der neuen Client-SOPs. |
|
||||
| Gateway-Management | INPUT-Regeln für zugeordnete Familie-/Server-Admin-Peers ergänzen; lokale Zugangsgruppen festlegen. |
|
||||
| Per-Client Firewall | aktivieren, erzeugte Regeln samt Hooks prüfen, negative Tests und Wiederanlauf abnehmen. |
|
||||
| GUI-HTTPS | Hostname, Zertifikat und Namensauflösung entscheiden und implementieren. |
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
# Standard Operating Procedure
|
||||
|
||||
**Dokumenten-ID:** GNAI-006-SEC-SOP-01
|
||||
**Titel:** Clients in der wg-easy-GUI einrichten und verwalten
|
||||
**Status:** Betriebsverfahren dokumentiert; Rollen-Firewall noch nicht umgesetzt oder abgenommen
|
||||
**Referenzen:** [Gateway-Architektur](GNAI-006-SEC_VPN.md), [Rollenmodell](GNAI-004-SEC_Access-Control.md), [Windows](GNAI-006-SEC_VPN_Clients_Windows11.md), [Linux](GNAI-006-SEC_VPN_Clients_Linux.md)
|
||||
|
||||
## Änderungsverlauf
|
||||
|
||||
| Datum | Version | Autor | Änderung |
|
||||
| --- | --- | --- | --- |
|
||||
| 2026-09-15 | 1.0 | spektr | Eigenständige SOP für Rollenzuordnung, Profilausgabe, Änderung, Widerruf und Abnahme angelegt. |
|
||||
| 2026-09-18 | 1.1 | spektr | Offenen Umsetzungsstand der Rollen-Firewall, Gateway-INPUT-Regeln und negative Rollentests präzisiert. |
|
||||
|
||||
## 1. Zweck und Voraussetzungen
|
||||
|
||||
Administratoren erstellen, ändern, verteilen und widerrufen WireGuard-Profile. Nutzer erhalten ausschließlich ihr eigenes Geräteprofil und benötigen keinen Zugriff auf wg-easy. GUI-Zugang ist für Familie und Server Admins vorgesehen, LLM Admins erhalten keinen Zugang.
|
||||
|
||||
Benötigt werden ein Administratorlogin, Zugriff auf `http://10.0.0.15:51821` aus einem erlaubten Netz und ein aktuelles Serverinventar. Der dokumentierte Endpoint ist `vpn.ghostnet.selfhost.eu`; vor Profilausgabe seine DNS-Auflösung mit der aktuellen WAN-IP vergleichen. HTTPS ist geplant, noch nicht eingerichtet. Ein eigener Peer pro Gerät ermöglicht gezielten Widerruf.
|
||||
|
||||
Vor Rollenvergabe müssen Per-Client Firewall und Gateway-INPUT-Regeln nach der Architektur eingerichtet und geprüft werden. Der derzeitige Serverzustand bietet noch keine nachgewiesene Rollenisolierung. Diese SOP dokumentiert die Umstellung und den anschließenden Regelbetrieb; sie erklärt bestehende Peers nicht rückwirkend für sicher.
|
||||
|
||||
## 2. Rollenwerte festlegen
|
||||
|
||||
| Rolle | Allowed IPs im Profil | Firewall Allowed IPs auf dem Server | DNS |
|
||||
| --- | --- | --- | --- |
|
||||
| Familie | `10.0.0.0/24` | `10.0.0.0/24` | `10.0.0.1` |
|
||||
| Server Admin | freigegebene Server jeweils `/32` | dieselben Serveradressen ausdrücklich eintragen | zunächst leer / System-DNS |
|
||||
| LLM Admin | `10.0.0.90/32` | `10.0.0.90/32` | leer / System-DNS |
|
||||
|
||||
Für Server Admins enthält das Quelleninventar derzeit Proxmox `.2` sowie `.4`, `.10`, `.11`, `.12`, `.15`, `.17`, `.23`, `.47` und KI-Server `.90`. Vor Vergabe in Proxmox mit der tatsächlichen Belegung abgleichen. Beispiel nach bestätigtem Inventarabgleich:
|
||||
|
||||
```text
|
||||
10.0.0.2/32, 10.0.0.4/32, 10.0.0.10/32, 10.0.0.11/32, 10.0.0.12/32, 10.0.0.15/32, 10.0.0.17/32, 10.0.0.23/32, 10.0.0.47/32, 10.0.0.90/32
|
||||
```
|
||||
|
||||
Das ist eine Inventarliste, keine behauptete vollständige LXC-Erfassung. Neue Server einzeln ergänzen. Der geplante statische Bereich bis `.99` wird nicht automatisch freigegeben. Die Fritzbox `.1` ist keine implizite Server-Admin-Freigabe. DNS über die Fritzbox für diese Rolle benötigt eine separate Entscheidung und Freigabe, gegebenenfalls gezielt TCP/UDP 53.
|
||||
|
||||
Zugriff auf `10.8.0.1` oder andere VPN-Peers ist in diesen Basislisten nicht enthalten. Bei Bedarf gesondert beschließen und sowohl Routing als auch Firewall ergänzen. Familie hat mit `10.0.0.0/24` Zugriff auf Heimnetz-Clients, nicht automatisch auf sämtliche anderen VPN-Peers.
|
||||
|
||||
## 3. Einmalige Umstellung auf Per-Client Firewall
|
||||
|
||||
1. Vor Änderung konsistentes Backup und aktuelle Regeln sichern; Arbeiten über LAN/Proxmox-Konsole durchführen.
|
||||
2. Bestehende Peers, ihre VPN-IP, Gerät und Rolle erfassen. Der alte Name „FullAdmin“ unterscheidet Familie und Server Admin nicht. Unzugeordnete Peers deaktivieren.
|
||||
3. In **Admin Panel → Interface** **Per-Client Firewall** einschalten und speichern. Sichtbarkeit und Funktion im installierten v15.4.0 prüfen. Falls das Feld fehlt oder eine Fehlermeldung erscheint, nicht auf clientseitiges Routing als Ersatz ausweichen.
|
||||
4. Die zugeordneten Peers nacheinander bearbeiten und ausdrückliche **Firewall Allowed IPs** setzen. Die Fallback-Wirkung leerer Felder nicht als Rollenpolitik verwenden.
|
||||
5. Gateway-INPUT-Zugriff für Familie und Server Admin anhand der bestätigten VPN-IP-Zuordnung ergänzen. wg-easy-Port 51821 und SSH-Port 22 für LLM Admin prüfen und sperren; GUI-Einstellungen allein beweisen diese INPUT-Beschränkung nicht.
|
||||
6. Serverregeln und Hooks prüfen. Positive und negative Tests aus Abschnitt 7 ausführen. Erst danach Peers für die neue Rollenpolitik freigeben.
|
||||
|
||||
Die offizielle Dokumentation kennzeichnet Per-Client Firewall als experimentell; sie benötigt eine funktionierende iptables-Umgebung. [Admin Panel](https://wg-easy.github.io/wg-easy/latest/guides/admin/)
|
||||
|
||||
## 4. Neuen Geräteclient anlegen und Profil verteilen
|
||||
|
||||
1. In wg-easy anmelden und über die Funktion zum Hinzufügen eines Clients einen neuen Eintrag erstellen. Die konkrete Schaltflächenbeschriftung kann je nach Sprache abweichen.
|
||||
2. Einen eindeutigen Gerätenamen setzen und Besitzer, Rolle, Datum und Zweck im Peer-Verzeichnis erfassen. Kurze technische Profilnamen verwenden, beispielsweise `gnai-laptop`; Linux-Interface-Namen sind auf 15 Zeichen begrenzt.
|
||||
3. Den Eintrag bis zur abgeschlossenen Konfiguration deaktiviert halten. Falls die GUI das Anlegen nur aktiviert ermöglicht, direkt deaktivieren und noch kein Profil verteilen.
|
||||
4. Zugewiesene IPv4-Adresse im VPN-Netz prüfen: Server `.1`, Endgeräte eindeutige freie Adressen. Adressen bestehender Peers nicht versehentlich wiederverwenden.
|
||||
5. Client-Details öffnen. **Allowed IPs**, **Firewall Allowed IPs** und **DNS** gemäß Rolle setzen. **Server Allowed IPs** bei einem einfachen Endgerät auf dessen eigene VPN-IP `/32` belassen.
|
||||
6. Endpoint kontrollieren: `vpn.ghostnet.selfhost.eu`, UDP-Port `51820`, DNS-Abgleich mit aktueller WAN-IP. MTU zunächst beim geprüften Default belassen. Keepalive ist im Altbestand `0`; bei Bedarf für Geräte hinter NAT gezielt `25` Sekunden konfigurieren und testen.
|
||||
7. Client-Hooks leer lassen, damit das Profil auch in Windows und NetworkManager importierbar bleibt. Server-Hooks für NAT nicht mit diesen Client-Hooks verwechseln.
|
||||
8. Änderungen speichern. Über die Download-Funktion das aktualisierte `.conf` exportieren. Für die vorgesehenen Windows-/Linux-Verfahren wird die Datei verwendet.
|
||||
9. Lokal prüfen: eigene `Address`, richtiger Endpoint, rollenabhängige AllowedIPs/DNS, kein unbeabsichtigtes `0.0.0.0/0` oder `::/0`. PrivateKey und PresharedKey dabei nicht in Dokumente oder Nachrichten kopieren.
|
||||
10. Profil über einen geschützten, für den Empfänger bestimmten Kanal verteilen. Das Profil ist ein Zugangsschlüssel. Keine öffentlichen Links, gemeinsamen Ordner oder offenen E-Mail-/Chat-Verteiler verwenden.
|
||||
11. Peer kontrolliert aktivieren und mit dem Nutzer die Client-SOP und rollenabhängigen Abnahmen durchführen. Danach Status und Datum eintragen; ungeschützte Downloadkopien entfernen.
|
||||
|
||||
Die Unterscheidung von Routing, serverseitigen Zielrechten und Client-Hooks wird in der [offiziellen Feldreferenz](https://wg-easy.github.io/wg-easy/latest/guides/clients/) erläutert. Das Server-Firewallfeld ist kein Bestandteil des exportierten WireGuard-Profils.
|
||||
|
||||
## 5. Bestehenden Client ändern
|
||||
|
||||
Vor Änderung aktuelle Rolle und Freigaben erfassen. Bei Rollensenkung den Peer zunächst deaktivieren, Serverrechte einschränken und aktualisiertes Routingprofil verteilen; erst nach Prüfung wieder aktivieren. Änderungen an AllowedIPs, DNS, Endpoint, MTU oder Keepalive benötigen einen neuen Export und eine Aktualisierung auf dem Endgerät. Server-Firewalländerungen wirken serverseitig, werden aber ebenfalls getestet und dokumentiert.
|
||||
|
||||
Ein Serverneuzugang erweitert nur die Server-Admin-Profile, die diesen Host tatsächlich benötigen. Namen ändern widerruft keine Schlüssel. Änderungen an erzeugten `wg0.conf`-Dateien oder direkte SQLite-Manipulation gehören nicht zum Regelbetrieb.
|
||||
|
||||
## 6. Deaktivieren, löschen und Schlüssel ersetzen
|
||||
|
||||
**Temporäre Sperre:** Client über seinen Aktivierungsstatus deaktivieren. Prüfen, dass der Peer aus der aktiven Serverkonfiguration entfernt wurde und keine neue Verbindung mehr funktioniert. Reaktivieren nur nach Prüfung des Sperrgrunds.
|
||||
|
||||
**Geräteverlust oder vermutete Schlüsseloffenlegung:** Betroffenen Peer sofort deaktivieren bzw. löschen. Einen neuen Client mit neuen Schlüsseln erstellen, konfigurieren und verteilen. Ein neuer Dateiname oder erneuter Download desselben Peers ist keine Schlüsselrotation. Ein gesperrter oder gelöschter Peer wird nicht durch bloßes Entfernen der Datei auf dem Client widerrufen.
|
||||
|
||||
**Dauerhaft entfernen:** Besitzer informieren, Peer löschen, Inventar und Widerrufsliste aktualisieren, Clientprofil entfernen und alte Exporte vernichten. Keine vollständigen geheimen Profile zur Nachvollziehbarkeit archivieren. Nach Restore die Widerrufsliste anwenden.
|
||||
|
||||
## 7. Rollenprüfung und Betriebsabnahme
|
||||
|
||||
| Test | Familie | Server Admin | LLM Admin |
|
||||
| --- | --- | --- | --- |
|
||||
| KI-Server-Dienst auf `.90` | erlaubt | erlaubt | erlaubt |
|
||||
| Proxmox `10.0.0.2:8006` | erlaubt | erlaubt | gesperrt |
|
||||
| wg-easy `10.0.0.15:51821` | erlaubt | erlaubt | gesperrt |
|
||||
| NPM Admin `10.0.0.10:81` | erlaubt | erlaubt | gesperrt |
|
||||
| aktiver Heimnetz-PC im DHCP-Bereich | erlaubt, soweit Hostdienst freigegeben | gesperrt | gesperrt |
|
||||
| normales Internet | direkt | direkt | direkt |
|
||||
|
||||
Für Sperrtests die clientseitigen AllowedIPs bewusst um ein verbotenes Ziel ergänzen oder ein kontrolliertes Testprofil mit breiterem Routing nutzen. Derselbe Zielservice muss von einem erlaubten Peer erreichbar sein. Auf dem Gateway Regeln und Zähler kontrollieren; nur fehlendes Routing oder ein ausgeschalteter Zielhost sind kein Firewallnachweis. Testprofil danach zurückbauen.
|
||||
|
||||
Im Status prüfen: letzter Handshake und steigende Transferwerte unter erzeugtem Verkehr. Ein eingeschalteter Client allein beweist keine Verbindung. Vor der Produktionsabnahme auch Dienstneustart, Firewall-Reload und LXC-/Host-Wiederanlauf prüfen.
|
||||
|
||||
## 8. Nachweis und Abschluss
|
||||
|
||||
Pro Peer Besitzer, Gerät, neue Rolle, VPN-IP, Freigaben, Aktivierungsstatus, Ausgabedatum und Abnahme erfassen. PrivateKeys, PresharedKeys, GUI-Passwörter und QR-Codes nicht aufnehmen. Neue Rollen sind erst nach erfolgreicher serverseitiger Durchsetzung freigegeben. Die vorhandenen Altpeers und ihre neuen Rollen sind noch mit dem Betreiber abzugleichen.
|
||||
@@ -1,105 +1,168 @@
|
||||
# GNAI-006-SEC – VPN-Client-Einrichtung: Linux (KDE Plasma)
|
||||
# SOP – WireGuard unter Linux einrichten und verwenden
|
||||
|
||||
**Bezug:** GNAI-006-SEC_VPN.md (WireGuard-VPN-Gateway LXC 105)
|
||||
**Zielgruppe:** Benutzer (Laptop, z. B. CachyOS mit KDE Plasma)
|
||||
**Version:** 1.0 · 2026-09-09
|
||||
**Dokumenten-ID:** GNAI-006-SEC-SOP-03
|
||||
**Plattformen:** Debian, Arch/CachyOS und Fedora; Fedora Kinoite gesondert berücksichtigt
|
||||
**Status:** Anleitung bereinigt; bisheriger CachyOS-CLI-Test teilweise bestanden, übrige Varianten nicht abgenommen
|
||||
**Referenzen:** [Gateway](GNAI-006-SEC_VPN.md), [Profilverwaltung](GNAI-006-SEC_VPN_Client-Management.md)
|
||||
|
||||
---
|
||||
## Änderungsverlauf
|
||||
|
||||
## 1. Voraussetzungen
|
||||
| Datum | Version | Autor | Änderung |
|
||||
| --- | --- | --- | --- |
|
||||
| 2026-09-09 | 1.0 | spektr | Erste Clientanleitung für Linux mit KDE Plasma erstellt. |
|
||||
| 2026-09-15 | 2.0 | spektr | Debian, Arch/CachyOS, Fedora und Kinoite getrennt beschrieben; NetworkManager und wg-quick, Geheimnisschutz, Fehlersuche und belegten Teiltest überarbeitet. |
|
||||
|
||||
* WireGuard-Client-Paket installiert
|
||||
* Das eigene wg-easy-Profil (`.conf`) – s. Abschnitt 2
|
||||
## 1. Voraussetzungen und Begriffe
|
||||
|
||||
## 2. Profil aus der wg-easy-UI beziehen (einmalig)
|
||||
Du benötigst ein eigenes `.conf`-Profil vom Administrator, sudo-Berechtigung für die Einrichtung und Internetzugang. Der Administrator nennt deine Rolle und ein erreichbares Testziel. Du benötigst keine wg-easy-Anmeldung.
|
||||
|
||||
> ⚠️ Die UI ist **nur aus dem LAN** erreichbar (nftables). Beim ersten Setup also im Heimnetz (WLAN/LAN) bleiben.
|
||||
Das Profil enthält geheime Schlüssel: **PrivateKey und PresharedKey** dürfen nicht geteilt werden. PublicKeys sind öffentlich, die vollständige Datei ist dennoch geheim. Jeder Rechner verwendet einen eigenen Peer. Serverdienste verlangen weiterhin ihre eigene Anmeldung.
|
||||
|
||||
1. Browser öffnen → `http://10.0.0.15:51821`
|
||||
2. Passwort eingeben
|
||||
3. In der Client-Liste den eigenen Eintrag wählen (z. B. `Laptop-FullAdmin`)
|
||||
4. **`Download`** klicken → Datei `Laptop-FullAdmin.conf` wird heruntergeladen
|
||||
*(Alternativ: QR-Code auf dem Display mit dem Smartphone scannen – Android/KDE-kompatibel.)*
|
||||
Bei Split-Tunneling gehen nur freigegebene Ziele durch WireGuard, normale Internetverbindungen bleiben direkt. Wähle **eine** der Methoden: NetworkManager oder wg-quick. Beide dürfen dasselbe Profil nicht gleichzeitig aktivieren.
|
||||
|
||||
Die Datei enthält alles Notwendige:
|
||||
## 2. Software bereitstellen
|
||||
|
||||
```ini
|
||||
[Interface]
|
||||
PrivateKey = … # nur die eigenen – NICHT weitergeben
|
||||
Address = 10.8.0.2/32
|
||||
DNS = 10.0.0.1 # Fritzbox als Resolver
|
||||
|
||||
[Peer]
|
||||
PublicKey = …
|
||||
PresharedKey = …
|
||||
Endpoint = vpn.ghostnet.selfhost.eu:51820
|
||||
AllowedIPs = 10.0.0.0/24, 10.8.0.0/24, …
|
||||
```
|
||||
|
||||
**Nur der Abschnitt `[Interface]` (PrivateKey!) ist privat** – `PublicKey`/`PresharedKey` dürfen geteilt werden, `PrivateKey` niemals.
|
||||
|
||||
## 3. WireGuard installieren (CachyOS)
|
||||
|
||||
```bash
|
||||
sudo pacman -S wireguard-dkms wireguard-tools
|
||||
```
|
||||
|
||||
* DKMS baut das WireGuard-Kernelmodul für den jeweils laufenden Kernel (CachyOS wechselt Kernel häufig – DKMS verhindert, dass nach einem Kernel-Update das Modul fehlt).
|
||||
* Prüfen: `lsmod | grep wireguard`
|
||||
|
||||
## 4. Profil importieren
|
||||
|
||||
### Variante A – KDE-Systemtray (empfohlen)
|
||||
|
||||
1. Oben rechts in der Taskleiste → **Systemtray-Icon** (kleines WLAN/Schild-Symbol) – erscheint nach Installation von `wireguard-tools` + `plasma-workspace` (bzw. `plasma-vault`-unabhängig, Teil der Standard-KDE-Pakete).
|
||||
2. Rechtsklick auf das Icon → **„New from file…“** → die `.conf` wählen.
|
||||
3. Eintrag erscheint in der Liste → Rechtsklick → **„Connect“**.
|
||||
|
||||
### Variante B – `wg-quick` (Konsole / Autostart)
|
||||
|
||||
```bash
|
||||
# Profil in das Konfigurationsverzeichnis legen
|
||||
install -m 600 ~/Downloads/Laptop-FullAdmin.conf /etc/wireguard/
|
||||
|
||||
# Verbindung starten (ohne root)
|
||||
sudo wg-quick up wg0
|
||||
|
||||
# Status
|
||||
wg show wg0
|
||||
|
||||
# Verbinden getrennt
|
||||
sudo wg-quick down wg0
|
||||
```
|
||||
|
||||
**Autostart (optional):** `/etc/wireguard/wg0.conf` mit `[Interface] PrivateKey=…` vorhanden → `sudo systemctl enable wg-quick@wg0`.
|
||||
|
||||
## 5. Verifikation
|
||||
|
||||
```bash
|
||||
ip -br addr show wg0 # wg0 UP, 10.8.0.2/32
|
||||
ping -c 3 10.8.0.1 # VPN-Gateway (muss funktionieren)
|
||||
ping -c 3 10.0.0.2 # Proxmox – LAN via Tunnel
|
||||
ping -c 3 10.0.0.90 # LLM-Server – LAN via Tunnel
|
||||
curl -s ifconfig.co # eigene ÖFFENTLICHE IP (Nicht-LAN: muss die WAN-IP des Providers sein, NIE 10.0.0.x)
|
||||
```
|
||||
|
||||
**Erwartet (Split-Tunneling):**
|
||||
* LAN-Hosts (`10.0.0.0/24`) → **über den VPN-Tunnel**
|
||||
* Alles andere (Internet) → **direkt** (Nicht-LAN: Provider-NAT)
|
||||
* `curl ifconfig.co` zeigt deine **normale** Außen-IP – **nicht** eine VPN-IP
|
||||
|
||||
## 6. Fehlersuche
|
||||
|
||||
| Symptom | Ursache / Lösung |
|
||||
| Distribution | Installation der WireGuard-Werkzeuge |
|
||||
| --- | --- |
|
||||
| „No handshake yet“ nach 30 s | (1) LAN: `http://10.0.0.15:51821` erreichbar? (2) Nicht-LAN: DNS von `vpn.ghostnet.selfhost.eu` auflösen (`nslookup vpn.ghostnet.selfhost.eu` → muss `93.208.161.126` zeigen); Fritzbox-Portforward UDP 51820 aktiv? |
|
||||
| `wg-quick` meldet `WireGuard kernel module not loaded` | `sudo modprobe wireguard` (DKMS nicht installiert oder Kernel-Update → `sudo pacman -S wireguard-dkms`) |
|
||||
| LAN-Ping funktioniert, `curl ifconfig.co` zeigt VPN-IP | Client ist (fälschlich) im Full-Tunnel-Modus → `AllowedIPs` in der `.conf` prüfen – muss **nur** `10.0.0.0/24,10.8.0.0/24,…` sein, **nicht** `0.0.0.0/0` |
|
||||
| `Permission denied` bei `wg-quick up` | `sudo` vergessen (oder: `sudo usermod -aG wheel $USER` + `sudo /usr/bin/setfacl -m u:$USER:rw /etc/wireguard/wg0.conf` für rootless) |
|
||||
| KDE-Icon fehlt | `plasma-workspace`-Paket installiert; Systemtray neu starten: `plasmashell --replace` |
|
||||
| Debian | `sudo apt update`, anschließend `sudo apt install wireguard-tools` |
|
||||
| Arch / CachyOS | `sudo pacman -S wireguard-tools` |
|
||||
| Fedora, klassisch | `sudo dnf install wireguard-tools` |
|
||||
| Fedora Kinoite | falls Werkzeuge fehlen: `sudo rpm-ostree install wireguard-tools`, anschließend in die neue Deployment-Version neu starten |
|
||||
|
||||
## 7. Sicherheitshinweise
|
||||
Die offiziellen Distributionsbefehle stehen auf der [WireGuard-Installationsseite](https://www.wireguard.com/install/). Aktuelle Standardkernel dieser Distributionen unterstützen WireGuard; bei angepassten Kerneln muss der Administrator dies prüfen. DKMS nicht pauschal installieren.
|
||||
|
||||
* **Niemals** den PrivateKey aus der `.conf` in einen Chat/Die-Cloud/Chat-Verlauf stellen.
|
||||
* `.conf` mit `chmod 600` (`install -m 600` s. oben) – kein World-Readable.
|
||||
* Bei Verdacht auf Kompromittierung: in der wg-easy-UI Client **deaktivieren** (Toggle) oder **delete** – der Server erkennt den Key nicht mehr an.
|
||||
Für NetworkManager muss dessen Dienst vorhanden und aktiv sein; auf KDE wird die Netzwerkoberfläche durch `plasma-nm` bereitgestellt, nicht durch ein automatisch von wireguard-tools erzeugtes Tray-Icon. Desktop-Installationen bringen das häufig bereits mit:
|
||||
|
||||
```bash
|
||||
nmcli --version
|
||||
systemctl is-active NetworkManager
|
||||
```
|
||||
|
||||
Wenn NetworkManager fehlt, klärt der Administrator zunächst, welcher Dienst dein Netzwerk verwaltet. Auf einem Debian-Server nicht parallel zur vorhandenen ifupdown-Konfiguration blind einen weiteren Netzwerkmanager einschalten.
|
||||
|
||||
## 3. Profilname und Aufbewahrung
|
||||
|
||||
Für diese Anleitung heißt die lokale Datei `gnai-laptop.conf`. Vom Administrator anders benannte Dateien gegebenenfalls im Dateimanager umbenennen. Der tatsächliche Name muss bei folgenden Befehlen passen. Linux-wg-quick verwendet den Dateinamen ohne `.conf` als Interface-Namen, **ohne `wg-`-Präfix**, maximal 15 Zeichen. [wg-quick-Implementierung](https://git.zx2c4.com/wireguard-tools/tree/src/wg-quick/linux.bash)
|
||||
|
||||
```bash
|
||||
chmod 600 "$HOME/Downloads/gnai-laptop.conf"
|
||||
```
|
||||
|
||||
## 4. Methode A: NetworkManager und Desktop
|
||||
|
||||
Für Desktop-Nutzer eignet sich die bestehende NetworkManager-Verwaltung. Unter KDE **Systemeinstellungen → Verbindungen** öffnen und die Funktion zum Importieren einer Verbindung verwenden, sofern deine Version WireGuard-Dateiimport anbietet. Wenn die Oberfläche diese Funktion nicht anbietet, ist der folgende Import eindeutig; danach erscheint die Verbindung in der Desktop-Netzwerkverwaltung:
|
||||
|
||||
```bash
|
||||
sudo nmcli connection import type wireguard file "$HOME/Downloads/gnai-laptop.conf"
|
||||
nmcli connection show
|
||||
```
|
||||
|
||||
Den beim Import gemeldeten Verbindungsnamen verwenden. Bei abweichendem Namen in folgenden Befehlen `gnai-laptop` ersetzen:
|
||||
|
||||
```bash
|
||||
sudo nmcli connection modify gnai-laptop connection.autoconnect no
|
||||
sudo nmcli connection up gnai-laptop
|
||||
nmcli connection show --active
|
||||
ip -br addr
|
||||
```
|
||||
|
||||
Zum Trennen:
|
||||
|
||||
```bash
|
||||
sudo nmcli connection down gnai-laptop
|
||||
```
|
||||
|
||||
Alternativ über die Desktop-Netzwerkverwaltung verbinden/trennen. Verbindung erst nach Absprache automatisch starten lassen; Autoconnect-Verhalten wird beim Import nicht vorausgesetzt. NetworkManager speichert das Profil in seiner eigenen Verwaltung; die Downloaddatei ist danach nur eine zusätzliche Geheimniskopie. [NetworkManager-CLI](https://networkmanager.dev/docs/api/latest/nmcli.html)
|
||||
|
||||
## 5. Methode B: wg-quick, Terminal und systemd
|
||||
|
||||
Diese Methode verwendet die Datei `/etc/wireguard/gnai-laptop.conf`. Nur verwenden, wenn Methode A für dieses Profil nicht aktiv ist:
|
||||
|
||||
```bash
|
||||
sudo install -d -m 700 /etc/wireguard
|
||||
sudo install -m 600 "$HOME/Downloads/gnai-laptop.conf" /etc/wireguard/gnai-laptop.conf
|
||||
sudo wg-quick up gnai-laptop
|
||||
sudo wg show gnai-laptop
|
||||
ip -br addr show gnai-laptop
|
||||
```
|
||||
|
||||
Erwartet: Interface `gnai-laptop`, eigene Adresse `10.8.0.x`, ein Handshake nach Verkehr zu einem freigegebenen Ziel. Nicht pauschal `wg0` abfragen; das ist der Interface-Name auf dem Server.
|
||||
|
||||
**DNS-Abhängigkeit:** Wenn das Profil `DNS = ...` enthält, ruft Linux-wg-quick `resolvconf` auf. Vorher prüfen:
|
||||
|
||||
```bash
|
||||
command -v resolvconf
|
||||
```
|
||||
|
||||
Bei fehlendem Befehl nicht die DNS-Zeile ungeprüft entfernen. Der Administrator installiert eine zum vorhandenen Resolver passende resolvconf-Implementierung oder nutzt NetworkManager. Debian/Arch/Fedora verwenden nicht in jeder Installation denselben Resolver; deshalb wird kein pauschaler Paketwechsel vorgeschrieben. Profile mit leerem DNS-Feld verwenden System-DNS.
|
||||
|
||||
Zum Trennen:
|
||||
|
||||
```bash
|
||||
sudo wg-quick down gnai-laptop
|
||||
```
|
||||
|
||||
Optionaler Autostart, erst nach erfolgreicher Prüfung und Absprache:
|
||||
|
||||
```bash
|
||||
sudo systemctl enable wg-quick@gnai-laptop.service
|
||||
```
|
||||
|
||||
Dies richtet den Bootstart ein. Für systemd-Verwaltung nach einem manuellen `wg-quick down`:
|
||||
|
||||
```bash
|
||||
sudo systemctl start wg-quick@gnai-laptop.service
|
||||
sudo systemctl status wg-quick@gnai-laptop.service
|
||||
```
|
||||
|
||||
Autostart entfernen und systemd-verwaltete Verbindung stoppen:
|
||||
|
||||
```bash
|
||||
sudo systemctl disable --now wg-quick@gnai-laptop.service
|
||||
```
|
||||
|
||||
## 6. Verbindung prüfen
|
||||
|
||||
Die erste Abnahme von einem fremden Netz ausführen, beispielsweise Smartphone-Hotspot. Zuerst einen tatsächlich freigegebenen Dienst aufrufen:
|
||||
|
||||
| Rolle | Testziel |
|
||||
| --- | --- |
|
||||
| Familie | Proxmox `https://10.0.0.2:8006` und ein bekannter Heimnetz-PC |
|
||||
| Server Admin | Proxmox oder bekannter freigegebener LXC-Dienst |
|
||||
| LLM Admin | bekannter Dienst auf `10.0.0.90`, gegebenenfalls SSH mit eigenem SSH-Key |
|
||||
|
||||
Ein Ping ist ergänzend möglich, aber Host-Firewalls können ihn sperren. Ein ausgeschalteter KI-Server ist kein geeignetes Testziel. `10.8.0.1` ist nur dann ein Testziel, wenn der Administrator Zugriff darauf ausdrücklich freigegeben hat.
|
||||
|
||||
```bash
|
||||
ip -4 route get 10.0.0.90
|
||||
sudo wg show
|
||||
```
|
||||
|
||||
Der Routenbefehl ist für Rollen geeignet, denen `.90` freigegeben wurde. Für Rollenprüfungen am Server reicht fehlendes Client-Routing nicht als Sperrnachweis.
|
||||
|
||||
Öffentliche IPv4-Adresse vor und nach der Aktivierung im selben fremden Netz vergleichen:
|
||||
|
||||
```bash
|
||||
curl -4 https://ifconfig.co/ip
|
||||
```
|
||||
|
||||
Erwartet: Außenadresse des verwendeten Netzes bleibt gleich, normale Internetnutzung bleibt direkt. `-4` erzwingt einen IPv4-Test. Ein direkter IPv6-Internetpfad ist im vorgesehenen IPv4-Split-Tunnel keine zusätzliche VPN-Route. Bei Internetproblemen auch DNS prüfen: DNS kann über das VPN laufen, obwohl der übrige Internetverkehr direkt bleibt.
|
||||
|
||||
## 7. Fehlersuche
|
||||
|
||||
| Symptom | nächster Schritt |
|
||||
| --- | --- |
|
||||
| Datei nicht gefunden / ungültiger Interface-Name | Pfad, `.conf`-Endung und maximal 15 Zeichen im Basisnamen prüfen |
|
||||
| kein Handshake | Internet prüfen, erlaubtes Ziel aufrufen; Administrator kontrolliert tatsächlichen Endpoint-DNS und UDP-Weiterleitung |
|
||||
| Handshake, aber Dienst unerreichbar | Zielstatus, Rolle, Routen, Server-Firewall und NAT vom Administrator prüfen lassen |
|
||||
| `resolvconf: command not found` | bei wg-quick DNS-Abhängigkeit aus Abschnitt 5 klären |
|
||||
| `Operation not permitted` | sudo bzw. Systemrechte prüfen; Datei-ACLs oder Gruppenzugehörigkeit ersetzen keine benötigten Netzwerkprivilegien |
|
||||
| Interface bereits vorhanden | andere Verwaltung oder zweite Aktivierung desselben Profils prüfen; Methoden nicht mischen |
|
||||
| KDE-Verbindung fehlt | NetworkManager und plasma-nm sowie Import prüfen; kein pauschaler Plasma-Neustart erforderlich |
|
||||
| fremdes Netz verwendet ebenfalls `10.0.0.0/24` | Adressüberschneidung melden und über anderes Netz gegenprüfen |
|
||||
|
||||
Bei neuem Profil erst die alte Verbindung trennen. Bei NetworkManager nach Absprache den alten Eintrag entfernen und neu importieren; bei wg-quick Datei geschützt ersetzen und wieder starten. Exporte nicht unter offen lesbaren Pfaden belassen. Geräteverlust oder Offenlegung sofort melden, damit der Administrator den Peer serverseitig widerruft.
|
||||
|
||||
## 8. Abnahmestand
|
||||
|
||||
Am 12.09.2026 wurde ein CachyOS-Laptop mit wg-quick von außerhalb des Heimnetzes getestet: Handshake, Ping auf das VPN-Gateway und Proxmox sowie direkter IPv4-Internetpfad bestanden. KI-Server war ausgeschaltet. Dieser historische Test bestätigt weder NetworkManager-/Fedora-/Debian-Verfahren noch die neue Rollen-Firewall; diese Abnahmen stehen aus.
|
||||
|
||||
@@ -1,86 +1,95 @@
|
||||
# GNAI-006-SEC – VPN-Client-Einrichtung: Windows 11
|
||||
# SOP – WireGuard unter Windows 11 einrichten und verwenden
|
||||
|
||||
**Bezug:** GNAI-006-SEC_VPN.md (WireGuard-VPN-Gateway LXC 105)
|
||||
**Zielgruppe:** Benutzer (Windows 11)
|
||||
**Version:** 1.0 · 2026-09-09
|
||||
**Dokumenten-ID:** GNAI-006-SEC-SOP-02
|
||||
**Status:** Anleitung bereinigt; Windows-Praxistest noch offen
|
||||
**Referenzen:** [Gateway](GNAI-006-SEC_VPN.md), [Profilverwaltung für Administratoren](GNAI-006-SEC_VPN_Client-Management.md)
|
||||
|
||||
> Windows 11 nutzt WireGuard über den **integrierten WireGuard-Treiber** (Hyper-V-basiert). Es braucht **kein** extra Kernelmodul – es reicht die Desktop-App.
|
||||
## Änderungsverlauf
|
||||
|
||||
---
|
||||
| Datum | Version | Autor | Änderung |
|
||||
| --- | --- | --- | --- |
|
||||
| 2026-09-09 | 1.0 | spektr | Erste Clientanleitung für Windows 11 erstellt. |
|
||||
| 2026-09-15 | 2.0 | spektr | Installation, Profilimport, Split-Tunneling, Geheimnisschutz, Fehlersuche und noch offene Praxisabnahme überarbeitet. |
|
||||
|
||||
## 1. WireGuard-App installieren
|
||||
## 1. Was du benötigst
|
||||
|
||||
### Variante A – Microsoft Store (empfohlen)
|
||||
WireGuard verbindet deinen Rechner mit den für dich freigegebenen Geräten im Heimnetz. Es ersetzt weder Windows-Anmeldungen noch SSH-Schlüssel oder Passwörter für Serverdienste. Normale Internetverbindungen bleiben bei diesem Projekt außerhalb des VPN-Tunnels; das heißt Split-Tunneling.
|
||||
|
||||
1. **Microsoft Store** öffnen → Suche: **WireGuard**
|
||||
2. Veröffentlicher: **WireGuard** (wireguard.com) → **Installieren**
|
||||
3. App startet leer („No connections“)
|
||||
Du benötigst Windows 11, Administratorrechte für die Installation, Internetzugang und eine eigene `.conf`-Datei vom Administrator. Der Administrator nennt dir deine Rolle und ein erreichbares Testziel. Du meldest dich zum Beziehen des Profils nicht an der wg-easy-Verwaltungsoberfläche an.
|
||||
|
||||
### Variante B – Installer (GitHub-Release)
|
||||
Jedes Gerät erhält ein eigenes Profil. Die Datei enthält den PrivateKey und gegebenenfalls einen PresharedKey. Beide sind geheim; behandle die vollständige Datei wie ein Passwort. Lege sie nicht in öffentlichen oder gemeinsam genutzten Ordnern ab.
|
||||
|
||||
1. <https://www.wireguard.com/install/> → **Windows** → `wireguard-x.x.x-amd64.msi`
|
||||
2. Installieren (Admin-Prompt bestätigen)
|
||||
## 2. Offiziellen Client installieren
|
||||
|
||||
## 2. Profil aus der wg-easy-UI beziehen (einmalig)
|
||||
1. [WireGuard-Installationsseite](https://www.wireguard.com/install/) öffnen und den **Windows Installer** herunterladen.
|
||||
2. Installer ausführen und die Windows-Rückfrage zu Administratorrechten bestätigen.
|
||||
3. WireGuard öffnen. Der Installer installiert auch den benötigten WireGuardNT-Treiber. Hyper-V oder ein angebliches optionales „Windows Internal WireGuard“-Feature sind nicht erforderlich. [Offizieller Windows-Client](https://github.com/WireGuard/wireguard-windows/blob/master/README.md)
|
||||
|
||||
> ⚠️ Die UI ist **nur aus dem LAN** erreichbar. Beim ersten Setup also im Heimnetz.
|
||||
## 3. Eigenes Profil importieren
|
||||
|
||||
1. Browser → `http://10.0.0.15:51821` → Passwort
|
||||
2. Eigene Client-Karte (z. B. `Laptop-FullAdmin`) → **`Download`** → `.conf` wird gespeichert
|
||||
1. Vom Administrator erhaltene Profil-Datei lokal in deinem persönlichen Benutzerordner speichern. Als kurzen Namen beispielsweise `gnai-laptop.conf` verwenden; Dateiendung `.conf` beibehalten.
|
||||
2. WireGuard öffnen und **Tunnel hinzufügen → Tunnel aus Datei importieren** wählen; englisch **Add Tunnel → Import tunnel(s) from file**.
|
||||
3. Deine `.conf` auswählen. Der Tunnel erscheint in der Liste.
|
||||
4. Den Eintrag auswählen. Name und freigegebene Zielnetze mit den Angaben des Administrators abgleichen. Schlüssel nicht in Screenshots oder Supportnachrichten zeigen.
|
||||
|
||||
**Profil in die App importieren:**
|
||||
Falls beim Import ein Fehler erscheint, den genauen Fehlertext und die Clientversion an den Administrator geben; keine vollständige Profil-Datei in einen offenen Chat kopieren. Eine neue Datei vom Administrator kann eine ältere importierte Verbindung ersetzen; dafür den alten Tunnel zuerst deaktivieren und nach Absprache entfernen.
|
||||
|
||||
1. WireGuard-App starten → **„+“** (oben rechts) → **„Import from file…“**
|
||||
2. Die heruntergeladene `.conf` wählen → Eintrag erscheint in der Verbindungsliste
|
||||
## 4. Verbinden und trennen
|
||||
|
||||
*(Alternativ: QR-Code aus der UI mit dem Telefon scannen → in WireGuard auf dem Telefon; für Windows nur File-Import.)*
|
||||
1. Für die erste Prüfung ein anderes Netz verwenden, etwa einen Smartphone-Hotspot. Ein Test im eigenen Heimnetz beweist keinen funktionierenden Fernzugriff.
|
||||
2. Tunnel in WireGuard auswählen und **Aktivieren / Activate** anklicken.
|
||||
3. Ein freigegebenes Ziel aufrufen. Die Verbindung erzeugt dann Verkehr; anschließend sollten ein aktueller Handshake und steigende Transferwerte angezeigt werden.
|
||||
4. Zum Trennen **Deaktivieren / Deactivate** anklicken.
|
||||
|
||||
## 3. Verbinden
|
||||
„Aktiv“ bedeutet zunächst, dass der lokale Tunnel eingeschaltet ist. Erst erfolgreicher Verkehr zu einem erlaubten Ziel bzw. ein Handshake beweist die VPN-Verbindung. WireGuard benötigt keinen besonderen Schildindikator im Windows-Netzwerksymbol.
|
||||
|
||||
1. In der App den Eintrag anklicken (z. B. `Laptop-FullAdmin`)
|
||||
2. **„Start“** (grüner Schalter)
|
||||
3. Taskleiste unten rechts: **Netzwerk-Icon** zeigt ein kleines **WireGuard-Schild** → verbunden
|
||||
4. Nach 2–5 s steht die Tunnel-IP `10.8.0.x/32` (s. Status unter „Verbinden“)
|
||||
## 5. Verbindung prüfen
|
||||
|
||||
## 4. Verifikation
|
||||
| Rolle | geeigneter Test | erwartetes Verhalten |
|
||||
| --- | --- | --- |
|
||||
| Familie | `https://10.0.0.2:8006` und ein vom Administrator genannter Heimnetz-PC | freigegebene Dienste erreichbar |
|
||||
| Server Admin | `https://10.0.0.2:8006` oder ein bekannter LXC-Dienst | Server erreichbar; gewöhnliche Heimnetz-PCs nicht freigegeben |
|
||||
| LLM Admin | vom Administrator genannter Dienst auf `10.0.0.90` | KI-Server erreichbar; Proxmox/NPM/wg-easy nicht freigegeben |
|
||||
|
||||
**PowerShell:**
|
||||
Ein Zertifikatshinweis bei einer Server-IP ist getrennt vom VPN zu behandeln: den Fingerprint bzw. vorgesehenen Hostnamen beim Administrator verifizieren, nicht wahllos Ausnahmen bestätigen. Ein fehlender Ping kann an einer Host-Firewall liegen; ein ausgeschalteter Server ist kein VPN-Testziel.
|
||||
|
||||
Optional in PowerShell, am Beispiel eines vom Administrator freigegebenen SSH-Ziels:
|
||||
|
||||
```powershell
|
||||
# 1. Tunnel-IP
|
||||
Get-NetIPAddress -InterfaceAlias "Laptop-FullAdmin" | Select-Object IPAddress
|
||||
# erwartet: 10.8.0.2 (oder .3)
|
||||
|
||||
# 2. LAN via Tunnel
|
||||
ping 10.8.0.1 # VPN-Gateway
|
||||
ping 10.0.0.2 # Proxmox
|
||||
ping 10.0.0.90 # LLM-Server
|
||||
|
||||
# 3. Außen-IP (muss die NORMALE Provider-IP sein, nicht 10.0.0.x)
|
||||
Invoke-RestMethod "https://ifconfig.co"
|
||||
Test-NetConnection -ComputerName 10.0.0.90 -Port 22
|
||||
Get-NetIPAddress -AddressFamily IPv4 |
|
||||
Where-Object { $_.IPAddress -like '10.8.0.*' }
|
||||
```
|
||||
|
||||
**Split-Tunneling-Erwartung:**
|
||||
* `10.0.0.0/24` + `10.8.0.0/24` → **Tunnel**
|
||||
* Internet (alles andere) → **direkt**, Außen-IP = deine normale WAN-IP
|
||||
Für den Split-Tunnel-Test die öffentliche IPv4-Adresse vor und nach dem Aktivieren im **gleichen fremden Netz** vergleichen:
|
||||
|
||||
## 5. Fehlersuche
|
||||
```powershell
|
||||
curl.exe -4 https://ifconfig.co/ip
|
||||
```
|
||||
|
||||
| Symptom | Ursache / Lösung |
|
||||
Sie soll weiterhin die Außenadresse des verwendeten Netzes anzeigen. Eine private `10.0.0.x`-Adresse wird von einem öffentlichen IP-Abfragedienst ohnehin nicht angezeigt. Ein Wechsel auf die öffentliche Heimnetz-Adresse wäre ein Hinweis auf unerwartetes Full-Tunnel-Routing. Während des Vergleichs nicht zwischen WLAN und Mobilfunk wechseln.
|
||||
|
||||
Die technische Rollenisolierung wird vom Administrator zusätzlich mit absichtlich verändertem Client-Routing geprüft. Ein bei dir fehlender Routeneintrag allein beweist keine serverseitige Sperre.
|
||||
|
||||
## 6. Alltag und Netzwerkwechsel
|
||||
|
||||
Ein aktivierter Tunnel läuft als Windows-Tunneldienst; das Schließen des GUI-Fensters ist nicht dasselbe wie Deaktivieren. Nach einem Neustart und nach Netzwechsel den tatsächlichen Tunnelzustand prüfen. Ein automatischer Start wird nur nach Absprache eingerichtet und separat getestet; diese SOP setzt keinen erfundenen GUI-Autostartschalter voraus.
|
||||
|
||||
Bei einem Netzwerkwechsel kurz warten und Verkehr zu einem erlaubten Ziel erzeugen. Bleibt die Verbindung aus, einmal deaktivieren und aktivieren. Gleichzeitige weitere VPN-Clients können Routen oder DNS verändern; dem Administrator deren Namen nennen.
|
||||
|
||||
## 7. Fehlersuche und Sicherheit
|
||||
|
||||
| Symptom | nächster Schritt |
|
||||
| --- | --- |
|
||||
| „No handshake yet“ nach 30 s | (1) Im LAN? (UI erreichbar `http://10.0.0.15:51821`) (2) Nicht-LAN: `nslookup vpn.ghostnet.selfhost.eu` → muss auf WAN-IP zeigen; Fritzbox-Forward UDP 51820 aktiv? |
|
||||
| App meldet `No WireGuard adapter found` | Windows 11 nutzt den integrierten WireGuard-Treiber – kein extra Setup nötig. Prüfen: *Einstellungen → Apps → Optionalle Features* → „Windows-Hyper-V-Plattform“ / „Windows Internal WireGuard“ aktiv. Fehlt es → Feature aktivieren (Admin) → Neustart. |
|
||||
| Ping ins LAN klappt, aber `Invoke-RestMethod ifconfig.co` zeigt VPN-IP | `AllowedIPs` in der `.conf` ist `0.0.0.0/0` (Full-Tunnel) → neu aus UI herunterladen (wg-easy-Env `WG_ALLOWED_IPS` muss gesetzt sein, s. GNAI-006) |
|
||||
| „Access is denied“ beim Start | App als Administrator starten (Einmalig) oder Firewall-Einstellung prüfen: Windows Firewall blockiert gelegentlich ausgehende UDP 51820 → Ausnahme hinzufügen. |
|
||||
| VPN-Icon in der Taskleiste fehlt | Taskleiste rechts → Pfeil → „WireGuard“ → **pinnen** (Rechtsklick → „Auf Taskleiste pinnen“) |
|
||||
| kein Handshake | Internetzugang prüfen, Tunnel neu aktivieren; Administrator prüft Endpoint-DNS und UDP-Portweiterleitung |
|
||||
| Handshake vorhanden, Dienst nicht erreichbar | richtige Rolle, Ziel-IP, Port und Serverzustand mit Administrator prüfen |
|
||||
| Internet funktioniert, interne Namen nicht | DNS-Verhalten melden; ohne ausdrückliche DNS-Freigabe System-DNS verwenden |
|
||||
| Import-/Treiberfehler | offiziellen Installer reparieren bzw. neu installieren; Fehlertext melden, kein Hyper-V-Feature aktivieren |
|
||||
| Aktivierung verweigert | Windows-Berechtigungen prüfen lassen; Firewall nicht pauschal deaktivieren |
|
||||
| fremdes WLAN nutzt ebenfalls `10.0.0.0/24` | mögliche Adressüberschneidung melden und etwa per Hotspot gegenprüfen; Routen nicht auf Verdacht ändern |
|
||||
|
||||
## 6. Autostart / Verhalten bei Netzwerkwechsel
|
||||
Nach erfolgreichem Import ungeschützte Downloadkopien löschen. Unterstützte interne Profilspeicherung ersetzt keine Rechteprüfung für eigene Backups. Bei Geräteverlust oder Profiloffenlegung sofort den Administrator informieren; nur serverseitiger Widerruf sperrt den Zugang zuverlässig. [Windows-Dienstmodell](https://github.com/WireGuard/wireguard-windows/blob/master/docs/enterprise.md)
|
||||
|
||||
* **Standard:** Verbindung bleibt aktiv, wechselt mit dem Netzwerk (WAN-Wechsel = kurzer Datenverlust, dann Re-Handshake).
|
||||
* **Autostart bei Login:** WireGuard-App → Einstellungen (Zahnrad) → „Start automatically at login“ (falls verfügbar; in älteren Builds: `shell:startup` mit `wireguard.exe --startup` – **empfohlen: Store-Version**).
|
||||
## 8. Abnahme
|
||||
|
||||
## 7. Sicherheitshinweise
|
||||
|
||||
* **Niemals** den `[Interface]`-Abschnitt der `.conf` (PrivateKey) teilen, per E-Mail/Chat/Kopie.
|
||||
* `.conf` auf dem Rechner mit NTFS-Berechtigungen schützen (Standard-User-Ordner = `Users\<du>\Downloads` – genügt für Einzelplatz; bei Mehrbenutzer-Rechner unter `C:\Users\Public` **nicht** ablegen).
|
||||
* Bei Verdacht auf Kompromittierung: wg-easy-UI → Client deaktivieren/löschen → neu erzeugen (alter Key wird dann nie mehr akzeptiert).
|
||||
Administrator und Nutzer dokumentieren Profilname, Gerät, Rolle, Datum, fremdes Testnetz, Handshake, erreichbaren Dienst und Split-Tunnel-Ergebnis. PrivateKey und PresharedKey bleiben aus dem Nachweis ausgeschlossen. Für Windows liegt bislang kein praktischer Abnahmenachweis vor.
|
||||
|
||||
@@ -1,147 +1,138 @@
|
||||
# GNAI-006-SEC – Implementation-Log
|
||||
|
||||
**Bezug:** GNAI-006-SEC_VPN.md
|
||||
**Session:** 2026-09-09 (Agent-Session, Arbeit per SSH auf LXC 105)
|
||||
**Letzte Aktualisierung:** 2026-09-09 17:15 – Fritzbox-Portforward ✅; DNS-Korrektur (A-Record beim Domain-DNS-Anbieter, nicht NPM); WAN-IP `93.208.161.126` verifiziert; O1/O2 aktualisiert
|
||||
**Zweck:** Nachvollziehbare Dokumentation der Umsetzungsschritte, Abweichungen vom Draft, technischen Befunde und Fehlerbehebungen.
|
||||
**Dokumenten-ID:** GNAI-006-SEC-SOP-04
|
||||
**Bezug:** [Gateway-Architektur](GNAI-006-SEC_VPN.md)
|
||||
**Zweck:** Historische Umsetzung, Korrekturen an früheren Befunden und noch offene Abnahmen nachvollziehbar halten.
|
||||
|
||||
---
|
||||
## Änderungsverlauf
|
||||
|
||||
## 1. erledigte Schritte
|
||||
| Datum | Version | Autor | Änderung |
|
||||
| --- | --- | --- | --- |
|
||||
| 2026-09-09 | 1.x | spektr | ursprüngliches Aufbau- und Testprotokoll |
|
||||
| 2026-09-15 | 2.0 | spektr | Historie nach v14/v15 getrennt, Betreiberangaben eingearbeitet, unbelegte Befunde korrigiert, offene Sicherheitsabnahmen ausgewiesen |
|
||||
| 2026-09-16 | 2.1 | spektr | bestätigten Fail2Ban-Pin und wieder laufenden Container als Querverweis aufgenommen; weitergehende Abnahme nicht unterstellt |
|
||||
| 2026-09-18 | 2.2 | spektr | Lesenden SSH-Abgleich von CT 105 und Grenzen des Nachweises dokumentiert. |
|
||||
|
||||
### 1.1 SSH-Zugriff & Admin-User (GNAI-004-SEC)
|
||||
## 1. Evidenz und zeitliche Einordnung
|
||||
|
||||
* `admin` (uid 1000) mit SSH-Key-Zugang; `sudoers`: `admin ALL=(ALL) NOPASSWD: ALL`
|
||||
* sshd-Härtung-Drop-in `/etc/ssh/sshd_config.d/99-security.conf` (PermitRootLogin no, PasswordAuthentication no, KbdInteractiveAuthentication no, PubkeyAuthentication yes, PermitEmptyPasswords no)
|
||||
* Verifiziert: Key-Login, `sudo` passwortlos
|
||||
* `/root/.ssh/authorized_keys` existierte nie → kein root-Key-Rückbau nötig
|
||||
* Lokal: `~/.ssh/config`-Alias `lxc` → `10.0.0.15`, User `admin`, dedizierter Key `~/.ssh/id_ed25519_lxc`, `StrictHostKeyChecking accept-new`
|
||||
| Zeitpunkt | Evidenz |
|
||||
| --- | --- |
|
||||
| 09.09.2026 | Quellenprotokoll zum Serveraufbau, initial v14 und anschließende Migration auf v15.4.0 |
|
||||
| 12.09.2026 | dokumentierter CachyOS-Laptoptest aus WAN |
|
||||
| 15.09.2026 | Betreiber liefert LXC-Konfiguration, Quadlet, Hooks, Routen und Forwarding; bestätigt deaktivierte Per-Client Firewall |
|
||||
| 15.09.2026 | Betreiber bestätigt NPM `.10`, WireGuard `.15`, dynamischen LXC-Bestand bis `.99`, DHCP `.100–.200`; neues Rollenmodell |
|
||||
| 16.09.2026 | Betreiber bestätigt Fail2Ban-Pin `1.1.0-r2-ls43` und wieder laufenden Container; weitergehende Fail2Ban-Abnahme nicht gemeldet |
|
||||
| 18.09.2026 | lesender SSH-Abgleich auf CT 105: Dienste, Container, nftables, iptables-legacy und Listener geprüft |
|
||||
| diese Revision | Dokumentationsänderungen; keine WireGuard-Systemänderung und keine zusätzliche WireGuard-Abnahme |
|
||||
|
||||
### 1.2 nftables & IP-Forwarding
|
||||
## 2. Historischer Serveraufbau am 09.09.2026
|
||||
|
||||
* `/etc/nftables.conf` geschrieben (via `sudo tee`) und geladen (`sudo /usr/sbin/nft -f /etc/nftables.conf`)
|
||||
* INPUT: policy **drop**, lo accept, invalid drop, established/related accept, ICMP-Erreichbarkeit, **UDP 51820 öffentlich**, `tcp 22/51821` nur aus `10.0.0.0/24`, Rate-limited Drop-Log `nft-input-dropped:`
|
||||
* FORWARD: policy drop, `iif wg0 → 10.0.0.0/24` new accept (Split-Tunnel), Reverse-Route-Regel, drop
|
||||
* OUTPUT: policy accept
|
||||
* `net.ipv4.ip_forward=1` aktiv, persistent via `/etc/sysctl.d/99-ipforward.conf`
|
||||
* Verifiziert: SSH nach nftables-Load weiterhin erreichbar; Regeln per `nft list ruleset` kontrolliert
|
||||
Im WireGuard-LXC wurde Benutzer `admin` mit SSH-Key und passwortlosem sudo eingerichtet. Quellen nennen uid 1000 und `/etc/sudoers.d/admin`. SSH-Drop-in `/etc/ssh/sshd_config.d/99-security.conf` deaktiviert Root-, Passwort- und Keyboard-Interactive-Login. Der lokale SSH-Alias `lxc` verwendet `10.0.0.15`, Benutzer `admin` und einen dedizierten Ed25519-Key. Der Alias ist Workstation-Konfiguration, kein DNS- oder Hostname.
|
||||
|
||||
### 1.3 wg-easy Quadlet
|
||||
Die nftables-Baseline mit INPUT/FORWARD-DROP und breiter VPN→LAN-Freigabe sowie persistentes `net.ipv4.ip_forward=1` wurden dokumentiert. TUN war über `105.conf` durchgereicht. Podman 5.4.2, Datenverzeichnis und Quadlet wurden eingerichtet. Die generierte Unit heißt `wg-easy.service`.
|
||||
|
||||
* `podman` 5.4.2 installiert; TUN-Device `c 10:200` vorhanden (vorhanden seit Podman-Setup, `lxc.mount.entry` in 105.conf bereits gesetzt)
|
||||
* `/opt/wg-easy/data` (Volume-Target) + `/opt/wg-easy/environment` (chmod 600) angelegt
|
||||
* `/etc/containers/systemd/wg-easy.container` → generierte Unit: **`wg-easy.service`** (Podman streicht die `.container`-Endung beim Unit-Namen)
|
||||
* `systemctl daemon-reload && systemctl restart wg-easy.service`
|
||||
* Ergebnis: `wg0` up, `10.8.0.1/24`, `ListenPort 51820`; UI `http://10.0.0.15:51821` → HTTP 200 (localhost & LAN-IP)
|
||||
* ENV im Container verifiziert (`podman inspect`): `WG_HOST=vpn.ghostnet.selfhost.eu`, `WG_PORT=51820`, `WG_DEFAULT_ADDRESS=10.8.0.x`, `WG_DEFAULT_DNS=10.0.0.1`, bcrypt-`PASSWORD_HASH` vorhanden
|
||||
### 2.1 v14-Phase: ausschließlich historisch
|
||||
|
||||
### 1.4 Peers
|
||||
Die erste Phase verwendete `ghcr.io/wg-easy/wg-easy:latest`, zu diesem Zeitpunkt laut Quellen v14. VPN-Defaults lagen in `WG_HOST`, `WG_PORT`, `WG_DEFAULT_ADDRESS`, `WG_DEFAULT_DNS` und `WG_ALLOWED_IPS`; GUI-Anmeldung verwendete bcrypt-`PASSWORD_HASH`. Zustand lag in `wg0.json`, Client-IDs waren UUIDs.
|
||||
|
||||
Beide Peers über die wg-easy-API erstellt (Details Sektion 3):
|
||||
Historische API-Pfade waren `POST /api/session`, `POST /api/wireguard/client` und `GET /api/wireguard/client/<UUID>/configuration`. Diese Referenz gehört nicht in v15-Betriebsanweisungen. Das damals globale clientseitige AllowedIPs-Default wurde um Split-Tunnel-Netze ergänzt. Alte Environment- und API-Anweisungen sind obsolet und dürfen nicht in das aktuelle v15-Setup übernommen werden.
|
||||
|
||||
| Peer | Adresse | Status |
|
||||
### 2.2 Migration auf v15.4.0
|
||||
|
||||
Das Hauptdokument protokolliert eine Migration am 09.09.2026 mittels Setup-API und Import von `wg0.json`; Server- und Client-Schlüssel einschließlich PresharedKeys wurden übernommen. Ein Backup ist unter `/opt/wg-easy/backup-2026-09-09/` genannt. Existenz, Konsistenz und Restore wurden in dieser Revision nicht überprüft.
|
||||
|
||||
Der aktuelle Quadlet-Pin `15.4.0` ist durch den Betreiber bestätigt. v15 verwendet `wg-easy.db`; `wg0.conf` wird erzeugt. VPN- und Clientwerte werden im Admin Panel gepflegt. Das alte `PASSWORD_HASH`-Environment ist kein aktueller Passwortspeicher. Quellen nennen 1Password-Eintrag `ghostnet/wg-easy-ui`; Passwort nicht in Dokumente übernehmen. Historische API-Aufrufe sind keine geprüfte aktuelle API-Spezifikation.
|
||||
|
||||
## 3. Historische Peers und Laptoptest am 12.09.2026
|
||||
|
||||
| Altpeer | VPN-IP | v15-Client-ID laut Quellen | Einordnung |
|
||||
| --- | --- | --- | --- |
|
||||
| Laptop-FullAdmin | `10.8.0.2` | 1 | neue Rolle Familie oder Server Admin noch ausdrücklich zuordnen |
|
||||
| Android-LLMAdmin | `10.8.0.3` | 2 | Altbestand; Android außerhalb des neuen SOP-Umfangs, keine Praxisabnahme |
|
||||
|
||||
Profile wurden laut Log manuell aus der SQLite-Datenbank generiert und gegen die Serverkonfiguration geprüft. Das ist ein historischer Vorgang, kein künftiges SOP-Verfahren. Neue Profile werden über die GUI exportiert. Der Pfad `docs/GNAI-006-profiles/` wurde als gitignored genannt; Profile bleiben unabhängig von Git-Ausschlüssen Geheimnisse.
|
||||
|
||||
Der Laptop wurde von außerhalb des Heimnetzes über EasyCable mit damaliger Außen-IPv4 `80.187.120.60` getestet. Diese und die damalige Heimnetz-WAN-IP sind zeitgebundene Messwerte, keine DNS-Sollwerte.
|
||||
|
||||
| Prüfung | Ergebnis |
|
||||
| --- | --- |
|
||||
| WireGuard-Handshake | bestanden; Server sah Endpoint `80.187.120.60:1688` und Transfer |
|
||||
| Ping `10.8.0.1` | bestanden |
|
||||
| Ping `10.0.0.2` | bestanden |
|
||||
| `curl -4 ifconfig.co` | `80.187.120.60`; Internetpfad blieb direkt |
|
||||
| Ping KI-Server `10.0.0.90` | nicht durchgeführt / zurückgestellt, Server ausgeschaltet |
|
||||
| Android-Handshake und Zugriff | ausstehend |
|
||||
| Proxmox-GUI / SSH und Rollenisolierung | kein Abnahmenachweis |
|
||||
|
||||
Der Betreiber bestätigt: Seit diesem Test keine weiteren WireGuard-Abnahmen.
|
||||
|
||||
## 4. Betreiberbestätigung am 15.09.2026
|
||||
|
||||
CT 105: unprivileged, Debian/amd64, Hostname `wireguard`, 1 Core, 512 MiB RAM, 512 MiB Swap, 4 GiB RootFS, nesting/keyctl, `eth0` an `vmbr0`, statisch `10.0.0.15/24`, Gateway `.1`, onboot und TUN-Passthrough. Quadlet rootful mit host-Netz, NET_ADMIN/NET_RAW, Environment-File und persistenter Datenvolume-Bindung. Vollständige reproduzierbare Angaben stehen in der Architektur.
|
||||
|
||||
Hooks: PreUp/PreDown leer; PostUp legt MASQUERADE für VPN→LAN sowie breite UDP-INPUT-/wg0-FORWARD-ACCEPT-Regeln an; PostDown entfernt diese. **Per-Client Firewall deaktiviert.** Routen: Default über `.1`, Heimnetz auf eth0, VPN-Netz auf wg0. Forwarding aktiv. Die Fritzbox hat keine Rückroute zu `10.8.0.0/24`.
|
||||
|
||||
Die Fritzbox-Portweiterleitungen sind TCP 80/443→NPM `.10` und UDP 51820→WireGuard `.15`; die zwischenzeitlich vertauschte Betreiberangabe ist ausdrücklich korrigiert.
|
||||
|
||||
## 5. Korrekturen an früheren technischen Befunden
|
||||
|
||||
| früherer Befund | korrigierte Bewertung |
|
||||
| --- | --- |
|
||||
| Android akzeptiert nur `/32`, keine `/24` | ungetestete Behauptung eines LLM laut Betreiber; als allgemeine Einschränkung verworfen |
|
||||
| CIDR plus einzelne `/32` nötig für Android | keine belastbare Begründung; innerhalb desselben `/24` sind diese `/32` im normalen Routing redundant |
|
||||
| clientseitiges AllowedIPs-Profil isoliert die Rolle | kontrolliert Routing; serverseitige Firewall muss geänderte Clientprofile abfangen |
|
||||
| PostUp-Hooks vollständig redundant | MASQUERADE wird mangels Rückroute benötigt; Filterregeln müssen mit Peer-Firewall geprüft werden |
|
||||
| serverseitige AllowedIPs generell hartkodiert und unveränderlich | v14-Quellbefund nicht als pauschale v15-Aussage weiterführen; für Einzelgeräte eigenes VPN-IP-`/32` beibehalten |
|
||||
| wg-quick ergänzt `wg-`, maximal 12 Zeichen im Profilnamen | kein Präfix; Basisname ist Interface, maximal 15 Zeichen |
|
||||
| v14-Environment und `wg0.json` weiterhin aktiv | v15-Datenbank und aktuelle Container-Schalter verwenden; Altdateien allenfalls historischer Bestand |
|
||||
| selfHOST kein DNS-Anbieter | verworfen; Fritzbox aktualisiert selfHOST-DynDNS laut Betreiber |
|
||||
| Wildcard macht zusätzlichen A-Record immer harmlos | veraltete feste Records können Wildcard-Zuordnung übersteuern; tatsächlich vorhandenen Record und Update prüfen |
|
||||
|
||||
[wg-quick-Quelle](https://git.zx2c4.com/wireguard-tools/tree/src/wg-quick/linux.bash), [wg-easy-Clientreferenz](https://wg-easy.github.io/wg-easy/latest/guides/clients/)
|
||||
|
||||
## 6. Historisches Fehlerregister
|
||||
|
||||
| ID | Vorgang | gültige Einordnung |
|
||||
| --- | --- | --- |
|
||||
| Laptop-FullAdmin | `10.8.0.2` | aktiv, PreSharedKey, in `wg0.conf` |
|
||||
| Android-LLMAdmin | `10.8.0.3` | aktiv, PreSharedKey, in `wg0.conf` |
|
||||
| F1 | Permission denied / nft nicht im PATH | sudo verwenden; unter Debian liegt nft üblicherweise in `/usr/sbin` |
|
||||
| F2 | `wg-easy.container.service` nicht gefunden | generierte Unit heißt `wg-easy.service` |
|
||||
| F3 | Inline-Escaping des bcrypt-Environment schlug fehl | ausschließlich v14; EnvironmentFile löste den damaligen Fehler |
|
||||
| F4 | `POST /` lieferte 405 | falscher historischer v14-Loginpfad; keine v15-Anweisung |
|
||||
| F5 | Download mit Name statt UUID lieferte 404 | historische v14-API; künftig GUI-Export |
|
||||
| F6 | allowedIPs im v14-Create nicht übernommen | v14-Implementierungsbefund; neues Rollenmodell setzt Server-Firewall voraus |
|
||||
| F7 | wg-Tool im LXC nicht gefunden | Serverstatus mit `sudo podman exec wg-easy wg show wg0` prüfen |
|
||||
| F8 | sysctl nicht gefunden | procps/PATH prüfen; Forwarding unter `/proc/sys/net/ipv4/ip_forward` lesbar |
|
||||
| F9 | wireguard-dkms in CachyOS nicht verfügbar | im getesteten Kernel WireGuard vorhanden; wireguard-tools genügte |
|
||||
| F10 | zu langer Profil-/Interface-Name | `Laptop-FullAdmin` hat 16 Zeichen; auf `laptop` umbenannt, ohne Präfix |
|
||||
| F11 | öffentliche IP-Abfrage lieferte IPv6 | `curl -4` für einen gezielten IPv4-Vergleich |
|
||||
|
||||
Server-Config `/opt/wg-easy/data/wg0.conf`: Server `10.8.0.1/24`, `ListenPort 51820`, beide Peers mit `PresharedKey`, serverseitig `AllowedIPs = <peer-ip>/32` (wg-easy-Hardcode, siehe Sektion 3.3).
|
||||
## 7. Lesender Live-Abgleich am 18.09.2026
|
||||
|
||||
---
|
||||
Per SSH-Profil `lxc` wurde CT 105 ohne Konfigurationsänderung geprüft:
|
||||
|
||||
## 2. Abweichungen vom ursprünglichen Draft
|
||||
| Prüfung | Beobachtung |
|
||||
| --- | --- |
|
||||
| Host und Dienste | Hostname `wireguard`; `wg-easy` und `nftables` aktiv; `net.ipv4.ip_forward=1` |
|
||||
| Container | `ghcr.io/wg-easy/wg-easy:15.4.0`, `host`-Netzwerk, Status `running`; WireGuard-Interface `wg0` vorhanden |
|
||||
| nftables | INPUT-Policy `drop`, UDP 51820 erlaubt; TCP 22/51821 nur für Quellen aus `10.0.0.0/24` ausdrücklich erlaubt; FORWARD-Policy `drop` mit breiter Freigabe `wg0` → `10.0.0.0/24` |
|
||||
| iptables | Standardaufruf meldet vorhandene Legacy-Tabellen; `iptables-legacy` zeigt FORWARD-ACCEPT für `wg0` in beide Richtungen und MASQUERADE für `10.8.0.0/24` über `eth0` |
|
||||
| Listener | UDP 51820 auf IPv4 und IPv6; TCP 51821 auf allen IPv4-Adressen; SSH TCP 22 auf IPv4 und IPv6. Listener allein beweisen keine Erreichbarkeit aus dem Internet. |
|
||||
| DNS-Abgleich | `vpn.ghostnet.selfhost.eu` und ausgehende Gateway-IPv4: `93.208.161.126`; `vpn.ghostnet.dyndns.eu`: `83.169.40.234`. Dieser Zeitpunkt belegt keine automatische Aktualisierung. |
|
||||
|
||||
| # | Draft | Umsetzung | Begründung |
|
||||
| --- | --- | --- | --- |
|
||||
| A1 | Hostname `wireguard-gateway` | Hostname `wireguard` | Konvention: kurze, eindeutige Hostnames (entspricht GNAI-003-Bezeichnung „WireGuard LXC“) |
|
||||
| A2 | `PASSWORD_HASH=DEIN_ARGON2_HASH` | bcrypt-Hash (Rounds 12) | wg-easy verifiziert per `bcryptjs` – Argon2 wird **nicht** unterstützt |
|
||||
| A3 | Quadlet mit inline `Environment=`-Zeilen | `EnvironmentFile=/opt/wg-easy/environment` | `$`-Zeichen im bcrypt-Hash (`$2a$12$…`) führen beim inline `Environment=` zu escaping-Problem (Hash ging beim ersten Try verloren, siehe Fehler-Log F3). EnvironmentFile ist deterministisch |
|
||||
| A4 | Testmatrix „Validiert“ | Testmatrix „Ausstehend“ | Penetrationstests über Mobilfunk wurden in dieser Session noch **nicht** durchgeführt (warten auf Step 5/6: Fritzbox-Forward + DynDNS-Subdomain) |
|
||||
| A5 | nftables-Schritt fehlte im Draft | Neue Step 2 (nftables + ip_forward) | Strikte INPUT policy `drop` ist Doktrinen-Anforderung (GNAI-004-SEC); wg-easy erzeugt eigene (breitere) Regeln, die nicht ausreichen |
|
||||
| A6 | Peers „über Web-UI manuell“ | Peers via REST-API | UI-Flow in Session nicht durchlaufen; API liefert deterministisches Ergebnis (Endpoint-Dokumentation siehe Sektion 3.1) |
|
||||
| A7 | `PostUp`-Regeln wg-easy nicht erwähnt | Dokumentiert: redundant, kein Konflikt | wg-easy-Default-`PostUp` setzt iptables-MASQUERADE/FORWARD/INPUT-ACCEPT-Regeln. Mit der nftables-Config redundant; iptables-FORWARD-ACCEPT ist breiter, die maßgeblichen nftables-Forward-Rules bleiben bestehen. Optional: `WG_POST_UP`/`WG_PRE_DOWN` über Env auf Leerzeichen setzen – **Entscheidung offen** |
|
||||
Diese Beobachtungen bestätigen den breiten Netzpfad und die NAT-Abhängigkeit. Sie belegen keine Peer-spezifische Zugriffsbeschränkung; Per-Client Firewall und negative Rollentests bleiben offen. Die Prüfung erfasste weder die GUI-Einstellungen noch die Fritzbox-, IPv6-Perimeter- oder Clientseite.
|
||||
|
||||
---
|
||||
## 8. Offene Umsetzung und Abnahme
|
||||
|
||||
## 3. Technische Befunde wg-easy
|
||||
|
||||
### 3.1 API-Referenz (aus `ghcr.io/wg-easy/wg-easy:latest`, verifiziert in Session)
|
||||
|
||||
| Aktion | Endpoint | Body | Hinweis |
|
||||
| --- | --- | --- | --- |
|
||||
| Login | `POST /api/session` | `{ "password": "…" }` | Setzt `connect.sid`-Cookie; `POST /` gibt 405 zurück |
|
||||
| Client anlegen | `POST /api/wireguard/client` | `{ "name": "…" }` | **Nur `name` wird akzeptiert**; Address wird aus `WG_DEFAULT_ADDRESS` (`10.8.0.x`) sequenziell zugewiesen (Server `.1`, erste Clients `.2`, `.3`, …) |
|
||||
| Address ändern | `PUT /api/wireguard/client/:clientId/address` | `{ "address": "10.8.0.x" }` | `clientId` = UUID (aus `GET /api/wireguard/client`) |
|
||||
| Name ändern | `PUT /api/wireguard/client/:clientId/name` | `{ "name": "…" }` | |
|
||||
| Enable / Disable | `POST /api/wireguard/client/:clientId/enable` / `disable` | – | |
|
||||
| Client-Config (download) | `GET /api/wireguard/client/:clientId/configuration` | – | **`clientId` = UUID, nicht Name** (Name → 404) |
|
||||
| Config neu generieren | `POST /api/wireguard` (`ALLOW_CONFIG_CHANGE=true`) | – | Schreibt `wg0.conf` + wendet `wg` an |
|
||||
|
||||
Client-UUIDs (LXC): `Laptop-FullAdmin` = `2e9ed910-36dc-4fbd-8694-8d904670ea19`, `Android-LLMAdmin` = `2009acd2-19cf-4e5e-a93a-7b05eb05fc12`.
|
||||
|
||||
### 3.2 Passwort-Handling
|
||||
|
||||
* `PASSWORD_HASH` wird mit **bcryptjs** (Salt-Rounds 12, bcrypt-Format `$2a$12$…`) verifiziert.
|
||||
* UI-Login: `POST /api/session` mit Klartext-Passwort (im internen Netz, LAN-only freigeschaltet).
|
||||
|
||||
### 3.3 allowedIPs-Limitation (wichtigster Befund)
|
||||
|
||||
* **Serverseitig:** `__saveConfig()` in `/app/lib/WireGuard.js` (Container) generiert pro Peer `AllowedIPs = ${client.address}/32` – hartkodiert. Das Feld `allowedIPs` im internen `wg0.json` existiert, wird vom Create-Endpoint aber **nie** befüllt (stets `None`).
|
||||
* **Konsequenz:** Es gibt keinen API-Path, um serverseitige AllowedIPs freier zu konfigurieren (z. B. ein Peer aus mehreren VPN-IPs).
|
||||
* **Architektonische Bewertung:** Für unser Modell ist das serverseitige `/32`-Verhalten **korrekt und gewünscht**: Ein Peer darf nur Traffic aus seiner eigenen VPN-IP senden. Das eigentliche Routing (Split-Tunneling) ist **clientseitig** bestimmt – die AllowedIPs im installierten Client-Profil entscheiden, welche Zielnetzwerke über den Tunnel laufen.
|
||||
* **Clientseitig (gelöst 2026-09-09):** `getClientConfiguration()` in `/app/lib/WireGuard.js` generiert in den herunterladbaren Profilen `AllowedIPs = ${WG_ALLOWED_IPS}` – eine **globale** Env-Variable (kein per-Client-Override). Default: `0.0.0.0/0, ::/0` = **Full-Tunnel** (alle Traffic durch VPN) – nicht gewünscht.
|
||||
* **Aktion:** `WG_ALLOWED_IPS` in `/opt/wg-easy/environment` ergänzt (Backup `environment.bak.<ts>`), `wg-easy.service` neu gestartet, Env im Container verifiziert:
|
||||
```
|
||||
WG_ALLOWED_IPS=10.0.0.0/24,10.8.0.0/24,10.0.0.2/32,10.0.0.10/32,10.0.0.90/32
|
||||
```
|
||||
* **Android-Limitierung:** WireGuard für Android akzeptiert in `AllowedIPs` nur `/32` (keine `/24`-CIDRs). Die `/32`-Einträge (Fritzbox `.1`, Proxmox `.2`, NPM `.10`, LLM-Server `.90`) existieren daher explizit für Android-LLMAdmin; Laptop-FullAdmin nutzt die `/24`-Netzwerke. **Pflege-Konsequenz:** Neue LAN-Hosts müssen beide Varianten erhalten (CIDR + `/32`), danach `wg-easy.service` neu starten.
|
||||
* **End-to-End-Verifikation (O4) bleibt offen:** heruntergeladene Profile prüfen (AllowedIPs + Endpoint), dann Routing-Tests auf den Endgeräten.
|
||||
|
||||
---
|
||||
|
||||
## 4. Fehler-Log & Behebungen
|
||||
|
||||
| # | Fehler | Ursache | Behebung |
|
||||
| --- | --- | --- | --- |
|
||||
| F1 | `bash: /etc/nftables.conf: Permission denied`, `nft: command not found` | admin-User ohne root; `nft` nicht im non-login-Shell-PATH | `sudo tee /etc/nftables.conf`, `sudo /usr/sbin/nft …` (volle Pfade) |
|
||||
| F2 | `Failed to start wg-easy.container.service: Unit not found` | Quadlet generiert Unit **`wg-easy.service`** (ohne `.container`) | `sudo systemctl start wg-easy.service` |
|
||||
| F3 | `PASSWORD_HASH` fehlte nach Container-Start in `podman inspect` | `Environment=PASSWORD_HASH=\$2a\$12\$…` – Inline-Escaping in Quadlet schlug fehl, Hash ging verloren | `/opt/wg-easy/environment` (chmod 600) mit echten `$`-Zeichen + `EnvironmentFile=`; nach Restart verifiziert: Hash vorhanden |
|
||||
| F4 | `POST /` → `405 Method Not Allowed` beim UI-Login | Falscher Endpoint | `POST /api/session` mit `{"password": "…"}` → 200 + `Set-Cookie: connect.sid` |
|
||||
| F5 | `GET /api/wireguard/client/Laptop-FullAdmin/configuration` → 404 | Endpoint erwartet **UUID**, nicht Client-Namen | `GET /api/wireguard/client/2e9ed910-…/configuration` |
|
||||
| F6 | `allowedIPs` aus Create-Request nicht persistiert (wg0.json: `None`) | Create-Endpoint extrahiert ausschließlich `{name}`; kein Endpoint für allowedIPs; serverseitig hardcodiert `address/32` | Sektion 3.3 – Bewertung: serverseitig korrekt; clientseitige Routing-Verifikation offen (Step 8 im SOP) |
|
||||
| F7 | `sudo wg: command not found` (ältere Session) | `wg`-Tool nicht installiert / PATH | Status via `cat /proc/net/dev` + wg0-Config geprüft; wg-easy verwaltet das Interface selbst |
|
||||
| F8 | `sysctl` nicht verfügbar (ältere Session) | Paket `sysctl-utils`/PATH | `cat /proc/sys/net/ipv4/ip_forward`; persistenz via `/etc/sysctl.d/99-ipforward.conf` |
|
||||
|
||||
---
|
||||
|
||||
## 5. Offene Punkte & nächste Schritte
|
||||
|
||||
| # | Punkt | Typ | Blockiert durch |
|
||||
| --- | --- | --- | --- |
|
||||
| O1 | Fritzbox 7530: Portforward **UDP 51820 → 10.0.0.15** | ✅ erledigt (2026-09-09) | E2E-Check mit O4/O5 |
|
||||
| O2 | DNS für `vpn.ghostnet.selfhost.eu` (Korrektur: **nicht** NPM/selfhost.eu-Portal, sondern Domain-DNS-Anbieter) | ✅ erledigt (2026-09-09): Auflösung `93.208.161.126` verifiziert; bestehende **Wildcard-DynDNS** `*.ghostnet.selfhost.eu` war bereits ausreichend, expliziter A-Record redundant; DynDNS vorhanden → Statisch-Check entfällt | – |
|
||||
| O3 | Client-Profile herunterladen (Laptop + Android), `AllowedIPs` (aus `WG_ALLOWED_IPS`) + `Endpoint vpn.ghostnet.selfhost.eu:51820` prüfen | Agent + User | O1, O2 |
|
||||
| O4 | Split-Tunnel-Routing end-zu-end verifizieren (Step 8 SOP; Konfig steht, s. 3.3) | Agent + User | O3 |
|
||||
| O5 | Penetrationstest Mobilfunk (Testmatrix Sektion 4 SOP) | gemeinsam | O1, O2, O3 |
|
||||
| O6 | Entscheidung: wg-easy-`PostUp`-iptables-Regeln via `WG_POST_UP`/`WG_PRE_DOWN` deaktivieren (hygiene) oder belassen (redundant, kein Konflikt) | Agent | O5 (nach Tests) |
|
||||
| O7 | Projekt-Kontext in `MEMORY.md` / Memory-Store persistieren | Agent | – |
|
||||
|
||||
**Abhängigkeits-Kette:** O1+O2 → O3 → O4 → O5 → (O6)
|
||||
|
||||
---
|
||||
|
||||
## 6. Artefakt-Index (LXC 105, `/etc/…` & `/opt/…`)
|
||||
|
||||
| Pfad | Zweck | Status |
|
||||
| ID | Arbeit | Status |
|
||||
| --- | --- | --- |
|
||||
| `/etc/nftables.conf` | Perimeter-Firewall (strict INPUT drop) | aktiv |
|
||||
| `/etc/sysctl.d/99-ipforward.conf` | `net.ipv4.ip_forward=1` persist | aktiv |
|
||||
| `/etc/containers/systemd/wg-easy.container` | Quadlet → `wg-easy.service` | aktiv |
|
||||
| `/opt/wg-easy/environment` | wg-easy ENV (inkl. bcrypt-`PASSWORD_HASH`, chmod 600) | aktiv |
|
||||
| `/opt/wg-easy/data/wg0.conf` | WireGuard-Server-Config (wg-easy-generiert) | aktiv, wg0 up |
|
||||
| `/opt/wg-easy/data/wg0.json` | wg-easy interner State (Clients, UUIDs) | aktiv |
|
||||
| `/etc/ssh/sshd_config.d/99-security.conf` | SSH-Härtung (GNAI-004-SEC) | aktiv |
|
||||
| `/etc/sudoers.d/admin` | `admin` NOPASSWD sudo | aktiv |
|
||||
| Lokal: `~/.ssh/config` | Alias `lxc` (User admin, dedizierter Key) | gesetzt |
|
||||
| O1 | Fritzbox-Portforward | bestätigt; Laptop-WAN-Handshake als Teilnachweis vorhanden |
|
||||
| O2 | DynDNS-Aktualisierung nach WAN-IP-Wechsel und Fritzbox-Einstellung prüfen | aktueller selfhost-Endpoint am 18.09.2026 durch DNS-/WAN-Abgleich bestätigt; dyndns.eu zeigt auf andere Adresse |
|
||||
| O3 | Altpeers neuen Rollen zuordnen | offen |
|
||||
| O4 | Per-Client Firewall und Gateway-INPUT-Rollenrechte umsetzen | offen |
|
||||
| O5 | Rollenisolierung bei geänderten lokalen AllowedIPs testen | offen |
|
||||
| O6 | KI-Server, Proxmox-GUI und SSH testen | offen |
|
||||
| O7 | WAN-/IPv6-Managementport-Isolation | offen |
|
||||
| O8 | Reboot, Firewall-Reload und Restore | offen |
|
||||
| O9 | wg-easy-GUI-HTTPS und lokales Gruppenmodell | geplant; Werte noch festzulegen |
|
||||
|
||||
> Secrets (wg-easy-UI-Passwort/Hash, PreSharedKeys, PrivateKeys) sind **nicht** in diesem Repo dokumentiert und liegen ausschließlich auf dem LXC bzw. in den clientseitigen Profilen.
|
||||
| PW | wg-easy-UI-Passwort initial generiert, Klartext nach Session nicht verfügbar (bcrypt=Einweg-Hash) | ✅ rotiert 2026-09-09 18:40: neuer bcrypt-Hash im Env-File, API-Login 200; Klartext nur in 1Password (ghostnet/wg-easy-ui) |
|
||||
Andere Sicherheitsbefunde werden im [Dokumentationsindex](GNAI-000-DOC_Index.md) geführt. Dieses Log hält nur WireGuard-Umsetzung und zugehörige Tests fest.
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
# Secrets: WireGuard PrivateKeys/PresharedKeys – niemals committen
|
||||
*
|
||||
!.gitignore
|
||||
!README.md
|
||||
Reference in New Issue
Block a user