--- name: security-audit-hardening description: "Linux-Server-Sicherheitsaudit mit automatischer Härtung – SSH, fail2ban, UFW, Angriffserkennung" version: 1.0.0 author: Agent A (netcup VPS Deployer) platforms: [linux] --- # Security Audit & Hardening Schnelles Sicherheitsaudit für Linux-VPS mit Sofortmaßnahmen gegen Bruteforce-Angriffe. ## Audit-Befehl (alles auf einmal) ```bash echo "=== OFFENE PORTS ===" && ss -tlnp | awk '{print $4,$NF}' | sort -u echo "=== UFW ===" && ufw status verbose echo "=== SSH ===" && grep -E "^PermitRootLogin|^PasswordAuthentication|^PubkeyAuthentication|^Port" /etc/ssh/sshd_config echo "=== FAIL2BAN ===" && systemctl status fail2ban 2>/dev/null | head -3 echo "=== SSH-ANGRIFFE ===" && grep -c "Failed password" /var/log/auth.log 2>/dev/null echo "=== AKTIVE ANGREIFER ===" && grep "Failed password" /var/log/auth.log 2>/dev/null | tail -5 | awk '{print $NF}' | sort -u ``` ## Sofortmaßnahmen (in dieser Reihenfolge) ### 1. Aktuelle Angreifer blockieren ```bash # IPs aus Auth-Log extrahieren ufw deny from ``` ### 2. fail2ban installieren ```bash apt-get install -y fail2ban systemctl enable fail2ban systemctl start fail2ban ``` ### 3. fail2ban aggressiv konfigurieren ```bash cat > /etc/fail2ban/jail.local << 'EOF' [DEFAULT] bantime = 3600 findtime = 600 maxretry = 3 [sshd] enabled = true port = ssh maxretry = 3 bantime = 7200 EOF systemctl restart fail2ban ``` ### 4. SSH härten ```bash cat >> /etc/ssh/sshd_config << 'EOF' MaxAuthTries 3 MaxSessions 2 LoginGraceTime 30 ClientAliveInterval 300 ClientAliveCountMax 2 EOF sshd -t && systemctl reload sshd ``` > ⚠️ **Pitfall: Nicht aussperren!** Vor `PasswordAuthentication no` prüfen ob SSH-Keys existieren: `cat /root/.ssh/authorized_keys`. Wenn keine Keys → Passwort-Auth lassen, aber mit fail2ban + MaxAuthTries absichern. > 🔥 **Pitfall: fail2ban bannt eigene Mesh-/Agent-IPs!** SSH/scp-Polling von Sub-Agenten aus (regelmäßige Key-Auth-Verbindungen zum Master) wird von fail2ban als „fehlgeschlagene Login-Versuche" gezählt und gebannt — besonders wenn eine once mal nicht matchen will. **Symptom:** „Connection refused" auf Port 22 NUR für genau eine IP, während Ping geht und andere Agenten noch funktionieren. **Fix — eigene/vertraute IPs dauerhaft whitelisten** in `/etc/fail2ban/jail.local`: ```ini [sshd] ignoreip = 172.24.34.142 172.24.20.26 172.24.178.202 172.24.92.162 ``` Dann `fail2ban-client reload` + `fail2ban-client set sshd unbanip `. WICHTIG: nur EINE `[sshd]`-Sektion pflegen (eine doppelte, appendierte Sektion gilt separat — konsolidieren). ### 5. Webhook-/Mesh-Schnittstellen auf bekannte ZeroTier-Geräte isolieren **Prinzip (NUTZERWUNSCH 2026-08-03):** Kein Subnetz-/16-Catch-all. Mesh-Ports nur für explizit bekannte ZeroTier-IPs freigeben, damit ein unbekanntes Gerät im Netz keine Dienste einschleusen kann. Inkl. Handy (Gerät, kein Agent). ```bash # Bekannte ZT-Geräte einzeln freigeben (Ports: Webhook 8644, NFS 2049/111/20048, Ollama 11434) for ip in 172.24.34.142 172.24.20.26 172.24.178.202 172.24.92.162; do ufw allow from $ip to any port 8644 proto tcp comment 'Webhook Mesh' ufw allow from $ip to any port 2049 proto tcp comment 'NFS Mesh' ufw allow from $ip to any port 111 proto tcp comment 'rpcbind' ufw allow from $ip to any port 111 proto udp comment 'rpcbind U' ufw allow from $ip to any port 20048 proto tcp comment 'nfs lockd' ufw allow from $ip to any port 11434 proto tcp comment 'Ollama Mesh' done ``` **Zuerst alte /16-Regeln löschen:** `ufw delete ` fragt interaktiv → mit `yes |` erzwingen. **Verifikation:** `ufw status | grep '172.24.0.0/16'` darf NICHTS zeigen; `grep -oP '172\\.24\\.\\d+\\.\\d+' | sort -u` darf nur die bekannten IPs listen. > 🔒 **NFS deaktivieren — SSH/scp für Agent-Tasks ist sicherer (2026-08-03).** > NFS (`sec=sys`) transferiert plaintext über TCP → Man-in-the-Middle-anfällig, und braucht > Kernelmodule/FUSE, die auf Tegra-Hosts (Nintendo-Switch: Kernel `4.9.140-l4t` → kein `nfs`/ > kein `fuse`) fehlen. Entscheidung: **alle Sub-Agenten nutzen SSH/scp mit Key-Auth** > (Ende-zu-Ende verschlüsselt), NFS-Server deaktiviert und NFS-Ports (2049/111/20048) aus UFW > entfernt. Das schließt die NFS-Angriffsfläche komplett. Details zum SSH/scp-Polling: > siehe Skill `multi-agent-mesh` (Kontext: Task-Polling über SSH/scp). > ⚠️ **Pitfall:** Nach VPN/Netz-Wechsel (WireGuard→ZeroTier) hängen UFW-Regeln oft noch an alten > Subnetzen (z.B. `10.8.0.0/24`). Immer prüfen, welches Netzwerk jetzt real aktiv ist. ### 6. Automatische Sicherheitsupdates ```bash apt-get install -y unattended-upgrades dpkg-reconfigure -f noninteractive unattended-upgrades ``` ## Audit-Ergebnis bewerten | Signal | Risiko | |--------|--------| | SSH `PasswordAuthentication yes` | 🔴 Bruteforce möglich | | SSH `PermitRootLogin yes` | 🔴 Root direkt angreifbar | | Kein fail2ban | 🔴 Keine Ratenbegrenzung | | Webhook-Port öffentlich | 🟡 API für jeden erreichbar | | >100 Failed Passwords | 🔴 Aktiver Angriff | | UFW default deny | 🟢 korrekt | ## Verhalten bei aktivem Angriff 1. **Nicht in Panik verfallen** — SSH mit Passwort + fail2ban hält 99% der Angriffe ab 2. Angreifer-IPs per `ufw deny` dauerhaft sperren 3. fail2ban-Status prüfen: `fail2ban-client status sshd` 4. Auth-Log monitoren: `tail -f /var/log/auth.log | grep Failed` ## JIT SSH-Portal (nächste Stufe: SSH schließen, 2FA-Freischaltung) Wenn der Server-SSH nicht dauerhaft offen sein soll: baue ein **Just-In-Time-Portal** — Flask + Telegram-2FA + temporäre UFW-Freischaltung (1h Auto-Close). Details + Reset-Rezept: `references/jit-ssh-2fa-portal.md`. **Kern-Pitfall:** Ein End-to-End-Test des Portals überschreibt das echte Passwort (PW-Wechsel-Pflicht) — nach dem Test IMMER zurücksetzen, nie Test-Artefakte im laufenden System hinterlassen. ## Niemals tun - ❌ SSH-Port ändern (security by obscurity, bringt nichts) - ❌ `PermitRootLogin no` ohne funktionierenden SSH-Key - ❌ `PasswordAuthentication no` ohne SSH-Key für ALLE User - ❌ UFW deaktivieren "weil's nicht funktioniert"