add docs
This commit is contained in:
532
docs/05-Security-Hardening.md
Normal file
532
docs/05-Security-Hardening.md
Normal file
@@ -0,0 +1,532 @@
|
||||
# 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)
|
||||
Reference in New Issue
Block a user