Ghost.net AI Struktur um Encoding erweitert.

This commit is contained in:
2026-09-20 01:04:13 +02:00
parent 2a2bd2326d
commit bf7431d672
25 changed files with 668 additions and 102 deletions
+8 -14
View File
@@ -2,7 +2,7 @@
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: 20.09.2026.** Die Dokumentationsrevisionen sind zusammengeführt. Mehrere Sicherheitsmaßnahmen und technische Endabnahmen stehen noch aus. Auf dem KI-Server sind die gemeinsame Host-Baseline und Podman eingerichtet; der LLM-Anwendungsstack ist noch nicht installiert.
> **Projektstand: 20.09.2026.** Die Dokumentationsrevisionen sind zusammengeführt. Mehrere Sicherheitsmaßnahmen und technische Endabnahmen stehen noch aus. Auf dem KI-Server sind Host-Baseline, Podman und getrennte rootless Workload-Konten eingerichtet; LLM- und Encoding-Anwendungen sind noch nicht installiert.
## Überblick
@@ -26,7 +26,7 @@ Die drei vorgesehenen VPN-Netzwerkrollen sind **Familie** (gesamtes Heimnetz), *
| Bereich | Belegter Stand | Nächster Nachweis oder Schritt |
| --- | --- | --- |
| KI-Server | Debian-Basissystem, verifizierter Deployment-Zugang, minimale Host-Baseline und Podman 5.4.2 mit geprüftem Quadlet-Generator | Ausführungsmodell und Service-Accounts für Production und Testing festlegen; danach GPU-Laufzeit prüfen |
| KI-Server | Debian-Basissystem, Deployment-Zugang, Host-Baseline, Podman 5.4.2 und drei getrennte rootless Workload-Konten | GPU-Zugriff für KI prüfen sowie Encoding-Zeitfenster und Ressourcenlimits festlegen |
| 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 |
@@ -38,21 +38,15 @@ Der [Dokumentationsindex](docs/GNAI-000-DOC_Index.md) enthält die datierten Que
| 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 |
| [Ansible-Deployment-Planung](docs/GNAI-007-PLAN_Ansible-Deployment.md) | nicht finaler Arbeitsentwurf zur reproduzierbaren Bereitstellung, Gitea-Integration und geplanten Folgedokumentation |
| [Ansible-Control-Projekt](ansible/README.md) | lokale Einrichtung, Preflight, Deployment-Account, Host-Baseline und Podman-Runtime |
| [Plattform-Dokumentation](docs/platform/README.md) | Hostbasis, Zugriffsmodell, Reverse Proxy und VPN |
| [KI-Dokumentation](docs/ai/README.md) | KI-Zielarchitektur und nicht finale Ansible-Deployment-Planung |
| [Video-Encoding](docs/video-encoding/GNENC-000-DOC_Index.md) | getrennter Planungs- und späterer SOP-Bereich für den CPU-Encoding-Workload |
| [Ansible-Control-Projekt](ansible/README.md) | lokale Einrichtung, Preflight, Deployment-Account, Host-Baseline, Podman und Workload-Konten |
## Arbeiten mit dem Repository
Dieses Repository enthält Dokumentation und ein Ansible-Control-Projekt. Es prüft Inventar, SSH-Zugang, Hostidentität, Betriebssystem und die dokumentierten GPUs. Gemeinsame Rollen verwalten die Konfigurations- und Datenwurzeln sowie Podman und Quadlet. Images, Container und der KI-Anwendungsstack sind noch nicht bereitgestellt. Vor einer Infrastrukturänderung den Ist-Stand am betroffenen Host prüfen, die passende Fachanleitung lesen und die dort genannten Abnahmeschritte dokumentieren.
Dieses Repository enthält Dokumentation und ein Ansible-Control-Projekt. Es prüft Inventar, SSH-Zugang, Hostidentität, Betriebssystem und die dokumentierten GPUs. Gemeinsame Rollen verwalten Plattform, Podman und getrennte Workload-Identitäten. KI- und Encoding-Fachdokumentation bleiben in getrennten Bereichen; Images und Container sind noch nicht bereitgestellt. Vor einer Infrastrukturänderung den Ist-Stand am betroffenen Host prüfen, die passende Fachanleitung lesen und die dort genannten Abnahmeschritte dokumentieren.
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.
WireGuard-Profile enthalten private Schlüssel. Sie gehören nicht in Git, Ausgaben oder freigegebene Dokumente. Das lokale Verzeichnis `docs/platform/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.
+24 -7
View File
@@ -106,13 +106,14 @@ unprivileged SSH identity and non-interactive escalation to effective UID 0.
## Shared host baseline
The host baseline is common to Production and Testing. It verifies the target
identity and at least 100 GiB free on the root filesystem, then manages these
root-owned directory roots:
The host baseline is common to all workloads. It verifies the target identity
and at least 100 GiB free on the root filesystem, then manages these root-owned
parent and shared-data roots:
```text
/etc/ghostnet-ai/{production,testing}
/var/lib/ghostnet-ai/{production,testing,shared}
/etc/ghostnet-ai
/var/lib/ghostnet-ai
/var/lib/ghostnet-ai/shared
```
It does not install software or start services. Use the dedicated host
@@ -147,7 +148,23 @@ overlay storage driver and exercises the installed Quadlet generator without
creating a workload.
The role explicitly keeps the Podman API socket and automatic image-update
timer disabled. It pulls no image and does not yet choose rootful or rootless
execution for the two environments. Apply and check it through the same
timer disabled. It pulls no image. Apply and check it through the same
`playbooks/host.yml` commands shown above. The first run may install packages;
an immediate second run must report `changed=0`.
## Workload accounts
The shared host play creates three locked service identities with deterministic
UID/GID and subordinate-ID ranges:
| Account | UID/GID | Purpose | Rootless Podman graph root |
| --- | --- | --- | --- |
| `gnai-production` | 980 | stable AI Production | `/var/lib/ghostnet-ai/production/.local/share/containers/storage` |
| `gnai-testing` | 981 | temporary AI Testing | `/var/lib/ghostnet-ai/testing/.local/share/containers/storage` |
| `gn-encoding` | 982 | scheduled CPU video encoding | `/var/lib/ghostnet-encoding/.local/share/containers/storage` |
Each account has a persistent systemd user manager and a separate,
administrator-managed directory below `/etc/containers/systemd/users/<UID>`.
Configuration is root-owned and group-readable; workload data belongs to its
service account. The role does not grant GPU access and creates no workload
containers.
+1
View File
@@ -11,3 +11,4 @@
roles:
- role: host_baseline
- role: podman_runtime
- role: workload_accounts
+4 -2
View File
@@ -8,8 +8,10 @@ Its first version deliberately has a narrow scope:
- refuse changes when hostname, Debian major version or primary IPv4 address
do not match the declared target;
- require at least 100 GiB free on the root filesystem; and
- create root-owned configuration and persistent-data directory roots for both
environments and future shared data.
- create root-owned parent directories and the future shared-data root.
Environment-specific directory ownership is managed by `workload_accounts` so
the shared baseline and workload identities do not compete over permissions.
It does not install packages, drivers, Podman or applications and does not
start or stop services. Ownership below the directory roots will be assigned
@@ -10,15 +10,7 @@ host_baseline_minimum_root_free_gib: 100
host_baseline_directories:
- path: /etc/ghostnet-ai
mode: "0755"
- path: /etc/ghostnet-ai/production
mode: "0750"
- path: /etc/ghostnet-ai/testing
mode: "0750"
- path: /var/lib/ghostnet-ai
mode: "0755"
- path: /var/lib/ghostnet-ai/production
mode: "0750"
- path: /var/lib/ghostnet-ai/testing
mode: "0750"
- path: /var/lib/ghostnet-ai/shared
mode: "0755"
+16
View File
@@ -0,0 +1,16 @@
# Workload accounts
The `workload_accounts` role creates separate locked service identities for AI
Production, AI Testing and CPU-based video encoding. Each identity receives a
stable UID/GID, a non-overlapping subordinate ID range, a private data root, an
administrator-managed rootless Quadlet directory and a persistent systemd user
manager.
Configuration remains owned by root and is readable by the corresponding
service group. Workload data and the rootless Podman store belong to the
service account. The role verifies that all three Podman stores are rootless
and use distinct graph roots.
The role does not grant GPU device access and does not define containers,
networks, schedules or resource limits. Those states belong to the AI and
video-encoding workload roles.
@@ -0,0 +1,43 @@
---
workload_accounts:
- name: gnai-production
uid: 980
gid: 980
comment: Ghostnet AI Production workload
home: /var/lib/ghostnet-ai/production
config_directory: /etc/ghostnet-ai/production
subid_start: 362144
supplementary_groups: []
- name: gnai-testing
uid: 981
gid: 981
comment: Ghostnet AI Testing workload
home: /var/lib/ghostnet-ai/testing
config_directory: /etc/ghostnet-ai/testing
subid_start: 427680
supplementary_groups: []
- name: gn-encoding
uid: 982
gid: 982
comment: Ghostnet video encoding workload
home: /var/lib/ghostnet-encoding
config_directory: /etc/ghostnet-encoding
subid_start: 493216
supplementary_groups: []
workload_subid_count: 65536
workload_quadlet_user_directory: /etc/containers/systemd/users
workload_data_directories:
- path: /var/lib/ghostnet-encoding/input
owner: 982
group: 982
mode: "0750"
- path: /var/lib/ghostnet-encoding/output
owner: 982
group: 982
mode: "0750"
- path: /var/lib/ghostnet-encoding/work
owner: 982
group: 982
mode: "0750"
@@ -0,0 +1,207 @@
---
- name: Verify workload account declarations
ansible.builtin.assert:
that:
- workload_accounts | map(attribute="name") | unique | length == workload_accounts | length
- workload_accounts | map(attribute="uid") | unique | length == workload_accounts | length
- workload_accounts | map(attribute="gid") | unique | length == workload_accounts | length
- >-
workload_accounts | map(attribute="subid_start") | unique | length ==
workload_accounts | length
fail_msg: Workload account names and numeric IDs must be unique.
- name: Create dedicated workload groups
ansible.builtin.group:
name: "{{ workload_account.name }}"
gid: "{{ workload_account.gid }}"
system: true
state: present
loop: "{{ workload_accounts }}"
loop_control:
loop_var: workload_account
label: "{{ workload_account.name }}"
- name: Create locked workload service accounts
ansible.builtin.user:
name: "{{ workload_account.name }}"
uid: "{{ workload_account.uid }}"
group: "{{ workload_account.name }}"
comment: "{{ workload_account.comment }}"
home: "{{ workload_account.home }}"
shell: /usr/sbin/nologin
groups: "{{ workload_account.supplementary_groups | join(',') }}"
append: false
create_home: true
system: true
password_lock: true
state: present
loop: "{{ workload_accounts }}"
loop_control:
loop_var: workload_account
label: "{{ workload_account.name }}"
- name: Assign deterministic subordinate UID ranges
ansible.builtin.lineinfile:
path: /etc/subuid
regexp: "^{{ workload_account.name | regex_escape }}:"
line: >-
{{ workload_account.name }}:{{ workload_account.subid_start }}:{{ workload_subid_count }}
owner: root
group: root
mode: "0644"
loop: "{{ workload_accounts }}"
loop_control:
loop_var: workload_account
label: "{{ workload_account.name }}"
- name: Assign deterministic subordinate GID ranges
ansible.builtin.lineinfile:
path: /etc/subgid
regexp: "^{{ workload_account.name | regex_escape }}:"
line: >-
{{ workload_account.name }}:{{ workload_account.subid_start }}:{{ workload_subid_count }}
owner: root
group: root
mode: "0644"
loop: "{{ workload_accounts }}"
loop_control:
loop_var: workload_account
label: "{{ workload_account.name }}"
- name: Assign workload data roots to their service accounts
ansible.builtin.file:
path: "{{ workload_account.home }}"
state: directory
owner: "{{ workload_account.uid }}"
group: "{{ workload_account.gid }}"
mode: "0750"
loop: "{{ workload_accounts }}"
loop_control:
loop_var: workload_account
label: "{{ workload_account.home }}"
- name: Keep workload configuration root-managed
ansible.builtin.file:
path: "{{ workload_account.config_directory }}"
state: directory
owner: root
group: "{{ workload_account.gid }}"
mode: "0750"
loop: "{{ workload_accounts }}"
loop_control:
loop_var: workload_account
label: "{{ workload_account.config_directory }}"
- name: Create workload-specific data directories
ansible.builtin.file:
path: "{{ workload_directory.path }}"
state: directory
owner: "{{ workload_directory.owner }}"
group: "{{ workload_directory.group }}"
mode: "{{ workload_directory.mode }}"
loop: "{{ workload_data_directories }}"
loop_control:
loop_var: workload_directory
label: "{{ workload_directory.path }}"
- name: Create the administrator-managed rootless Quadlet root
ansible.builtin.file:
path: "{{ workload_quadlet_user_directory }}"
state: directory
owner: root
group: root
mode: "0755"
- name: Create separate administrator-managed Quadlet directories
ansible.builtin.file:
path: "{{ workload_quadlet_user_directory }}/{{ workload_account.uid }}"
state: directory
owner: root
group: root
mode: "0755"
loop: "{{ workload_accounts }}"
loop_control:
loop_var: workload_account
label: "{{ workload_account.name }} (UID {{ workload_account.uid }})"
- name: Enable persistent user managers for rootless Quadlets
ansible.builtin.command:
argv:
- /usr/bin/loginctl
- enable-linger
- "{{ workload_account.name }}"
creates: "/var/lib/systemd/linger/{{ workload_account.name }}"
loop: "{{ workload_accounts }}"
loop_control:
loop_var: workload_account
label: "{{ workload_account.name }}"
- name: Wait for persistent user managers
ansible.builtin.command:
argv:
- /usr/bin/systemctl
- is-active
- "user@{{ workload_account.uid }}.service"
changed_when: false
register: workload_user_manager_status
retries: 5
delay: 1
until: workload_user_manager_status.stdout == "active"
loop: "{{ workload_accounts }}"
loop_control:
loop_var: workload_account
label: "{{ workload_account.name }}"
when: not ansible_check_mode
- name: Initialize and inspect each rootless Podman store
ansible.builtin.command:
argv:
- /usr/sbin/runuser
- --user
- "{{ workload_account.name }}"
- --
- /usr/bin/env
- "HOME={{ workload_account.home }}"
- "XDG_RUNTIME_DIR=/run/user/{{ workload_account.uid }}"
- /usr/bin/podman
- info
- --format=json
chdir: "{{ workload_account.home }}"
changed_when: false
register: workload_podman_info_commands
loop: "{{ workload_accounts }}"
loop_control:
loop_var: workload_account
label: "{{ workload_account.name }}"
when: not ansible_check_mode
- name: Parse rootless Podman information
ansible.builtin.set_fact:
workload_podman_infos: >-
{{ workload_podman_info_commands.results
| map(attribute="stdout")
| map("from_json")
| list }}
when: not ansible_check_mode
- name: Verify isolated rootless Podman stores
ansible.builtin.assert:
that:
- >-
workload_podman_infos | map(attribute="host.security.rootless")
| select("equalto", true) | list | length == workload_accounts | length
- >-
workload_podman_infos | map(attribute="store.graphRoot")
| unique | list | length == workload_accounts | length
fail_msg: Workload accounts do not have separate rootless Podman stores.
success_msg: All workload accounts use separate rootless Podman stores.
when: not ansible_check_mode
- name: Report workload account isolation
ansible.builtin.debug:
msg:
accounts: "{{ workload_accounts | map(attribute='name') | list }}"
uids: "{{ workload_accounts | map(attribute='uid') | list }}"
graph_roots: >-
{{ workload_podman_infos | map(attribute="store.graphRoot") | list }}
when: not ansible_check_mode
+47 -21
View File
@@ -5,20 +5,35 @@
## 1. Dokumente und Zielgruppen
### Plattform und Host
| 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 |
| [GNAI-007-PLAN_Ansible-Deployment.md](GNAI-007-PLAN_Ansible-Deployment.md) | nicht finaler Arbeitsentwurf zum Ansible-/Gitea-Deployment und zur geplanten Folgedokumentation; Infrastrukturadministratoren und Mitwirkende |
| [Ansible-Control-Projekt](../ansible/README.md) | Control-Node, Preflight, Deployment-Account, Host-Baseline und Podman-Runtime; Intermediate IT |
| [Bereichsindex](platform/README.md) | Einstieg in die Plattform- und Hostdokumentation |
| [GNAI-001-INFRA_BaseSystem.md](platform/GNAI-001-INFRA_BaseSystem.md) | Hardware und Debian-Installation; Intermediate IT |
| [GNAI-002-INFRA_Users.md](platform/GNAI-002-INFRA_Users.md) | Benutzer, statisches Hostnetz, Resolver und SSH; Intermediate IT |
| [GNAI-004-SEC_Access-Control.md](platform/GNAI-004-SEC_Access-Control.md) | verbindliches Rollen- und Zugriffsziel; Intermediate IT |
| [GNAI-005-SEC_Reverse-Proxy.md](platform/GNAI-005-SEC_Reverse-Proxy.md) | NPM/Fail2Ban und Keycloak-Korrekturverfahren; Intermediate IT |
| [GNAI-006-SEC_VPN.md](platform/GNAI-006-SEC_VPN.md) | wg-easy-Installation/Konfiguration in Proxmox LXC; Intermediate IT |
| [GNAI-006-SEC_VPN_Client-Management.md](platform/GNAI-006-SEC_VPN_Client-Management.md) | eigenständige GUI-SOP für Ausgabe, Änderungen und Widerruf; Intermediate IT |
| [GNAI-006-SEC_VPN_Clients_Windows11.md](platform/GNAI-006-SEC_VPN_Clients_Windows11.md) | offizieller Windows-Client, Import und Verwendung; Junior IT |
| [GNAI-006-SEC_VPN_Clients_Linux.md](platform/GNAI-006-SEC_VPN_Clients_Linux.md) | Debian, Arch/CachyOS, Fedora/Kinoite; Junior IT |
| [GNAI-006-SEC_VPN_Implementation-Log.md](platform/GNAI-006-SEC_VPN_Implementation-Log.md) | historische v14/v15-Umsetzung und Evidenzkorrekturen; Intermediate IT |
### KI
| Dokument | Zweck / Zielgruppe |
| --- | --- |
| [Bereichsindex](ai/README.md) | Einstieg in die KI-spezifische Dokumentation |
| [GNAI-003-INFRA_Architecture.md](ai/GNAI-003-INFRA_Architecture.md) | Gesamtzielarchitektur und Inventar des KI-Stacks; Intermediate IT |
| [GNAI-007-PLAN_Ansible-Deployment.md](ai/GNAI-007-PLAN_Ansible-Deployment.md) | nicht finaler Arbeitsentwurf zum Ansible-/Gitea-Deployment und zur geplanten Folgedokumentation; Infrastrukturadministratoren und Mitwirkende |
### Video-Encoding und Automatisierung
| Dokument | Zweck / Zielgruppe |
| --- | --- |
| [Video-Encoding-Dokumentation](video-encoding/GNENC-000-DOC_Index.md) | getrennter Index für Architektur und spätere Nutzer-SOPs des CPU-Encoding-Workloads |
| [Ansible-Control-Projekt](../ansible/README.md) | Control-Node, Preflight, Deployment-Account, Host-Baseline, Podman und Workload-Konten; Intermediate IT |
## 2. Verbindliche, bestätigte Entscheidungen
@@ -26,32 +41,34 @@ NPM ist `.10`, WireGuard `.15`, Proxmox `.2`, KI-Server `.90`, Fritzbox `.1`, je
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.
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](platform/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.
Der KI-Server heißt laut lesendem SSH-Abgleich vom 18.09.2026 `ghostnet-ki`; damals bestanden die persönlichen Konten `ghost`, `debugofen` und das Agentenkonto `ghost-agent`. Inzwischen ergänzen `ansible-deploy` sowie die gesperrten Workload-Konten `gnai-production`, `gnai-testing` und `gn-encoding` diesen Bestand. `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 wurde als frisches Debian-Basissystem begonnen. Inzwischen sind die dokumentierten Ansible-Zugänge, die minimale Host-Baseline und Podman eingerichtet. Die LLM-Anwendungen sind weiterhin nicht installiert; GNAI-003 und GNAI-004 beschreiben für sie ein Zielbild.
Der [Ansible-Deployment-Entwurf](GNAI-007-PLAN_Ansible-Deployment.md) persistiert den seit dem 19.09.2026 fortgeschriebenen Planungs- und Implementierungsstand. Er ist ausdrücklich keine verbindliche Spezifikation und kein Nachweis einer vollständig eingerichteten Deploymentkette. Die dort genannten Runner-, Freigabe- und Secret-Verfahren sind bis zu ihrer Prüfung und formalen Übernahme vorläufig.
Der [Ansible-Deployment-Entwurf](ai/GNAI-007-PLAN_Ansible-Deployment.md) persistiert den seit dem 19.09.2026 fortgeschriebenen Planungs- und Implementierungsstand. Er ist ausdrücklich keine verbindliche Spezifikation und kein Nachweis einer vollständig eingerichteten Deploymentkette. Die dort genannten Runner-, Freigabe- und Secret-Verfahren sind bis zu ihrer Prüfung und formalen Übernahme vorläufig.
Das erste Ansible-Control-Projekt mit Testing-Inventar und lesendem Preflight wurde am 19.09.2026 angelegt. Der Live-Lauf über `ghost-agent` bestätigte Hostidentität, Debian 13.6, IPv4-Adresse, Python, CPU, RAM und zwei Navi-21-Geräte mit `changed=0`, `unreachable=0` und `failed=0`. Dieser Nachweis umfasst weder privilegierten Zugriff noch eine eingerichtete Production-/Testing-Laufzeitumgebung.
Der separate Ed25519-Schlüssel mit Fingerprint `SHA256:IKEInbIo8VVI1USg5+a3ypGK8H8FweJiQu+v7KvhQDU` und das Bootstrap-Playbook wurden am 19.09.2026 verwendet, um `ansible-deploy` einzurichten. Der private Schlüssel liegt ausschließlich außerhalb des Repositories. Der Account besitzt ein gesperrtes Passwort, einen auf LAN- und WireGuard-Quellnetze beschränkten Public Key und eine mit `visudo` validierte Regel `NOPASSWD: ALL`. Ein getrenntes Prüfplaybook bestätigte anschließend Anmeldung, Modulausführung und effektive UID 0 über sudo mit `ok=5 changed=0 unreachable=0 failed=0`.
Die erste schreibende Rolle `host_baseline` wurde am 19.09.2026 nach erfolgreichem Syntax- und Check-Modus-Lauf angewendet. Sie prüft Hostname, Debian-Hauptversion, Standard-IPv4 sowie mindestens 100 GiB freien Speicher und verwaltet ausschließlich `/etc/ghostnet-ai/{production,testing}` und `/var/lib/ghostnet-ai/{production,testing,shared}` mit Root-Eigentum. Der erste reale Lauf meldete `ok=6 changed=1 unreachable=0 failed=0`; der unmittelbar folgende identische Lauf belegte Idempotenz mit `ok=6 changed=0 unreachable=0 failed=0`. Pakete, Dienste und Anwendungen wurden dabei nicht verändert.
Die erste schreibende Rolle `host_baseline` wurde am 19.09.2026 nach erfolgreichem Syntax- und Check-Modus-Lauf angewendet. Sie prüft Hostname, Debian-Hauptversion, Standard-IPv4 sowie mindestens 100 GiB freien Speicher. Die zunächst dort angelegten Umgebungsverzeichnisse werden seit Einführung der Servicekonten durch `workload_accounts` verwaltet; `host_baseline` besitzt nur noch die gemeinsamen Eltern und `/var/lib/ghostnet-ai/shared`. Der erste reale Lauf meldete `ok=6 changed=1 unreachable=0 failed=0`; der unmittelbar folgende identische Lauf belegte Idempotenz mit `ok=6 changed=0 unreachable=0 failed=0`.
Die Rolle `podman_runtime` wurde am 20.09.2026 angewendet. Sie installierte Podman 5.4.2 aus Debian 13 einschließlich expliziter DNS- und rootless Netzwerkvoraussetzungen, prüfte systemd, cgroup v2, Overlay-Storage und den Quadlet-Generator und legte `/etc/containers/systemd` an. `podman.socket` und `podman-auto-update.timer` werden deaktiviert und gestoppt gehalten. Der abschließende Gesamtlauf meldete `ok=20 changed=0 unreachable=0 failed=0`; eine getrennte Prüfung bestätigte leere Image- und Containerlisten sowie beide Units als `disabled` und `inactive`.
Die Rolle `workload_accounts` richtete am 20.09.2026 die gesperrten Konten `gnai-production` (UID/GID 980), `gnai-testing` (981) und `gn-encoding` (982) mit festen, getrennten SubID-Bereichen ein. Konfiguration bleibt rootverwaltet; Daten, rootless Podman-Stores und persistente systemd-User-Manager sind pro Workload getrennt. Der korrigierte Gesamtlauf meldete `ok=36 changed=0 unreachable=0 failed=0` und bestätigte drei unterschiedliche rootless Graph Roots. Images und Container wurden nicht angelegt.
## 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 |
| Keycloak-Administration öffentlich erreichbar, externe Anmeldung möglich | [GNAI-005](platform/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](platform/GNAI-006-SEC_VPN.md) und [GUI-SOP](platform/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](platform/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](platform/GNAI-005-SEC_Reverse-Proxy.md): mögliche legitime Treffer und rollen-/routingabhängiger VPN-Ausweichweg dokumentiert |
## 4. Noch erforderliche Angaben
@@ -69,7 +86,7 @@ Es werden keine Werte für diese offenen Angaben angenommen. Die betreffenden Ve
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).
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](platform/GNAI-001-INFRA_BaseSystem.md) und [GNAI-002](platform/GNAI-002-INFRA_Users.md).
Am 19.09.2026 bestätigte ein erster reproduzierbarer Ansible-Preflight über das unprivilegierte Konto `ghost-agent` erneut `ghostnet-ki`, Debian 13.6, `10.0.0.90`, 14 vCPUs, 64.123 MiB RAM, Remote-Python 3.13.5 und zwei PCI-Geräte `1002:73bf`. Der Play Recap lautete `ok=5 changed=0 unreachable=0 failed=0`. Das Playbook verwendete kein `sudo` und nahm keine Serverkonfiguration vor.
@@ -79,4 +96,13 @@ Für die gemeinsame Host-Baseline bestätigte ein vorgelagerter Check-Modus gena
Am 20.09.2026 sagte der Podman-Check-Modus 38 neue Debian-Pakete und das Quadlet-Verzeichnis voraus. Der reale Lauf installierte diese Pakete; seine erste Nachprüfung bewertete den Debian-Symlink des Quadlet-Generators irrtümlich nicht als reguläre Datei. Nach Korrektur der Ansible-`stat`-Prüfung auf das aufgelöste Ziel bestanden Podman 5.4.2, cgroup v2, Overlay-Storage und der Generator-Dry-Run. Der finale Gesamtlauf war mit `changed=0` idempotent. Es wurden weder Images geladen noch Container oder Anwendungsdienste angelegt.
Der anschließende Workload-Account-Lauf richtete drei Konten, feste
SubUID-/SubGID-Bereiche, rootverwaltete Quadlet-Pfade und persistente
systemd-User-Manager ein. Zwei reine Abschlussprüfungen deckten zunächst den
nicht erlaubten direkten sudo-Benutzerwechsel sowie konkurrierende
Verzeichniseigentümer zwischen Rollen auf. Nach Umstellung der Prüfung auf
rootseitiges `runuser` und eindeutiger Eigentümerzuständigkeit endete der
Gesamtlauf mit `ok=36 changed=0 unreachable=0 failed=0`. Die drei rootless
Podman-Stores sind voneinander getrennt und noch leer.
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.
@@ -3,7 +3,7 @@
**Dokumenten-ID:** GNAI-003-INFRA
**Titel:** Homelab / LLM-Infrastruktur – Zielarchitektur
**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)
**Vorgänger / Referenzen:** [Basisinstallation](../platform/GNAI-001-INFRA_BaseSystem.md), [Benutzer/SSH](../platform/GNAI-002-INFRA_Users.md), [Zugriffskonzept](../platform/GNAI-004-SEC_Access-Control.md), [Reverse Proxy](../platform/GNAI-005-SEC_Reverse-Proxy.md), [WireGuard](../platform/GNAI-006-SEC_VPN.md)
---
@@ -338,4 +338,4 @@ Die Architektur gilt als korrekt umgesetzt, wenn mindestens folgende Eigenschaft
## 14. Umsetzungsstand
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.
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.
@@ -4,7 +4,7 @@
**Titel:** Ansible-Deployment für den KI-Server – Planungsstand
**Stand:** 2026-09-20
**Status:** Nicht finaler Arbeitsentwurf zur Persistierung des aktuellen Planungsstands
**Referenzen:** [Projektstand](GNAI-000-DOC_Index.md), [Zielarchitektur](GNAI-003-INFRA_Architecture.md), [Zugriffskonzept](GNAI-004-SEC_Access-Control.md)
**Referenzen:** [Projektstand](../GNAI-000-DOC_Index.md), [Zielarchitektur](GNAI-003-INFRA_Architecture.md), [Zugriffskonzept](../platform/GNAI-004-SEC_Access-Control.md)
> **Abgrenzung:** Dieses Dokument hält die Ergebnisse der am 19.09.2026
> begonnenen und am 20.09.2026 fortgeschriebenen Planungssession fest. Es ist
@@ -27,6 +27,7 @@
| 2026-09-19 | 0.6 | spektr / Codex | `ansible-deploy` auf dem KI-Server eingerichtet und SSH-/sudo-Zugriff unabhängig erfolgreich verifiziert |
| 2026-09-19 | 0.7 | spektr / Codex | minimale gemeinsame Host-Baseline mit Schutzprüfungen und getrennten Verzeichniswurzeln implementiert, angewendet und auf Idempotenz geprüft |
| 2026-09-20 | 0.8 | spektr / Codex | gemeinsame Podman-/Quadlet-Runtime implementiert, installiert und ohne Images oder Container verifiziert |
| 2026-09-20 | 0.9 | spektr / Codex | getrennte rootless Konten für AI Production, AI Testing und CPU-Encoding eingerichtet; Parallelitäts- und Repository-Grenzen ergänzt |
---
@@ -73,6 +74,11 @@ ein Production-Inventar existieren noch nicht. Der Preflight selbst nahm keine
Änderungen vor; die bislang angewendeten Rollen bleiben auf die nachfolgend
dokumentierten Zugangs-, Verzeichnis- und Runtime-Zustände begrenzt.
Ein fachlich vom LLM-Stack getrennter CPU-Encoding-Workload wird auf demselben
Host vorgesehen. Sein Ansible-Sollzustand bleibt wegen des gemeinsamen Hosts im
Infrastructure-Repository; Architektur und spätere Nutzer-SOPs werden unter
[`docs/video-encoding/`](../video-encoding/GNENC-000-DOC_Index.md) getrennt geführt.
---
## 3. Vorläufiges Zielbild
@@ -114,7 +120,7 @@ Planungsrichtung und noch nicht bestätigten Implementierungsdetails.
| Thema | Aktueller Planungsstand | Verbindlichkeit / Nachweis |
| --- | --- | --- |
| Konfigurationsmanagement | Ansible beschreibt Basissystem, Laufzeitumgebung, Dienste und Konfiguration | Control-Projekt, Preflight, `host_baseline` und `podman_runtime` vorhanden und angewendet; GPU- und Anwendungsrollen fehlen noch |
| Konfigurationsmanagement | Ansible beschreibt Basissystem, Laufzeitumgebung, Dienste und Konfiguration | Control-Projekt, Preflight, `host_baseline`, `podman_runtime` und `workload_accounts` vorhanden und angewendet; GPU- und Anwendungsrollen fehlen noch |
| Quell- und Freigabeverfahren | Änderungen über Gitea-Branches und Pull Requests; kein regulärer Direkt-Push auf `main` | vorgesehen; Branch-Schutz noch nicht geprüft oder eingerichtet |
| CI | Pull Requests erhalten Lint-, YAML- und Ansible-Syntaxprüfungen ohne produktive Zugangsdaten | vorgesehen; Workflow noch nicht vorhanden |
| Produktionsausführung | Gitea Actions startet Ansible über eine dedizierte Production-Berechtigungsstufe | bevorzugte Lösung; Gitea-Version, Runner-Trennung und Actions-Funktion noch zu prüfen |
@@ -125,13 +131,14 @@ Planungsrichtung und noch nicht bestätigten Implementierungsdetails.
| Zielzugang | eigener technischer SSH-Account `ansible-deploy` mit separatem, quellnetzbeschränktem Schlüssel und validiertem `NOPASSWD: ALL` | auf dem KI-Server eingerichtet und unabhängig verifiziert; spätere Runner-Übernahme und Rotation offen |
| Geheimnisse | verschlüsselte Ansible-Variablen plus getrennt gespeichertes Vault-Passwort und Runner-Zugangsdaten | Richtung angenommen; konkreter Secret-Workflow noch offen |
| Artefaktversionen | Pakete, Collections und Container-Images werden auf konkrete Versionen, nach Möglichkeit Digests, festgelegt | vorgesehen |
| Repository-Zuschnitt | vorerst ausschließlich das bestehende Repository `infrastructure`; weitere Quellcode-Repositories erst bei tatsächlich eigenständig entwickelten Anwendungen oder MCP-Komponenten | als aktuelle Planungsentscheidung angenommen |
| Repository-Zuschnitt | `infrastructure` bleibt alleinige Quelle für alle Ansible-Zustände des Hosts; KI- und Encoding-Dokumentation werden getrennt geführt; weitere Quellcode-Repositories erst bei eigenständig entwickelten Anwendungen | als aktuelle Planungsentscheidung angenommen |
| Anwendungsupdates | Upstream-Artefakte werden im Infrastruktur-Repository auf eine geprüfte Version festgelegt; eigene Build-Repositories sind vorerst nicht Bestandteil des Projekts | vorgesehen; Registry- und Buildverfahren bei späterem Eigenentwicklungsbedarf neu bewerten |
| Automatische Updates | kein unbeaufsichtigtes Produktionsupdate über `latest` oder Watchtower | vorläufige Sicherheitsentscheidung |
| Laufzeitumgebungen | Production und Testing werden als getrennte Stacks auf demselben physischen KI-Server betrieben | als aktuelle Planungsentscheidung angenommen |
| Production | stabiler, extern nutzbarer Stand mit bewusst freigegebenen Versionen | Zielbild; Dienste noch nicht eingerichtet |
| Testing | interner, kurzlebiger oder zurücksetzbarer Stand für kontrollierte Tests vor dem Merge nach `main`; nutzt während eines Wartungsfensters die vollständige Hardware exklusiv | Zielbild; Dienste, Zugriffsweg und Umschaltverfahren noch nicht eingerichtet |
| Ressourcenbetrieb | keine feste physische Aufteilung; Production und Testing laufen nicht gleichzeitig und werden über einen exklusiven Umschaltvorgang zeitlich gestaffelt | als aktuelle Planungsentscheidung angenommen |
| Testing | interner, kurzlebiger oder zurücksetzbarer Stand für kontrollierte Tests vor dem Merge nach `main`; nutzt während eines Wartungsfensters beide GPUs exklusiv gegenüber Production | Zielbild; Dienste, Zugriffsweg und Umschaltverfahren noch nicht eingerichtet |
| Ressourcenbetrieb | AI Production und AI Testing laufen nicht gleichzeitig; der getrennte CPU-Encoding-Workload darf nachts parallel zur jeweils aktiven KI-Umgebung laufen | als aktuelle Planungsentscheidung angenommen; Grenzwerte und Lasttest offen |
| Workload-Konten | `gnai-production`, `gnai-testing` und `gn-encoding` verwenden getrennte rootless Podman-Stores und systemd-User-Manager | eingerichtet und mit `changed=0` verifiziert |
| Betriebsnachweis | erfolgreicher Lauf dokumentiert Git-Commit, Zielhost, Zeitpunkt, Prüfungen und Ergebnis | vorgesehen |
| Rollback | Konfigurationsänderung über Revert und erneute Freigabe; persistente Daten zusätzlich über getestete Backups wiederherstellen | Grundprinzip; konkrete SOP noch zu erstellen |
@@ -223,9 +230,11 @@ Umgebung läuft.
Production und Testing laufen zunächst auf demselben physischen KI-Server.
Damit können Anwendungscontainer, Konfigurationen und Daten sauber logisch
getrennt werden. Die Hardware kann wegen des hohen Leistungsbedarfs nicht
dauerhaft zwischen beiden Umgebungen aufgeteilt werden. Stattdessen erhält die
jeweils aktive Umgebung CPU, RAM und beide GPUs exklusiv. Es entstehen dennoch
keine getrennten Fehlerdomänen:
dauerhaft zwischen beiden KI-Umgebungen aufgeteilt werden. Stattdessen erhält
die jeweils aktive KI-Umgebung beide GPUs exklusiv gegenüber der anderen
KI-Umgebung. Ein fachlich getrennter CPU-Encoding-Workload darf außerhalb der
Stoßzeiten parallel laufen. Es entstehen dennoch keine getrennten
Fehlerdomänen:
- Kernel, AMD-Treiber beziehungsweise ROCm, Podman und systemd werden gemeinsam
verwendet;
@@ -256,19 +265,27 @@ geplante Unterbrechung von Production.
| Persistente Daten | eigene Volumes mit Backup- und Restore-Verfahren | eigene zurücksetzbare Volumes; keine Production-Datenkopie ohne Bereinigung und Freigabe |
| Secrets und API-Keys | ausschließlich Production-Credentials | eigene eingeschränkte Test-Credentials |
| Ports und Hostnamen | stabile freigegebene Endpunkte | getrennte interne Ports und noch festzulegende Testhostnamen |
| Ressourcen | erhält im Normalbetrieb die vollständige Hardware exklusiv | erhält ausschließlich im freigegebenen Testfenster die vollständige Hardware exklusiv |
| Ressourcen | erhält im Normalbetrieb beide GPUs und das festzulegende KI-Ressourcenbudget | erhält im Testfenster beide GPUs und das festzulegende KI-Ressourcenbudget |
| GPU | beide GPUs, solange Production aktiv ist | beide GPUs, nachdem Production vollständig beendet wurde |
| Ausführungszustand | standardmäßig aktiv | standardmäßig gestoppt |
| Verfügbarkeit | stabiler Betriebsstand außerhalb angekündigter Wartungsfenster | best effort; wird nach jedem Testlauf wieder vollständig gestoppt |
Eine gleichzeitige Inferenzlast beider Umgebungen ist nicht vorgesehen. Vor dem
Eine gleichzeitige Inferenzlast beider KI-Umgebungen ist nicht vorgesehen. Vor dem
Start von Testing muss nachweisbar sein, dass Production beendet wurde und
keine zugehörigen Prozesse mehr CPU-, RAM- oder GPU-Ressourcen halten. Vor dem
Wiederanlauf von Production muss Testing entsprechend vollständig beendet und
sein temporärer Zustand bereinigt sein. Speicherplatz- und Prozessgrenzen
bleiben auch bei exklusiver Rechenleistung sinnvoll, damit ein Test nicht den
bleiben auch bei exklusiver GPU-Nutzung sinnvoll, damit ein Test nicht den
gemeinsamen Datenträger füllt oder den Host dauerhaft beeinträchtigt.
Der CPU-basierte Encoding-Workload ist nicht Teil dieser KI-Umschaltung. Er darf
nachts parallel zu Production oder Testing laufen, erhält keinen GPU-Zugriff
und muss über CPU-, Speicher- und I/O-Grenzen die Reaktionsfähigkeit der
KI-Dienste schützen. Die Betreiberfestlegung „CPU-basiert“ und die geplante
Parallelität sind noch durch einen repräsentativen gemeinsamen Lasttest zu
bestätigen. Zeitfenster und Grenzwerte werden ausschließlich im getrennten
[Encoding-Plan](../video-encoding/GNENC-001-PLAN_Architecture.md) spezifiziert.
Große schreibgeschützte Modelldateien können später aus einem gemeinsamen,
nur lesbar eingebundenen Modellspeicher bereitgestellt werden. Datenbanken,
Uploads, Caches mit Schreibzugriff, Benutzerkonten und Anwendungsschlüssel
@@ -290,7 +307,7 @@ Production. Der vorläufige Ablauf lautet:
geordnet beenden;
5. prüfen, dass alle Production-Units, -Container und GPU-Prozesse beendet
sind;
6. einen hostweiten exklusiven Deployment-Lock setzen;
6. einen exklusiven Lock für den KI-Umgebungswechsel setzen;
7. Testing für den festgelegten Commit ausrollen und mit der vollständigen
Hardware starten;
8. Health Checks und fachliche Tests ausführen und Ergebnisse dem Pull Request
@@ -318,7 +335,8 @@ Verfügung.
Production und Testing dürfen niemals gleichzeitig als aktiv markiert sein.
Jeder Start prüft den Gegenstatus und bricht bei einem widersprüchlichen oder
unklaren Zustand ab.
unklaren Zustand ab. Der Encoding-Workload bleibt von diesem KI-Lock unabhängig;
ein allgemeines Hostwartungsfenster kann weiterhin alle Workloads stoppen.
### 7.4 Vorgesehene Ansible-Abbildung
@@ -327,37 +345,38 @@ getrennt:
```text
ansible/
├── inventories/
│ ├── production/
│ │ ├── hosts.yml
│ │ ├── group_vars/
│ │ └── host_vars/
│ └── testing/
│ ├── hosts.yml
│ ├── group_vars/
│ └── host_vars/
├── playbooks/
│ ├── host.yml
│ ├── environment.yml
│ └── verify.yml
│ ├── ai.yml
│ ├── video-encoding.yml
│ └── site.yml
└── roles/
├── host_baseline/
└── environment_stack/
├── podman_runtime/
├── workload_accounts/
├── ai_stack/
├── ai_environment_switch/
└── video_encoding/
```
Beide Inventare zeigen auf `ghostnet-ki`, enthalten aber ausschließlich die
für ihre Umgebung zulässigen Variablen und Secrets. `host.yml` verwaltet
gemeinsame Pakete, Treiber, Benutzer und Runtime-Komponenten einmalig.
`environment.yml` muss genau eine explizit gewählte Umgebung verwalten und vor
Änderungen prüfen, ob Namen, Pfade, Ports und Zielvariablen zur Auswahl passen.
Hoständerungen dürfen nicht beiläufig durch einen Testing-Lauf erfolgen.
`host.yml` verwaltet gemeinsame Pakete, Treiber, Benutzer und
Runtime-Komponenten einmalig. `ai.yml` verwaltet ausschließlich den LLM-Stack
und genau eine explizit gewählte KI-Umgebung. `video-encoding.yml` verwaltet nur
Encoding-Pfade, Images, Quadlets, Timer und Prüfungen. `site.yml` kann den
unterstützten Gesamtzustand in definierter Reihenfolge herstellen. Hoständerungen
dürfen nicht beiläufig durch einen Workload-Lauf erfolgen.
Für den ersten umgesetzten Baseline-Stand gelten getrennte Konfigurationsbäume
unter `/etc/ghostnet-ai/{production,testing}` und getrennte persistente
Datenbäume unter `/var/lib/ghostnet-ai/{production,testing}`. Der Pfad
`/var/lib/ghostnet-ai/shared` ist für später ausdrücklich freigegebene
gemeinsame Daten reserviert. Konkrete Unterverzeichnisse, Eigentümer sowie
Unit- und Container-Namen werden mit den jeweiligen Fachrollen festgelegt.
Unit- und Container-Namen werden mit den jeweiligen Fachrollen festgelegt. Die
Konten `gnai-production` und `gnai-testing` besitzen inzwischen ihre
Datenwurzeln und getrennten rootless Podman-Stores; Konfiguration bleibt
rootverwaltet und für die jeweilige Gruppe lesbar. Der Encoding-Workload
verwendet entsprechend `/etc/ghostnet-encoding` und
`/var/lib/ghostnet-encoding`.
---
@@ -534,8 +553,8 @@ nicht als Nachweis einer erfolgreichen Einrichtung.
### Phase D – KI-Laufzeit
- Podman- und Quadlet-Grundruntime eingerichtet und geprüft; konkretes
rootful/rootless Ausführungsmodell noch festzulegen;
- Podman- und Quadlet-Grundruntime sowie getrennte rootless Workload-Konten
eingerichtet und geprüft;
- AMD-GPU-/ROCm- oder alternative Laufzeit nach technischer Prüfung;
- `llama.cpp` und lokaler Funktionstest;
- Wiederanlauf nach geplantem Reboot prüfen.
@@ -585,9 +604,9 @@ Vor der technischen Spezifikation sind mindestens folgende Punkte zu klären:
Wiederanlauf von Production sicher, wenn Runner oder Testing ausfallen?
15. Welche internen Hostnamen und Ports erhält Testing, und welche LAN-/VPN-
Rollen dürfen darauf zugreifen?
16. Können Production und Testing mit getrennten unprivilegierten Accounts
verwaltet werden, oder erfordert die gewählte Podman-/systemd-Architektur
einen stärker privilegierten gemeinsamen Deploymentpfad?
16. Funktioniert der benötigte AMD-GPU-Zugriff zuverlässig aus den getrennten
rootless Konten, und welche Gruppen-, Device- und Containeroptionen sind
dafür minimal erforderlich?
17. Wie wird ein Testing-Deployment eines Pull-Request-Commits in der
eingesetzten Gitea-Version autorisiert, ohne Production-Secrets oder
Production-Runner für veränderbaren PR-Code verfügbar zu machen?
@@ -715,13 +734,33 @@ Eine getrennte Prüfung bestätigte außerdem leere Image- und Containerlisten
sowie `podman.socket` und `podman-auto-update.timer` jeweils als `disabled` und
`inactive`.
Die Rolle `workload_accounts` wurde anschließend in `host.yml` aufgenommen. Sie
verwaltet feste IDs, gesperrte Passwörter, `/usr/sbin/nologin`, getrennte
SubUID-/SubGID-Bereiche, Daten- und Konfigurationsrechte, rootverwaltete
Quadlet-Verzeichnisse und Linger für `gnai-production` (UID/GID 980),
`gnai-testing` (981) und `gn-encoding` (982). Die Datenwurzeln gehören dem
jeweiligen Konto; Konfiguration gehört root und ist für die jeweilige Gruppe
lesbar.
Beim ersten realen Lauf scheiterte nur die Abschlussprüfung, weil die
sudoers-Regel von `ansible-deploy` den direkten Ansible-Wechsel zu den
Servicekonten nicht erlaubt. Die Prüfung wurde auf einen rootseitigen Aufruf
über `runuser` umgestellt, ohne die sudoers-Regel zu erweitern. Ein weiterer
Lauf deckte eine konkurrierende Eigentümerverwaltung durch `host_baseline` auf;
die umgebungsspezifischen Pfade wurden daraufhin vollständig an
`workload_accounts` übertragen. Der korrigierte Gesamtlauf endete mit
`ok=36 changed=0 unreachable=0 failed=0` und bestätigte drei aktive
systemd-User-Manager sowie drei getrennte rootless Podman Graph Roots. Es
wurden keine Images oder Workload-Container angelegt.
---
## 15. Abschlussgrenze dieses Entwurfs
Mit Version 0.8 sind der aktuelle Planungsstand, der ausdrücklich begrenzte
Mit Version 0.9 sind der aktuelle Planungsstand, der ausdrücklich begrenzte
Ansible-Preflight, der verifizierte Deployment-Account und die angewendete
minimale Host-Baseline sowie die Podman-/Quadlet-Grundruntime persistiert.
minimale Host-Baseline, die Podman-/Quadlet-Grundruntime und die getrennten
Workload-Konten persistiert.
Insbesondere wurden noch nicht:
- ein Gitea Runner angelegt,
@@ -733,5 +772,6 @@ Insbesondere wurden noch nicht:
- Backups oder Rollbacks praktisch getestet oder
- die geplante Deploymentkette technisch abgenommen.
Der nächste Dokumentationsschritt ist die Ist-Aufnahme aus Phase A. Auf deren
Ergebnissen baut die verbindliche technische Spezifikation auf.
Die nächsten technischen Schritte sind der begrenzte GPU-Zugriffstest für die
beiden KI-Konten und die Festlegung von Zeitfenster sowie Ressourcenlimits im
getrennten Encoding-Plan. Darauf bauen die jeweiligen Fachrollen und SOPs auf.
+15
View File
@@ -0,0 +1,15 @@
# KI-Dokumentation
Dieser Bereich enthält die fachliche Zielarchitektur und Deployment-Planung für
den KI-Stack. Gemeinsame Host-, Netzwerk- und Sicherheitsgrundlagen liegen in
der [Plattformdokumentation](../platform/README.md). Der CPU-basierte
Video-Encoding-Workload besitzt einen
[eigenen Dokumentationsbereich](../video-encoding/GNENC-000-DOC_Index.md).
| Dokument | Inhalt |
| --- | --- |
| [GNAI-003](GNAI-003-INFRA_Architecture.md) | Zielarchitektur, Komponenten und Datenwege des KI-Stacks |
| [GNAI-007](GNAI-007-PLAN_Ansible-Deployment.md) | nicht finaler Arbeitsentwurf für Ansible- und Gitea-Deployment |
Der übergreifende Projektstand steht im
[zentralen Dokumentationsindex](../GNAI-000-DOC_Index.md).
@@ -15,12 +15,13 @@
| 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. |
| 2026-09-20 | 1.5 | spektr / Codex | Deployment- und getrennte rootless Workload-Konten mit festen IDs und Zuständigkeiten ergänzt. |
---
## 1. Zweck und Geltungsbereich
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`.
Dieses Dokument beschreibt Benutzer, statische IP und SSH des KI-Servers. Der ursprüngliche lesende Kontenabgleich vom 18.09.2026 umfasste `ghost`, `debugofen` und `ghost-agent`; `admin` existiert auf diesem Host nicht. Am 19. und 20.09.2026 kamen der Ansible-Deployment-Account sowie drei gesperrte Workload-Konten hinzu. 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`.
---
@@ -59,6 +60,22 @@ 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.
Die folgenden technischen Konten werden ausschließlich durch das
Ansible-Projekt verwaltet:
| Konto | UID/GID | Zweck | interaktiver Login / sudo |
| --- | --- | --- | --- |
| `ansible-deploy` | 1003 | privilegierte Ansible-Ausführung | SSH-Key, gesperrtes Passwort, `NOPASSWD` gemäß eigener sudoers-Regel |
| `gnai-production` | 980 | rootless AI Production | gesperrtes Passwort, `/usr/sbin/nologin`, kein sudo |
| `gnai-testing` | 981 | rootless AI Testing | gesperrtes Passwort, `/usr/sbin/nologin`, kein sudo |
| `gn-encoding` | 982 | rootless CPU-Encoding | gesperrtes Passwort, `/usr/sbin/nologin`, kein sudo |
Die drei Workload-Konten besitzen nicht überlappende SubUID-/SubGID-Bereiche,
eigene Daten- und Podman-Stores sowie persistente systemd-User-Manager. Ihre
rootverwalteten Quadlet-Verzeichnisse liegen unter
`/etc/containers/systemd/users/<UID>`. Direkte SSH-Schlüssel werden dort nicht
hinterlegt.
---
### 3.2 Statische Netzwerkkonfiguration (Server-Seite)
@@ -170,6 +187,7 @@ sudo systemctl restart ssh
## 4. Abnahmekriterien (Checkliste für den Junior-Admin)
* [ ] **Benutzerprüfung:** `ghost` und `debugofen` können ihre vorgesehenen sudo-Rechte nutzen; `ghost-agent` bleibt ohne sudo-Zuweisung.
* [x] **Workload-Konten:** `gnai-production`, `gnai-testing` und `gn-encoding` besitzen getrennte rootless Podman-Stores und aktive persistente User-Manager; geprüft am 20.09.2026.
* [ ] **Netzwerk:** Server ist unter der statischen IP `10.0.0.90` erreichbar. Ausgehender Datenverkehr funktioniert (`ping google.com`).
* [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*).
@@ -3,7 +3,7 @@
**Dokumenten-ID:** GNAI-004-SEC
**Titel:** Homelab / LLM-Infrastruktur – Sicherheits-, Authentifizierungs- und Zugriffskonzept
**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)
**Vorgänger / Referenzen:** [Architektur](../ai/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)
---
@@ -297,4 +297,4 @@ Das Sicherheitsmodell basiert damit nicht auf einem einzelnen „Security-Progra
## 11. Umsetzungsnachweise
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.
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.
@@ -3,7 +3,7 @@
**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)
**Vorgänger / Referenzen:** [Architektur](../ai/GNAI-003-INFRA_Architecture.md), [Zugriffskonzept](GNAI-004-SEC_Access-Control.md), [WireGuard](GNAI-006-SEC_VPN.md)
---
@@ -2,7 +2,7 @@
**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)
**Referenzen:** [Zielarchitektur](../ai/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)
## Änderungsverlauf
@@ -50,7 +50,7 @@ Der aktuelle Quadlet-Pin `15.4.0` ist durch den Betreiber bestätigt. v15 verwen
| 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.
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/platform/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.
@@ -135,4 +135,4 @@ Diese Beobachtungen bestätigen den breiten Netzpfad und die NAT-Abhängigkeit.
| O8 | Reboot, Firewall-Reload und Restore | offen |
| O9 | wg-easy-GUI-HTTPS und lokales Gruppenmodell | geplant; Werte noch festzulegen |
Andere Sicherheitsbefunde werden im [Dokumentationsindex](GNAI-000-DOC_Index.md) geführt. Dieses Log hält nur WireGuard-Umsetzung und zugehörige Tests fest.
Andere Sicherheitsbefunde werden im [Dokumentationsindex](../GNAI-000-DOC_Index.md) geführt. Dieses Log hält nur WireGuard-Umsetzung und zugehörige Tests fest.
+21
View File
@@ -0,0 +1,21 @@
# Plattform- und Hostdokumentation
Dieser Bereich enthält die gemeinsame Infrastruktur, auf der KI- und
Encoding-Workloads aufbauen. Dazu gehören Hostinstallation, Benutzer und SSH,
das übergreifende Zugriffsmodell, Reverse Proxy und VPN. Workload-spezifische
Architektur und Nutzerverfahren liegen in den jeweiligen Nachbarverzeichnissen.
| Dokument | Inhalt |
| --- | --- |
| [GNAI-001](GNAI-001-INFRA_BaseSystem.md) | Hardware und Debian-Basisinstallation des KI-Servers |
| [GNAI-002](GNAI-002-INFRA_Users.md) | Hostbenutzer, Netzwerk, Resolver und SSH |
| [GNAI-004](GNAI-004-SEC_Access-Control.md) | Rollen- und Zugriffsziel für die Infrastruktur |
| [GNAI-005](GNAI-005-SEC_Reverse-Proxy.md) | Reverse Proxy, Keycloak-Adminpfad und Fail2Ban |
| [GNAI-006](GNAI-006-SEC_VPN.md) | WireGuard-Gateway und Rollen-Firewall |
| [VPN-Client-Verwaltung](GNAI-006-SEC_VPN_Client-Management.md) | Profile ausgeben, ändern und widerrufen |
| [Windows 11](GNAI-006-SEC_VPN_Clients_Windows11.md) | WireGuard-Client unter Windows 11 |
| [Linux](GNAI-006-SEC_VPN_Clients_Linux.md) | WireGuard-Client unter unterstützten Linux-Varianten |
| [VPN-Implementation-Log](GNAI-006-SEC_VPN_Implementation-Log.md) | historische Umsetzung, Tests und Evidenzkorrekturen |
Der übergreifende Projektstand steht im
[zentralen Dokumentationsindex](../GNAI-000-DOC_Index.md).
@@ -0,0 +1,32 @@
# Video-Encoding – Dokumentationsindex und Projektstand
**Dokumenten-ID:** GNENC-000-DOC
**Stand:** 2026-09-20
**Status:** Nicht finaler Arbeitsstand; Encoding-Workload noch nicht installiert
## Dokumente
| Dokument | Zweck / Zielgruppe |
| --- | --- |
| [GNENC-001-PLAN_Architecture.md](GNENC-001-PLAN_Architecture.md) | vorläufige Architektur, Repository-Grenzen, Ressourcenmodell und offene Entscheidungen; Infrastrukturadministratoren |
## Bestätigter Stand
- Das gemeinsame Infrastructure-Repository bleibt die einzige Quelle für den
Ansible-Sollzustand des physischen Servers.
- Encoding-Dokumentation verwendet den getrennten Bereich `docs/video-encoding/`
und die Dokumentenkennung `GNENC`.
- Encoding ist nach Betreiberfestlegung CPU-basiert und darf parallel zur
jeweils aktiven KI-Umgebung laufen.
- Encoding soll ausschließlich außerhalb der Stoßzeiten, zunächst nachts,
automatisch ausgeführt werden.
- Das gesperrte Servicekonto `gn-encoding` mit UID/GID 982 und eigenem
rootless Podman-Store ist eingerichtet und verifiziert.
- Es sind noch kein Encoding-Image, kein Container, keine Quadlet-Unit und kein
Timer eingerichtet.
## Nächste Festlegungen
Vor einer Encoding-Implementierung müssen insbesondere Encoder und
Container-Image, Ein- und Ausgabeverfahren, genaue Zeitfenster, CPU-/I/O-Grenzen,
Abbruchverhalten am Ende des Zeitfensters und Aufbewahrung festgelegt werden.
@@ -0,0 +1,142 @@
# Arbeitsentwurf
**Dokumenten-ID:** GNENC-001-PLAN
**Titel:** CPU-basiertes Video-Encoding auf dem KI-Server
**Stand:** 2026-09-20
**Status:** Nicht finaler Arbeitsentwurf zur Persistierung der Planungsentscheidung
## 1. Zweck und Abgrenzung
Der physische Server `ghostnet-ki` soll neben den KI-Workloads einen getrennten
Workload zum Encoding von Videodateien ausführen. Der Encoding-Workload gehört
nicht zum LLM-Stack. Seine fachliche Architektur, Bedienung und späteren SOPs
werden deshalb in diesem eigenen Dokumentationsbereich geführt.
Ansible, Podman, Betriebssystem und hostweite Ressourcenregeln bleiben
gemeinsame Plattformbestandteile. Sie werden weiterhin ausschließlich im
Infrastructure-Repository verwaltet, damit nicht mehrere Repositories
unabhängig konkurrierende Sollzustände auf denselben Host anwenden.
## 2. Bestätigte Entscheidungen
| Thema | Entscheidung | Nachweisgrenze |
| --- | --- | --- |
| Repository | Host- und Deployment-Ansible bleibt im bestehenden Infrastructure-Repository | angenommen |
| Dokumentation | Encoding erhält `docs/video-encoding/` und die Kennung `GNENC` | umgesetzt |
| Ausführungsidentität | eigenes gesperrtes Konto `gn-encoding`, UID/GID 982 | eingerichtet und mit rootless Podman geprüft |
| Containertrennung | eigener rootless Podman-Store und eigener rootverwalteter Quadlet-Pfad | eingerichtet; noch keine Workload definiert |
| Rechenressource | Encoding ist nach Betreiberfestlegung rein CPU-basiert und erhält keinen GPU-Zugriff | Planungsentscheidung; reale Last noch nicht gemessen |
| Parallelität | darf parallel zu AI Production oder AI Testing laufen | Planungsentscheidung |
| Zeitsteuerung | automatische Ausführung ausschließlich außerhalb der Stoßzeiten, zunächst nachts | Richtung festgelegt; konkrete Uhrzeiten fehlen |
| Anwendungen | konkrete Encoder, Images, Profile und Queue sind noch nicht gewählt | offen |
## 3. Zielbild
```mermaid
flowchart LR
HOST[ghostnet-ki]
PROD[gnai-production\nrootless Podman]
TEST[gnai-testing\nrootless Podman]
ENC[gn-encoding\nrootless Podman]
GPU[beide GPUs]
CPU[CPU / I-O Budget]
TIMER[nächtliche systemd-Zeitsteuerung]
HOST --> PROD
HOST --> TEST
HOST --> ENC
PROD --> GPU
TEST --> GPU
ENC --> CPU
TIMER --> ENC
```
AI Production und AI Testing bleiben untereinander exklusiv. Der
Encoding-Workload ist von dieser KI-Umschaltung unabhängig und darf parallel
zur jeweils aktiven KI-Umgebung laufen. Hostwartung kann weiterhin einen Stopp
aller Workloads erfordern.
## 4. Ressourcen- und Zeitsteuerung
Die nächtliche Einplanung allein schützt Production nicht vollständig: Ein
Encoding-Lauf kann länger dauern als sein Startfenster, und Inferenz benötigt
trotz GPU-Schwerpunkt CPU für Tokenisierung, Netzwerk und Begleitdienste. Die
spätere Encoding-Unit soll deshalb mindestens verwalten:
- ein eindeutig definiertes Zeitfenster mit Zeitzone;
- Verhalten bei verpasstem Start, Neustart und überlangem Lauf;
- maximale CPU-Nutzung oder CPU-Gewichtung;
- niedrigere Scheduling-Priorität gegenüber interaktiven Diensten;
- I/O-Gewichtung und freien Speicher;
- geordneten Abbruch beziehungsweise Abschluss am Ende des erlaubten Fensters;
- Begrenzung auf genau einen gleichzeitigen Encoding-Job.
Konkrete Grenzwerte werden erst nach einem repräsentativen Encoding-Test unter
gleichzeitiger Inferenzlast festgelegt. `gn-encoding` erhält keine Mitgliedschaft
in GPU-Gruppen und keine `/dev/kfd`- oder `/dev/dri`-Weitergabe.
## 5. Repository-Grenzen
Vorgesehene Ansible-Struktur:
```text
ansible/
├── playbooks/
│ ├── host.yml
│ ├── ai.yml
│ ├── video-encoding.yml
│ └── site.yml
└── roles/
├── host_baseline/
├── podman_runtime/
├── workload_accounts/
├── ai_stack/
├── ai_environment_switch/
└── video_encoding/
```
`host.yml` verwaltet ausschließlich gemeinsame Plattformzustände.
`ai.yml` darf nur KI-Zustände verändern. `video-encoding.yml` verwaltet nur das
Konto `gn-encoding`, seine Pfade, Images, Quadlets, Timer und Health Checks. Ein
späteres `site.yml` kann die unterstützte Gesamtkonfiguration in definierter
Reihenfolge anwenden.
Ein separates Quellcode-Repository wird erst benötigt, wenn eigene
Encoding-Software, eine Oberfläche oder ein Queue-Dienst entwickelt wird. Ein
solches Repository erzeugt ein versioniertes Artefakt oder Image; ausschließlich
das Infrastructure-Repository legt fest, welche Version auf dem Server läuft.
## 6. Aktueller Implementierungsstand
Die gemeinsame Rolle `workload_accounts` hat am 20.09.2026 eingerichtet:
```text
Konto: gn-encoding (UID/GID 982)
Konfiguration: /etc/ghostnet-encoding
Daten: /var/lib/ghostnet-encoding
Eingang: /var/lib/ghostnet-encoding/input
Ausgang: /var/lib/ghostnet-encoding/output
Arbeitsdaten: /var/lib/ghostnet-encoding/work
Quadlets: /etc/containers/systemd/users/982
Podman-Store: /var/lib/ghostnet-encoding/.local/share/containers/storage
```
Passwort und interaktive Shell sind gesperrt. Der systemd-User-Manager läuft
dank Linger unabhängig von einer Anmeldung. Der Podman-Store wurde als
rootless und getrennt von beiden KI-Stores geprüft. Es wurden noch keine Images
oder Container angelegt.
## 7. Offene Entscheidungen
1. Welcher Encoder und welches fest versionierte Container-Image werden genutzt?
2. Welche Codecs, Qualitätsprofile und Hardwarekompatibilitäten sind erforderlich?
3. Woher kommen Eingabedateien, und wie werden fertige Dateien abgeholt?
4. Welches konkrete nächtliche Zeitfenster und welche Zeitzone gelten?
5. Darf ein laufender Job das Zeitfenster überschreiten oder wird er gestoppt?
6. Welche CPU-, Speicher- und I/O-Grenzen schützen die KI-Dienste?
7. Wie werden Warteschlange, Wiederholung, Teilresultate und Fehler behandelt?
8. Welche Aufbewahrungs-, Backup- und Löschregeln gelten für Video- und
Arbeitsdateien?
9. Welche Statusanzeige oder Benachrichtigung benötigen Nutzer?
Diese Werte werden nicht vorab in Playbooks angenommen.