Files
operating-automation/docs/05-Security-Hardening.md
Ansible Servercow da81549161 add docs
2026-06-11 18:04:41 +02:00

14 KiB

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:

# 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:

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:

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:

bad_keys:
  - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC... old-compromised-key"
  - "ssh-dss AAAAB3NzaC1kc3MAAACBAP... deprecated-dsa-key"

Standardvariablen (defaults/main.yml):

# 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:

# 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):

ssh-keygen -t ed25519 -C "admin@workstation-$(date +%Y%m%d)"

RSA 4096:

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:

# 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:

# 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:

# 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

# 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:

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

# /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

# 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:
    # 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:
    ssh-keygen -l -f /path/to/public_key.pub
    
  2. Überprüfen Sie Berechtigungen:
    ansible all -i inventories/... \
      -m shell -a "ls -la /root/.ssh/" \
      -b
    
  3. Führen Sie validate-keys Task manuell aus:
    - 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:
    - 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:

# 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:

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

# 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

# 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

# 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 | Nächstes: Virtualisierung →