4.0 KiB
SSH/scp Task-Polling statt NFS-Freigabe (Sicherheits-Umbau 2026-08-03)
Entscheidung
NFS-Freigabe ist OBSOLET. Alle Sub-Agenten erhalten Tasks über SSH/scp (Key-Auth, verschlüsselt).
Grund: NFS (sec=sys) überträgt plaintext → Man-in-the-Middle-fähig. SSH = Ende-zu-Ende verschlüsselt,
nur eigene Tasks sichtbar (gefiltert nach *.C.D.*), auditierbar.
/srv/work/tasks/ bleibt als zentrale Ablage auf dem Master (offen/in_arbeit/fertig/bugfix/archiv),
nur die Zugriffsart änderte sich: kein Mount, sondern pull/push per scp.
Warum NFS hier nicht überall geht
SwitchHermes = Ubuntu 24.04 auf Nintendo-Switch (Tegra-Kernel 4.9.140-l4t):
modprobe nfs→FATAL: Module nfsv4 not found- NFS-Client + FUSE/sshfs fehlen (kein Kernelmodul, wenig Speicher → kein Kernel-Ausbau gewollt) → SSH/scp ist die einzige portable Methode für ARM-Switch-Geräte.
Architecture des SSH-Poller-Daemons
- Jeder Agent hat eigenen ed25519-Key (auf Master:
/root/.ssh/<agent>_mesh), Public-Key inauthorized_keys. - Poller-Script
mesh-agent-poller.sh <meine-IP> <meine-ID> [master] [keyfile]:scppull eigene Tasksoffen/<JahrMonatTag>.<C>.<D>.*.jsonnach/tmp/mesh-tasks/- Atomarer Lock per SSH auf dem Master:
mv offen/... in_arbeit/...(absolute Pfade!),&& echo OK || echo LOST - Bearbeitung via
hermes chat -q "<PROMPT>" --quiet --max-turns 3 - Ergebnis als Base64 ins JSON-Feld
resultschreiben (SSH-python), dannmv in_arbeit/ → fertig/, chmod 0666
- Daemon: systemd-user-service (
~/.config/systemd/user/mesh-poller.service,Restart=always, Loop alle 10s). NICHT nohup/Cron-@reboot als Loop — der stirbt beim SSH-Session-Ende. - Service-Start für User-Services:
export XDG_RUNTIME_DIR=/run/user/$(id -u); systemctl --user ...
Wichtigste Pitfalls (alle live getroffen)
SSH_CMDMUSS den Host enthalten:SSH_CMD="ssh -i $KEY ... root@172.24.196.119". Vergessen →hostname contains invalid characters+ leerer Lock-Output = endlose SKIPs, obwohl der manuellemv-Test auf dem Master klappt.- Relative Pfade im remote-mv vermeiden —
../../../in_arbeitgeht 3 Ebenen hoch statt 1. Nutze absolute Pfade. - Datei-Rechte (Hauptgrund, warum Polling anfangs nie lief): vom Master (root) erstellte/durch
mvbewegte Task-Dateien behalten root-Owner → Sub-Agent (uid 1000) kann nicht reinschreiben, selbst bei 0777-Dir. Fix:chmod 0666nach Task-Erstellung (mesh-task-create.sh) UND nach jedemmvim Poller (in_arbeitUNDfertig). SonstPermissionError: [Errno 13]. - fail2ban bannt Mesh-IPs bei scp-Fehlschlägen →
Connection refusedauf Port 22, obwohl Ping klappt und sshd auf0.0.0.0:22lauscht. Fix:ignoreip = <alle ZT-IPs>in[sshd]-Sektion von/etc/fail2ban/jail.local. Verifizieren:fail2ban-client status sshd→ IP ausBanned IP listnehmen. - Doppelte Daemon-Prozesse (ein nohup-Rest + ein systemd-Rest) stören sich gegenseitig beim Lock.
Nach Umbau:
systemctl --user stop,pkill -9 -f mesh-poller-daemon, PID-Datei löschen, sauberstart. Am Ende MUSSpgrep -f mesh-poller-daemongenau EINEN Prozess zeigen. - "No such file or directory" beim remote-scp-Glob kann heißen, dass der Task bereits in
fertig/liegt (ein früherer Lauf hat ihn gezogen). Erstlsauf Master prüfen, bevor man den Glob verdächtigt.
NFS-Server deaktivieren (nach Migration)
systemctl stop/disable nfs-kernel-server rpcbindufw delete allow from <ip> to any port 2049/111/20048für jede Agenten-IP- Offene Mesh-Ports danach NUR: 22 (SSH), 8644 (Webhook), 11434 (Ollama) — alle gerichtet auf die 4 bekannten ZT-IPs.
/etc/exportsbleibt als Datei liegen, aber inaktiv.
NFS-Export-Härtung (falls man doch NFS nutzen muss)
Export auf die 4 bekannten IPs statt /16, zur
defense-in-depth: UFW-Regel (nur bekannte IPs) UND Export (bekannte IPs) konsistent:
/srv/work/tasks ip1(rw,sync,no_subtree_check,no_root_squash) ip2(...) ...
exportfs -ra reload separat ausführen, NICHT als gateway-gebundener Befehl (wird gekillt).