# Security & Hardening ## Übersicht Diese Kategorie umfasst Playbooks und Rollen zur Verbesserung der Systemsicherheit, insbesondere SSH-Zugriffsverwaltung und Härtung. **Anwendungsfälle**: - Verwaltung autorisierter SSH-Schlüssel - Entfernung kompromittierter oder veralteter Schlüssel - SSH-Zugriffskontrolle über Whitelisting und Blacklisting - Zentrale SSH-Schlüssel-Verwaltung über mehrere Hosts --- ## Playbooks ### hardening/manage-ssh-keys.yaml Verwaltung von SSH-Schlüsseln für Systemzugriff (Hinzufügen/Entfernen). **Datei**: `playbooks/hardening/manage-ssh-keys.yaml` **Zweck**: Zentrale Verwaltung von SSH-Public-Keys mit Whitelisting (erlaubte Schlüssel) und Blacklisting (zu entfernende Schlüssel) auf allen verwalteten Hosts. **Ziel-Hosts**: `all` **Benutzer**: `tincadmin` (mit sudo-Rechten) **Verwendete Rollen**: - `manage-ssh-keys` **Wichtige Variablen**: | Variable | Typ | Beschreibung | |----------|-----|-------------| | `good_keys` | Liste | Autorisierte SSH-Public-Keys (werden hinzugefügt) | | `bad_keys` | Liste | Zu entfernende SSH-Public-Keys (Blacklist) | | `ssh_user` | String | Zielbenutzer für SSH-Schlüssel (Default: `root`) | **Verwendungsbeispiel**: ```bash # Mit Variablen aus Rolle (defaults/main.yml) ansible-playbook playbooks/hardening/manage-ssh-keys.yaml \ -i inventories/icp-fra-pve1.yml \ -K # Mit externen Variablen (JSON-Format) ansible-playbook playbooks/hardening/manage-ssh-keys.yaml \ -i inventories/icp-fra-pve1.yml \ -e '{"good_keys": ["ssh-ed25519 AAAA... user@host"]}' \ -e '{"bad_keys": ["ssh-rsa AAAA... old-key"]}' \ -K # Nur auf einzelnem Host ansible-playbook playbooks/hardening/manage-ssh-keys.yaml \ -i inventories/icp-fra-pve1.yml \ --limit critical-server.example.com \ -K # Für spezifischen User (nicht root) ansible-playbook playbooks/hardening/manage-ssh-keys.yaml \ -i inventories/icp-fra-pve1.yml \ -e "ssh_user=tincadmin" \ -K ``` **Abhängigkeiten**: - `manage-ssh-keys` Rolle - Sudo-Rechte auf Zielhosts - SSH-Zugriff zu Hosts **Besonderheiten**: - **Kommentierte Variablen** für externe Übergabe im Playbook - **Validierung** von Schlüsseln vor Anwendung - **Idempotent**: Mehrfache Ausführung sicher - **Atomare Operationen**: Erst Validierung, dann Änderung - **Automatisches Backup**: Vor jeder Änderung **Workflow**: 1. Validiert SSH-Schlüssel-Format (good_keys und bad_keys) 2. Überprüft `.ssh`-Verzeichnis-Existenz (erstellt falls nötig) 3. Entfernt Schlüssel aus Blacklist (`bad_keys`) 4. Fügt Schlüssel aus Whitelist (`good_keys`) hinzu 5. Bereinigt Kommentare in authorized_keys 6. Fügt Änderungs-Timestamp hinzu **Sicherheitsaspekte**: - ✅ Whitelisting-Ansatz (explizite Erlaubnis) - ✅ Blacklisting für Revokation kompromittierter Schlüssel - ✅ Automatische Bereinigung alter Einträge - ✅ Audit-Trail durch Timestamps - ✅ Validierung verhindert fehlerhafte Schlüssel --- ## Rollen ### Rolle: manage-ssh-keys **Zweck**: Verwaltet SSH-Schlüssel mit Whitelisting und Blacklisting-Mechanismen für sicheren Systemzugriff. **Pfad**: `roles/manage-ssh-keys/` **Hauptaufgaben**: #### 1. validate-keys.yml Stellt sicher, dass `.ssh`-Verzeichnis existiert und korrekte Berechtigungen hat. **Funktionen**: - Erstellt `.ssh`-Verzeichnis (falls nicht vorhanden) - Setzt Berechtigungen: `0700` (nur Owner kann lesen/schreiben/ausführen) - Erstellt `authorized_keys`-Datei (falls nicht vorhanden) - Setzt Berechtigungen für `authorized_keys`: `0600` **Ausgeführt für User**: ```yaml ssh_user: "root" # Standard, kann überschrieben werden ``` #### 2. add-goodkeys.yml Fügt autorisierte SSH-Public-Keys hinzu. **Funktionen**: - Iteriert über `good_keys`-Liste - Fügt jeden Schlüssel zu `authorized_keys` hinzu - Verhindert Duplikate (idempotent) - Verwendet `authorized_key`-Modul von Ansible **Beispiel good_keys**: ```yaml good_keys: - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIExampleKey1 admin@workstation" - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC... admin@laptop" ``` #### 3. remove-badkeys.yml Entfernt nicht autorisierte oder kompromittierte Schlüssel. **Funktionen**: - Iteriert über `bad_keys`-Liste - Entfernt jeden Schlüssel aus `authorized_keys` - Verwendet `absent`-State in `authorized_key`-Modul - Sicher bei nicht vorhandenen Schlüsseln (idempotent) **Beispiel bad_keys**: ```yaml bad_keys: - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC... old-compromised-key" - "ssh-dss AAAAB3NzaC1kc3MAAACBAP... deprecated-dsa-key" ``` **Standardvariablen** (`defaults/main.yml`): ```yaml # User für SSH-Schlüsselverwaltung ssh_user: "root" # Pfad zu authorized_keys authorized_keys_file: "/{{ ssh_user }}/.ssh/authorized_keys" # Whitelist: Autorisierte SSH-Schlüssel (ca. 20+ Schlüssel) good_keys: - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIExampleKey1" - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIExampleKey2" - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC..." # ... weitere autorisierte Schlüssel # Blacklist: Zu entfernende Schlüssel (6+ revozierte Schlüssel) bad_keys: - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC... old-key-1" - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQD... compromised-key" # ... weitere zu entfernende Schlüssel ``` **Handler**: | Handler | Funktion | |---------|----------| | `Cleanup Comments` | Entfernt alte Kommentare aus authorized_keys | | `Add Comment` | Fügt Änderungs-Timestamp hinzu | **Verwendung in Playbooks**: ```yaml # Vollständige Rolle - name: Manage SSH Keys hosts: all become: true roles: - manage-ssh-keys # Mit custom Variablen - name: Manage SSH Keys for tincadmin user hosts: all become: true roles: - role: manage-ssh-keys vars: ssh_user: tincadmin good_keys: - "ssh-ed25519 AAAAC3... new-admin-key" bad_keys: - "ssh-rsa AAAAB3... old-admin-key" # Einzelne Tasks - name: Add authorized keys only include_role: name: manage-ssh-keys tasks_from: add-goodkeys.yml ``` --- ## SSH-Schlüssel-Typen ### Empfohlene Schlüsseltypen (2026) | Typ | Sicherheit | Empfehlung | Verwendung in Projekt | |-----|------------|------------|----------------------| | **Ed25519** | ⭐⭐⭐⭐⭐ Höchste | ✅ Bevorzugt | Ja (~15+ Schlüssel) | | **RSA 4096** | ⭐⭐⭐⭐ Hoch | ✅ Akzeptabel | Ja (~5+ Schlüssel) | | **ECDSA** | ⭐⭐⭐ Mittel | ⚠️ Mäßig | Nicht im Projekt | | **RSA 2048** | ⭐⭐ Niedrig | ⚠️ Veraltet | Einige Legacy-Keys | | **DSA** | ⭐ Sehr niedrig | ❌ Deprecated | Sollte entfernt werden | ### Schlüssel-Generierung **Ed25519 (empfohlen)**: ```bash ssh-keygen -t ed25519 -C "admin@workstation-$(date +%Y%m%d)" ``` **RSA 4096**: ```bash ssh-keygen -t rsa -b 4096 -C "admin@workstation-$(date +%Y%m%d)" ``` --- ## Best Practices ### 1. Regelmäßiges Key-Rotation Erneuern Sie SSH-Schlüssel regelmäßig: ```bash # Quartalsweise ansible-playbook playbooks/hardening/manage-ssh-keys.yaml \ -i inventories/icp-fra-pve1.yml \ -e '{"good_keys": [...neue Schlüssel...]}' \ -e '{"bad_keys": [...alte Schlüssel...]}' \ -K ``` ### 2. Zentrale Schlüsselverwaltung Pflegen Sie `good_keys` und `bad_keys` in: - `roles/manage-ssh-keys/defaults/main.yml` (Standard) - Externe Variablendateien für verschiedene Umgebungen - Vault-Datei für sensible Schlüssel ### 3. Audit-Trail Dokumentieren Sie Schlüssel-Änderungen: ```bash # Vor Änderung: Backup erstellen ansible all -i inventories/icp-fra-pve1.yml \ -m fetch \ -a "src=/root/.ssh/authorized_keys dest=/backup/ssh-keys/{{ inventory_hostname }}-{{ ansible_date_time.date }}" \ -b # Änderung durchführen ansible-playbook playbooks/hardening/manage-ssh-keys.yaml ... # Verifizierung ansible all -i inventories/icp-fra-pve1.yml \ -m shell -a "wc -l /root/.ssh/authorized_keys" \ -b ``` ### 4. Kompromittierte Schlüssel sofort entfernen Bei Sicherheitsvorfällen: ```bash # Notfall-Entfernung kompromittierter Schlüssel ansible-playbook playbooks/hardening/manage-ssh-keys.yaml \ -i inventories/all.yml \ -e '{"bad_keys": ["ssh-rsa AAAA... KOMPROMITTIERT"]}' \ -K ``` ### 5. Test auf Non-Production zuerst ```bash # Test auf einzelnem Host ansible-playbook playbooks/hardening/manage-ssh-keys.yaml \ -i inventories/icp-fra-pve1.yml \ --limit test-host.example.com \ -e '{"good_keys": [...]}' \ -K # Nach Verifizierung: Rollout ansible-playbook playbooks/hardening/manage-ssh-keys.yaml \ -i inventories/icp-fra-pve1.yml \ -K ``` ### 6. Mehrfache Admin-Keys Verwenden Sie mehrere Admin-Schlüssel für Redundanz: ```yaml good_keys: - "ssh-ed25519 ... primary-admin@workstation" - "ssh-ed25519 ... secondary-admin@laptop" - "ssh-ed25519 ... emergency-admin@spare" ``` --- ## SSH-Daemon-Härtung Während dieses Playbook die Schlüssel verwaltet, sollten Sie auch SSH-Daemon-Konfiguration härten. ### Empfohlene sshd_config-Einstellungen ```ini # /etc/ssh/sshd_config # Nur Public-Key-Authentifizierung PubkeyAuthentication yes PasswordAuthentication no ChallengeResponseAuthentication no # Kein Root-Login mit Passwort PermitRootLogin prohibit-password # Moderne Krypto-Algorithmen KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com # Weitere Härtungen PermitEmptyPasswords no X11Forwarding no MaxAuthTries 3 LoginGraceTime 20 ``` ### Anwendung mit Ansible **Siehe**: [`system` Rolle → ssh-hardening.yaml](07-Basis-System.md#rolle-system) ```bash # SSH-Daemon härten (falls implementiert in system Rolle) ansible-playbook playbooks/hardening/harden-sshd.yml \ -i inventories/icp-fra-pve1.yml \ -K ``` --- ## Fehlerbehebung ### Problem: Aussperrung nach Schlüssel-Entfernung **Symptome**: Kein SSH-Zugriff mehr nach Ausführung **Prävention**: 1. **Immer** mindestens einen funktionierenden Schlüssel in `good_keys` behalten 2. Testen Sie auf einzelnem Host zuerst (`--limit`) 3. Halten Sie Console-Zugriff bereit (z.B. Proxmox VNC) **Lösung bei Aussperrung**: 1. Zugriff über Console (Proxmox, IPMI, etc.) 2. Manuelle Wiederherstellung: ```bash # Via Console echo "ssh-ed25519 AAAA... emergency-key" >> /root/.ssh/authorized_keys ``` 3. Führen Sie Playbook erneut aus mit korrekten Schlüsseln ### Problem: Schlüssel werden nicht hinzugefügt **Symptome**: `good_keys` werden nicht in authorized_keys eingetragen **Lösung**: 1. Überprüfen Sie Schlüssel-Format: ```bash ssh-keygen -l -f /path/to/public_key.pub ``` 2. Überprüfen Sie Berechtigungen: ```bash ansible all -i inventories/... \ -m shell -a "ls -la /root/.ssh/" \ -b ``` 3. Führen Sie validate-keys Task manuell aus: ```yaml - include_role: name: manage-ssh-keys tasks_from: validate-keys.yml ``` ### Problem: Handler werden nicht ausgeführt **Symptome**: Timestamps oder Kommentare fehlen **Lösung**: - Handler laufen erst am Ende des Plays - Erzwingen Sie Handler-Ausführung: ```yaml - meta: flush_handlers ``` - Oder führen Sie Playbook mit `--force-handlers` aus ### Problem: Unterschiedliche Schlüssel pro Umgebung **Symptome**: Dev/Prod benötigen verschiedene Schlüssel-Sets **Lösung**: Verwenden Sie separate Variablendateien: ```bash # Development ansible-playbook playbooks/hardening/manage-ssh-keys.yaml \ -i inventories/dev.yml \ -e "@vars/ssh-keys-dev.yml" \ -K # Production ansible-playbook playbooks/hardening/manage-ssh-keys.yaml \ -i inventories/prod.yml \ -e "@vars/ssh-keys-prod.yml" \ -K ``` **vars/ssh-keys-prod.yml**: ```yaml good_keys: - "ssh-ed25519 ... prod-admin-1" - "ssh-ed25519 ... prod-admin-2" bad_keys: - "ssh-rsa ... old-dev-key" ``` --- ## Compliance und Audit ### DSGVO / Datenschutz SSH-Schlüssel-Management unterstützt Compliance durch: - ✅ **Access Control**: Nur autorisierte Personen - ✅ **Audit Trail**: Timestamps in authorized_keys - ✅ **Revocation**: Schnelle Entfernung kompromittierter Keys - ✅ **Least Privilege**: Spezifische User-Zuordnung ### Audit-Kommandos ```bash # Liste aller autorisierten Schlüssel ansible all -i inventories/icp-fra-pve1.yml \ -m shell -a "cat /root/.ssh/authorized_keys" \ -b # Zähle Schlüssel pro Host ansible all -i inventories/icp-fra-pve1.yml \ -m shell -a "wc -l /root/.ssh/authorized_keys" \ -b # Prüfe auf DSA-Schlüssel (veraltet) ansible all -i inventories/icp-fra-pve1.yml \ -m shell -a "grep 'ssh-dss' /root/.ssh/authorized_keys || echo 'None found'" \ -b # Letzte Änderung ansible all -i inventories/icp-fra-pve1.yml \ -m stat -a "path=/root/.ssh/authorized_keys" \ -b ``` --- ## Weitere Sicherheits-Maßnahmen Neben SSH-Schlüssel-Verwaltung gibt es weitere Härtungs-Maßnahmen im Projekt: ### 1. Fail2Ban (nicht implementiert) Schutz vor Brute-Force-Attacken ### 2. UFW/Firewall (nicht implementiert) Netzwerk-Level-Zugriffsschutz ### 3. Sudo-Beschränkungen Siehe `system` Rolle für zukünftige Implementierung ### 4. SELinux/AppArmor OS-Level Mandatory Access Control --- ## Nützliche Kommandos ### SSH-Schlüssel-Informationen abrufen ```bash # Alle Schlüssel auf Hosts anzeigen ansible all -i inventories/icp-fra-pve1.yml \ -m shell \ -a "cat /root/.ssh/authorized_keys | grep -v '^#' | while read line; do echo \$line | ssh-keygen -l -f - 2>/dev/null || echo 'Invalid: '\$line; done" \ -b # Schlüssel-Typen zählen ansible all -i inventories/icp-fra-pve1.yml \ -m shell \ -a "cat /root/.ssh/authorized_keys | grep -v '^#' | awk '{print \$1}' | sort | uniq -c" \ -b ``` ### Backup erstellen ```bash # Backup aller authorized_keys Dateien ansible all -i inventories/icp-fra-pve1.yml \ -m fetch \ -a "src=/root/.ssh/authorized_keys dest=/backup/ssh-keys/{{ inventory_hostname }}-{{ ansible_date_time.date }}/" \ -b ``` --- **Navigation**: [← Zurück: Mail-Server-Verwaltung](04-Mail-Server-Verwaltung.md) | [Nächstes: Virtualisierung →](06-Virtualisierung.md)