Leitfaden zur Sicherheitshärtung
Einleitung
openDesk Edu basiert auf einem Defense-in-Depth-Sicherheitsmodell. Die Plattform kombiniert mehrere überlappende Sicherheitsschichten — Kubernetes-native Steuerungsmechanismen, dienstübergreifende Authentifizierung über Keycloak, Netzwerksegmentierung durch Kubernetes NetworkPolicies, verschlüsselte Backups via k8up/restic sowie TLS-Terminierung mit automatisiertem Zertifikatsmanagement. Dieser mehrschichtige Ansatz stellt sicher, dass die Kompromittierung einer einzelnen Komponente nicht automatisch zu einer vollständigen Systemverletzung führt.
Dieser Leitfaden geht über die Standardkonfiguration hinaus. Die Basis-Helm-Chart-Werte bieten einen funktionsfähigen und grundlegend sicheren Startpunkt. Produktionsdeployments — insbesondere an deutschen Hochschulen, die personenbezogene Daten gemäß DSGVO und BDSG verarbeiten — erfordern jedoch zusätzliche Härtungsmaßnahmen. Jeder Abschnitt adressiert eine spezifische Angriffsfläche und liefert konkrete, umsetzbare Konfigurationsvorgaben.
Zielgruppe: IT-Sicherheitsteams von Hochschulen, DevOps-Ingenieure und Systemadministratoren, die openDesk Edu im Einklang mit den institutseigenen Sicherheitsrichtlinien und dem deutschen Datenschutzrecht betreiben.
Voraussetzungen: Sie verfügen über ein laufendes openDesk Edu-Deployment und administrativen Zugriff auf den Kubernetes-Cluster (kubectl, helmfile-Zugriff). Grundkenntnisse in Kubernetes-Sicherheitskonzepten werden vorausgesetzt.
Kubernetes-Clustersicherheit
Pod Security Standards
openDesk Edu-Dienste sollten unter dem Kubernetes restricted Pod Security Standard (PSS) ausgeführt werden. Dies verbietet privilegierte Container, Host-Netzwerkzugriff, hostPath-Volumes (außer für spezifische CSI-Treiber) und erlaubt nur Nicht-Root-Container mit read-only Root-Dateisystem.
Durchsetzung des restricted-Profils auf Namespace-Ebene:
apiVersion: v1
kind: Namespace
metadata:
name: opendesk-edu
labels:
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/enforce-version: latest
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/warn: restricted
Einige Dienste (z. B. BigBlueButtons Webcam-Container, bestimmte Monitoring-Agenten) benötigen möglicherweise Ausnahmen auf baseline-Niveau. Erstellen Sie für diese Dienste dedizierte Namespaces mit dem entsprechenden Label und isolieren Sie sie mit NetworkPolicies. Gewähren Sie niemals privileged-Zugriff ohne explizite Sicherheitsüberprüfung.
Network Policies
Das Standarddeployment verwendet eine permissive NetworkPolicy. Für den Produktionsbetrieb implementieren Sie eine Default-Deny-Policy und erlauben nur den erforderlichen Traffic.
Default-Deny für Ingress und Egress:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: opendesk-edu
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
Dienstspezifische Erlaubnisregeln — Beispiel: ILIAS kann nur mit seiner Datenbank und Keycloak kommunizieren:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-ilias-egress
namespace: opendesk-edu
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: ilias
policyTypes:
- Egress
egress:
# Datenbankzugriff (PostgreSQL)
- ports:
- port: 5432
protocol: TCP
to:
- podSelector:
matchLabels:
app.kubernetes.io/name: postgresql
app.kubernetes.io/component: ilias-db
# Keycloak-Authentifizierung
- ports:
- port: 8080
protocol: TCP
to:
- podSelector:
matchLabels:
app.kubernetes.io/name: keycloak
# DNS-Auflösung (Cluster-DNS)
- ports:
- port: 53
protocol: UDP
to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
Dieses Prinzip gilt für alle Dienste. Die folgende Tabelle fasst die empfohlenen Egress-Regeln zusammen:
| Dienst | DB-Zugriff | Keycloak | Internet | Andere Dienste |
|---|---|---|---|---|
| ILIAS | Ja | Ja | Nein | Nein |
| Moodle | Ja | Ja | Nein | Nein |
| Nextcloud | Ja | Ja | Eingeschränkt* | Collabora |
| Grommunio | Ja | Ja | Ja† | DNS, NTP |
| BigBlueButton | Nein | Ja | Nein | Nein |
| Element | Ja | Ja | Ja | Matrix-Föderation |
| XWiki | Ja | Ja | Nein | Nein |
| OpenProject | Ja | Ja | Nein | Nein |
| Monitoring | Nein | Nein | Nein | API-Server |
* Nextcloud benötigt Internetzugriff nur für App-Store-Updates und externe Speicher. In internen Netzwerken blockieren. † Grommunio benötigt SMTP/IMAP-Zugriff auf externe Mail-Server — Egress auf IP-Bereiche bekannter Partner-Mail-Exchanger beschränken.
Pod-Ressourcenlimits
Ressourcenlimits verhindern Denial-of-Service-Angriffe durch Ressourcenverknappung seitens eines kompromittierten oder fehlkonfigurierten Pods. Jeder Workload muss sowohl requests als auch limits gesetzt haben.
Beispiel für Keycloak:
resources:
requests:
memory: "2Gi"
cpu: "1"
limits:
memory: "4Gi"
cpu: "2"
Verwenden Sie ein LimitRange im Namespace, um minimale und maximale Standardwerte durchzusetzen:
apiVersion: v1
kind: LimitRange
metadata:
name: opendesk-edu-limits
namespace: opendesk-edu
spec:
limits:
- default:
memory: "2Gi"
cpu: "2"
defaultRequest:
memory: "512Mi"
cpu: "250m"
type: Container
Seccomp und AppArmor
Aktivieren Sie Runtime-Default-Seccomp-Profile für alle Workloads. Für sensible Dienste (Keycloak, Nextcloud, Grommunio) sollten benutzerdefinierte Seccomp-Profile erwogen werden, die die erlaubten Syscalls weiter einschränken.
securityContext:
seccompProfile:
type: RuntimeDefault
Sofern AppArmor verfügbar ist (Ubuntu-Knoten), wenden Sie Profile auf kritische Dienste an:
annotations:
container.apparmor.security.beta.kubernetes.io/keycloak: local/opendesk-keycloak
Ein typisches benutzerdefiniertes AppArmor-Profil für Keycloak sollte mount, ptrace und exec von unerwarteten Binärdateien unterbinden.
Node-Härtung
- Führen Sie Knoten CIS-Benchmark-konform aus (verwenden Sie
kube-benchzur Validierung). - Halten Sie Knoten-OS-Images aktuell; automatisieren Sie dies mit einem wöchentlichen Update-Fenster.
- Entfernen Sie überflüssige Pakete und Dienste von Knoten-Images. Minimieren Sie die Angriffsfläche.
- Beschränken Sie SSH-Zugriff auf Knoten: Verwenden Sie einen Bastion-Host oder VPN. Kein direkter öffentlicher SSH-Zugriff.
- Aktivieren Sie auditd auf Knoten zur Erfassung von Kernel-Ereignissen (Syscall-Überwachung).
- Nutzen Sie dedizierte Node-Pools für sensible Dienste (Keycloak, Datenbanken) mit Taints und Tolerations, um eine Koexistenz mit weniger vertrauenswürdigen Workloads zu verhindern.
Geheimnisverwaltung (Secret Management)
Aktueller Ansatz
Das Standarddeployment speichert Geheimnisse als Kubernetes Secrets, die über Helm-Werte oder helmfile erstellt werden. Dies birgt mehrere Risiken:
- Geheimnisse können unverschlüsselt in Git-Repositories gelangen (Klartext in values-Dateien).
- Es gibt keinen Rotationslebenszyklus.
- Eingeschränkte Audit-Trail für den Zugriff auf Geheimnisse.
Empfohlen: Sealed Secrets
Sealed Secrets ermöglicht die Verschlüsselung von Kubernetes Secrets in SealedSecret-Custom-Resources, die sicher in Git abgelegt werden können. Nur der Sealed-Secrets-Controller (im Cluster) kann sie entschlüsseln.
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
name: keycloak-admin-secret
namespace: opendesk-edu
spec:
encryptedData:
admin-password: AgBy3i4OJSWK+... (verschlüsselter Payload)
template:
type: Opaque
metadata:
labels:
app.kubernetes.io/name: keycloak
data:
admin-password: "" # Platzhalter, wird durch entschlüsselten Wert ersetzt
Alternative: External Secrets Operator
Für Teams, die bereits HashiCorp Vault, AWS Secrets Manager oder Azure Key Vault einsetzen, synchronisiert der External Secrets Operator Geheimnisse aus externen Stores in Kubernetes:
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
name: vault-backend
namespace: opendesk-edu
spec:
provider:
vault:
server: "https://vault.internal:8200"
path: "opendesk-edu"
version: "v2"
auth:
kubernetes:
mountPath: "kubernetes"
role: "opendesk-edu"
---
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: keycloak-admin
namespace: opendesk-edu
spec:
refreshInterval: "1h"
secretStoreRef:
name: vault-backend
kind: SecretStore
target:
name: keycloak-admin-secret
data:
- secretKey: admin-password
remoteRef:
key: "opendesk-edu/keycloak/admin"
property: "password"
Credential-Rotation
| Credential | Empfohlenes Rotationsintervall | Methode |
|---|---|---|
| Keycloak-Admin-Passwort | 90 Tage | Manuell via UI/API oder External Secrets Operator |
| Datenbank-Passwörter | 90–180 Tage | Helmfile-Neuausführung mit neuen Werten oder via Vault |
| TLS-Private-Keys | 1 Jahr (oder bei Widerruf) | cert-manager-Verlängerung (Let's Encrypt: 90 Tage automatisch) |
| SMTP-/API-Tokens | Je Dienstrichtlinie | External Secrets + regelmäßige Erneuerung |
| k8up/restic-Repository | Bei Vorfall oder jährlich | Neuen Schlüssel generieren; alle Backups neu verschlüsseln |
Vorgehen bei der Datenbank-Passwortrotation:
- Neues Passwort generieren (z. B.
openssl rand -base64 32). - Datenbank-Benutzerpasswort via SQL aktualisieren (
ALTER USER ... PASSWORD '...'). - Das Kubernetes Secret oder SealedSecret aktualisieren.
- Die betroffenen Dienst-Pods neu starten, damit sie das neue Secret übernehmen.
- Konnektivität vom Dienst zur Datenbank überprüfen.
- Das alte Passwort aus allen Credential-Stores entfernen.
TLS-Private-Key-Schutz
- Verwenden Sie cert-manager mit automatisierter Verlängerung, um das Fenster manueller Schlüsselverwaltung zu minimieren.
- Speichern Sie Private Keys ausschließlich in Kubernetes Secrets — exportieren Sie sie niemals in Dateien.
- Für openDesk-Zertifikate (Bundesdruckerei) importieren Sie den Private Key in einem einmaligen, air-gapped Verfahren direkt in ein Secret.
- Beschränken Sie den Zugriff auf TLS-Secrets via RBAC:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: tls-secret-reader
namespace: opendesk-edu
rules:
- apiGroups: [""]
resources: ["secrets"]
resourceNames: ["opendesk-edu-tls"]
verbs: ["get", "list"]
Netzwerksegmentierung
Service Mesh vs. Kubernetes Network Policies
Für die meisten openDesk Edu-Deployments bieten Kubernetes NetworkPolicies eine ausreichende Netzwerksegmentierung. Sie sind einfacher zu verwalten, benötigen keine zusätzliche Kontrollebene und integrieren sich nativ in die vorhandene RBAC.
Ziehen Sie ein Service Mesh (Istio, Linkerd, Cilium) nur in Betracht, wenn Sie folgende Anforderungen haben:
- mTLS zwischen allen Pods (über das Angebot von NetworkPolicies hinaus).
- Feingranulare L7-Traffic-Richtlinien (HTTP-Methodenfilterung, pfadbasierte Weiterleitung).
- Beobachtbarkeit mit Distributed Tracing über alle Dienste hinweg.
Empfohlene NetworkPolicy-Architektur
Das folgende Architekturmodell beschreibt die empfohlenen Isolationsebenen:
- Ingress-Tier — Der Ingress-Controller (nginx-ingress oder vergleichbar) ist der einzige Pod mit einem öffentlich erreichbaren Port. Er leitet Traffic basierend auf Hostname-Regeln weiter.
- Keycloak — Für den Ingress-Controller und alle Dienste erreichbar, die eine Authentifizierung benötigen. Keycloak sollte keine ausgehenden Verbindungen zu beliebigen Diensten initiieren.
- Datenbank-Tier — Jeder Datenbank-Pod ist nur von der zugehörigen Anwendung und dem Backup-Operator (k8up) erreichbar. Kein anderer Pod, einschließlich des Ingress-Controllers, sollte direkt auf Datenbanken zugreifen können.
- LMS-Dienste (ILIAS, Moodle) — Eingeschränkter Egress: nur Datenbank, Keycloak und Shibboleth SP. Kein allgemeiner Internetzugriff.
- Monitoring — Prometheus, Loki und Grafana sollten nur aus einem Admin-VPN oder einem Bastion-Netzwerk erreichbar sein.
Datenbank-Tier — Zugriff beschränkt auf Dienst und Backup-Operator:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: restrict-db-access
namespace: opendesk-edu
spec:
podSelector:
matchLabels:
app.kubernetes.io/component: database
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app.kubernetes.io/component: app
ports:
- port: 5432
- port: 3306
- from:
- podSelector:
matchLabels:
app.kubernetes.io/name: k8up
ports:
- port: 5432
- port: 3306
Keycloak — Zugriff für Ingress und authentifizierte Dienste:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: keycloak-ingress
namespace: opendesk-edu
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: keycloak
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: ingress-nginx
ports:
- port: 8080
- port: 8443
- from:
- podSelector: {} # Alle Pods im Namespace können Keycloak für Authentifizierung erreichen
ports:
- port: 8080
Monitoring — auf Admin-VPN beschränkt:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: restrict-monitoring
namespace: opendesk-edu
spec:
podSelector:
matchLabels:
app.kubernetes.io/component: monitoring
policyTypes:
- Ingress
ingress:
- from:
- ipBlock:
cidr: 10.0.0.0/8 # Durch CIDR des Admin-VPN ersetzen
ports:
- port: 9090 # Prometheus
- port: 3100 # Loki
- port: 3000 # Grafana
Egress-Filterung
Ermitteln Sie, welche Dienste Internetzugriff benötigen. Grundsatz: Standardmäßig verweigern, explizit erlauben.
| Dienst | Internet nötig? | Details |
|---|---|---|
| Keycloak | Bedingt | Föderations-Metadaten-Refresh; blocken bei statischen Metadaten |
| Nextcloud | Eingeschränkt | App-Store, externe Speicher — in internen Netzwerken blocken |
| Grommunio | Ja | SMTP/IMAP zu externen Mail-Servern — IP-Bereiche whitelisten |
| Element | Ja | Matrix-Föderation — wenn möglich auf bekannte Server beschränken |
| Moodle/ILIAS | Nein | Alle Inhalte intern gehostet |
| BigBlueButton | Nein | Keine externen Abhängigkeiten |
| Alle Datenbanken | Nein | Streng intern |
| k8up (restic) | Ja | S3-kompatibler Speicher-Endpoint — nur die S3-URL whitelisten |
| cert-manager | Ja | ACME-Challenge-Endpunkt oder openDesk-CA-API |
Authentifizierungshärtung
Keycloak-Sitzungsverwaltung
Konfigurieren Sie angemessene Sitzungs-Timeout-Werte, um das Zeitfenster für gestohlene Sitzungstoken zu begrenzen.
| Einstellung | Wert | Begründung |
|---|---|---|
| SSO Session Max | 8 Stunden | Entspricht einem Arbeitstag |
| SSO Session Idle | 30 Minuten | Automatische Abmeldung bei Inaktivität |
| Access Token Lifetime | 5 Minuten | Minimiert das Fenster für gestohlene Token |
| Refresh Token Max | 12 Stunden | Tägliche Neuauthentifizierung erforderlich |
| Refresh Token Idle | 30 Minuten | Refresh-Token verfallen bei Inaktivität |
| Client Session Max | 1 Tag | Begrenzt anwendungsspezifische Sitzungen |
| Offline Session Max | 30 Tage | Nur für genehmigte Clients; Standard auf 0 (Offline deaktiviert) |
Aktivieren Sie Refresh-Token-Rotation und Refresh-Token-Widerruf bei Wiederverwendung, um Token-Diebstahl zu erkennen.
Passwortrichtlinie
Konfigurieren Sie die integrierte Passwortrichtlinie in Keycloak:
| Richtlinie | Wert | Begründung |
|---|---|---|
| Mindestlänge | 12 Zeichen | NIST SP 800-63B-Empfehlung |
| Mindestens eine Ziffer | Aktiviert | Komplexitätsanforderung |
| Mindestens ein Kleinbuchstabe | Aktiviert | Komplexitätsanforderung |
| Mindestens ein Großbuchstabe | Aktiviert | Komplexitätsanforderung |
| Mindestens ein Sonderzeichen | Aktiviert | Komplexitätsanforderung |
| Passwort-Historie | 5 Passwörter | Verhindert Passwortwiederverwendung |
| Passwortablauf | 180 Tage | Regelmäßige Rotation |
| Nicht kürzlich verwendet | Deaktiviert | Vermeidet Usability-Einbußen ohne Sicherheitsgewinn |
Multi-Faktor-Authentifizierung
openDesk Edu unterstützt MFA über Keycloak-Authentifizierungsflüsse. Zwei Ansätze werden empfohlen:
WebAuthn/FIDO2 für Administrationskonten:
Administratoren (Keycloak-Realm-Administratoren, Dienstoperatoren) sollten zur Registrierung eines Hardware-Sicherheitsschlüssels (YubiKey, Nitrokey oder Plattform-Authentifikator) verpflichtet werden. Dies verhindert, dass gestohlene Anmeldedaten zu einer vollständigen administrativen Übernahme führen.
# In der Keycloak-Admin-Konsole:
# 1. Authentifizierungsfluss "Admin MFA" erstellen
# 2. "WebAuthn Authenticator" als REQUIRED hinzufügen
# 3. Diesen Fluss an alle Admin-Rollen binden
# 4. Benutzer auffordern, beim nächsten Login ihren Sicherheitsschlüssel zu registrieren
TOTP für reguläre Benutzer:
Zeitbasierte Einmalpasswörter (via Authenticator-Apps) bieten eine zugängliche MFA-Methode für die allgemeine Nutzerbasis.
Brute-Force-Schutz
Keycloaks integrierte Brute-Force-Erkennung:
- Maximale Anmeldefehler: 5
- Reset-Zeit bei Fehlern: 300 Sekunden
- Wartezeit-Inkrement: 60 Sekunden
- Quick Login Check: Aktiviert
Zusätzlich fail2ban auf dem Ingress-Knoten einsetzen, um HTTP-401-Antworten auf den Keycloak-Auth-Endpunkt zu ratenbegrenzen:
[keycloak-auth]
enabled = true
port = http,https
filter = keycloak-auth
logpath = /var/log/nginx/access.log
maxretry = 10
findtime = 60
bantime = 600
Rate Limiting auf Ingress-Ebene
Konfigurieren Sie den Ingress-Controller (nginx-ingress) mit globalen Ratenbegrenzungen:
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-ingress-rate-limit
namespace: ingress-nginx
data:
limit-rps: "50"
limit-burst: "100"
limit-whitelist: "10.0.0.0/8" # Interne Netzwerke von Ratenbegrenzung ausnehmen
Für den Keycloak-Auth-Endpunkt spezifisch eine strengere Annotation verwenden:
nginx.ingress.kubernetes.io/limit-rps: "10"
nginx.ingress.kubernetes.io/limit-burst: "20"
nginx.ingress.kubernetes.io/limit-whitelist: "10.0.0.0/8"
Audit-Logging und Monitoring
Was protokolliert werden sollte
| Ereignistyp | Log-Quelle | Aufbewahrung | Sensitivität |
|---|---|---|---|
| Authentifizierung Erfolg/Fehler | Keycloak | 1 Jahr | Personenbezogen |
| Admin-Konsolen-Aktionen | Keycloak, Kubernetes | 2 Jahre | Hoch |
| Pod-Erstellung/-Löschung/-Änderung | Kubernetes-Audit-Log | 1 Jahr | Metadaten |
| Network-Policy-Verstöße | Cilium/Calico-Netzwerk | 90 Tage | Metadaten |
| Backup Erfolg/Fehler | k8up | 1 Jahr | Metadaten |
| TLS-Zertifikatsablauf | cert-manager | 1 Jahr | Metadaten |
| Resource-Quota-Verstöße | Kubernetes | 90 Tage | Metadaten |
| API-Server-Zugriff | Kubernetes-Audit-Log | 2 Jahre | Hoch |
Log-Aggregation
Setzen Sie den Loki-Stack (Grafana Loki, Promtail, Grafana) zur zentralen Log-Sammlung ein. Dieser ist gegenüber Elasticsearch für Kubernetes-native Log-Aggregation zu bevorzugen, da er eine geringere Ressourcenbelastung und native Integration mit Prometheus-Metriken bietet.
# Promtail-Konfigurationsausschnitt — Keycloak-Logs scrapen
scrape_configs:
- job_name: kubernetes-pods
kubernetes_sd_configs:
- role: pod
pipeline_stages:
- cri: {}
relabel_configs:
- source_labels: [__meta_kubernetes_pod_label_app_kubernetes_io_name]
action: keep
regex: keycloak|nextcloud|ilias|moodle|grommunio|matrix
Alarmierungsregeln
Konfigurieren Sie den Prometheus Alertmanager mit sicherheitsrelevanten Alarmen:
| Alarmname | Bedingung | Schweregrad |
|---|---|---|
HighFailedLogins |
Rate der 401-Fehler auf Keycloak > 10/min für 5 Minuten | Kritisch |
KeycloakAdminLogin |
Admin-Konsolen-Login-Ereignis | Warnung |
PodCrashLooping |
Pod im CrashLoopBackOff > 5 Minuten | Kritisch |
TLSExpiringSoon |
Zertifikat läuft in < 30 Tagen ab | Warnung |
BackupFailure |
k8up-Backup-Job fehlgeschlagen | Kritisch |
PersistentVolumeUsageHigh |
PV-Auslastung > 85 % | Warnung |
NetworkPolicyViolation |
Verweigerte Verbindung geloggt | Info |
Log-Aufbewahrung und DSGVO-Compliance
Logs, die personenbezogene Daten enthalten (z. B. IP-Adressen in Authentifizierungslogs), dürfen nur so lange aufbewahrt werden, wie es erforderlich ist.
- Access-Logs (IP-Adressen): 7 Tage Rohdaten, 30 Tage anonymisiert (letztes Oktett abschneiden).
- Authentifizierungslogs: 1 Jahr (erforderlich für forensische Analysen).
- Keycloak-Admin-Aktionen: 2 Jahre (Compliance mit BDSG § 83).
- Kubernetes-Audit-Logs: Dynamischen Audit-Webhook konfigurieren mit Aufbewahrungsfrist gemäß institutioneller Richtlinie.
Verwenden Sie Log-Masking, um sensible Felder (Passwörter, Sitzungstoken, personenbezogene Identifikatoren) zu schwärzen, bevor Logs die Aggregationsebene erreichen. Promtail unterstützt regex-basierte replace-Stages zu diesem Zweck.
Datenschutz (DSGVO-Compliance)
Verschlüsselung ruhender Daten (Encryption at Rest)
Alle Persistent Volumes sollten verschlüsselt sein. Für On-Premise-Deployments:
- Verwenden Sie CSI-Treiber mit Volume-Verschlüsselung (z. B. LUKS auf dem Storage-Backend oder der CSI-Treiber verwaltet LUKS pro Volume).
- Für Cloud-Deployments verwenden Sie verschlüsselte Cloud-Datenträger (AWS EBS-Verschlüsselung, Azure Disk Encryption at Rest, GCE PD-Verschlüsselung).
Datenbankseitige Verschlüsselung sollte aktiviert werden:
-- PostgreSQL: TDE aktivieren oder pgcrypto für spaltenweise Verschlüsselung nutzen
CREATE EXTENSION IF NOT EXISTS pgcrypto;
-- MariaDB/MySQL: Tablespace-Verschlüsselung
CREATE TABLE sensitive_data (...) ENCRYPTION='Y';
Datenklassifikation
Die folgende Tabelle ordnet jedem Dienst die gespeicherten personenbezogenen Daten und Metadaten zu. Diese Klassifikation ist Grundlage für die Risikobewertung nach DSGVO Art. 32 und für die Erstellung des Verarbeitungsverzeichnisses (Art. 30 DSGVO).
| Dienst | Gespeicherte personenbezogene Daten | Gespeicherte Metadaten |
|---|---|---|
| Keycloak | Benutzerprofile, E-Mail, Gruppenmitgliedschaften | Login-Zeitstempel, IP-Adressen |
| Nextcloud | Dateien, Benutzerprofile, Freigabe-Metadaten | Zugriffslogs, Datei-Metadaten |
| OpenCloud | Dateien, Benutzerprofile | Zugriffslogs, Datei-Metadaten |
| Grommunio | E-Mails, Kontakte, Kalenderdaten | Mail-Header, Zugriffslogs |
| OX App Suite | E-Mails, Kontakte, Kalender, Dateien | Zugriffslogs, Nutzungsanalysen |
| SOGo | E-Mails, Kontakte, Kalender | Zugriffslogs |
| Moodle/ILIAS | Benutzerprofile, Kursdaten, Noten | Aktivitätslogs, Quiz-Daten |
| BigBlueButton | Aufzeichnungen (falls aktiviert), Chat-Logs | Anwesenheitsdaten, Sitzungsmetadaten |
| Element/Matrix | Chat-Nachrichten, Benutzerprofile | Raum-Metadaten, Föderationslogs |
| XWiki | Benutzerprofile, Seiteninhalte | Bearbeitungsverlauf, Seitenaufruf-Logs |
| OpenProject | Benutzerprofile, Projektdaten | Aktivitätslogs, Zeiterfassung |
| Zammad | Benutzerprofile, Ticket-Inhalte | Zugriffslogs, Agentenaktivität |
| CryptPad | Verschlüsselte Dokumente (Zero-Knowledge) | Sitzungsmetadaten (minimal) |
Datenaufbewahrung und -löschung
Die Aufbewahrungsfristen orientieren sich an den Grundsätzen der DSGVO Art. 5 Abs. 1 lit. e (Speicherbegrenzung) sowie an den hochschulspezifischen Vorgaben der Landesdatenschutzgesetze.
| Datentyp | Aufbewahrungsfrist | Löschmethode |
|---|---|---|
| Benutzerprofile | Kontolöschung + 30 Tage | Keycloak-Benutzerlöschung + DB-Bereinigung |
| Kurs-/LMS-Inhalte | 2 Jahre nach Kursende | Soft-Delete + 90-tägige Gnadenfrist |
| E-Mail-Inhalte | Gemäß Nutzerrichtlinie | IMAP-Löschung oder administrative Bereinigung |
| Dateispeicher | Gemäß Nutzerrichtlinie | Sofortlöschung aus PV + Backup |
| Authentifizierungslogs | 1 Jahr | Partition-Drop oder Log-Rotation |
| Sitzungsdaten | Sitzungsende + 1 Tag | Automatische Bereinigung durch Keycloak |
| Backup-Daten | Gemäß Richtlinie (30–365 Tage) | restic forget + prune |
Recht auf Löschung und Datenübertragbarkeit
openDesk Edu unterstützt die Anforderungen aus DSGVO Art. 17 (Recht auf Löschung) und Art. 20 (Recht auf Datenübertragbarkeit) durch:
- Keycloaks Self-Service für Profil-Export und Kontolöschung.
- Nextcloud/OpenClouds OCM-API für Datei-Portabilität zwischen Instanzen.
- Grommunios IMAP-Export-Funktionen.
- Moodle/ILIAS-Benutzerdaten-Export-Plugins.
Etablieren Sie einen operativen Prozess:
- Lösch-/Portabilitätsantrag eingegangen.
- Identität prüfen (z. B. via Hochschul-E-Mail oder persönliche Identifikation).
- Daten innerhalb von 30 Tagen exportieren (DSGVO Art. 12 Compliance).
- Datenlöschung in allen Diensten durchführen.
- Backup-Aufbewahrungsfrist abwarten (oder bei Sofortlöschungsbedarf eine Notfall-Backup-Rotation durchführen).
- Den Löschantrag und seine Erfüllung dokumentieren.
Backup-Verschlüsselung
Das k8up/restic-System verschlüsselt Backups bereits im Ruhezustand und während der Übertragung. Stellen Sie Folgendes sicher:
- Das restic-Repository-Passwort wird in einem SealedSecret oder Vault gespeichert — niemals im Klartext.
- Backup-Daten werden mit AES-256-GCM verschlüsselt (Standard bei restic).
- Der S3-Backup-Endpoint verwendet TLS (HTTPS).
- Wiederherstellungsverfahren werden vierteljährlich getestet, einschließlich der Entschlüsselungsprüfung.
Vorlage Incident-Response-Plan
Jedes openDesk Edu-Deployment sollte einen Incident-Response-Plan vorhalten. Die folgende Vorlage berücksichtigt die spezifischen Meldepflichten gemäß DSGVO Art. 33 (Meldung an Aufsichtsbehörde) und Art. 34 (Benachrichtigung betroffener Personen).
# INCIDENT-RESPONSE-PROTOKOLL
## 1. Erkennung
- Erkannt durch: [Monitoring-Alarm / Benutzermeldung / externe Benachrichtigung]
- Datum/Uhrzeit: JJJJ-MM-TT HH:MM UTC
- Beschreibung:
- Schweregrad (Kritisch / Hoch / Mittel / Niedrig):
## 2. Eindämmung
- Ergriffene Maßnahmen zur Schadensbegrenzung:
- Kompromittierte Systeme via NetworkPolicy isoliert:
- Credentials rotiert:
- Dienst-Pods neu gestartet:
## 3. Bewertung
- Betroffene Datentypen: [personenbezogene Daten / Credentials / Metadaten / keine]
- Geschätzte Anzahl betroffener Nutzer:
- Handelt es sich um eine DSGVO-meldepflichtige Verletzung? [Ja / Nein]
- Falls ja: Aufsichtsbehörde innerhalb von 72 Stunden benachrichtigt.
## 4. Beseitigung
- Ursache identifiziert:
- Schwachstelle behoben:
- Backdoor oder Persistenzmechanismus entfernt:
## 5. Wiederherstellung
- Aus Backup wiederhergestellt: [ja / nein, Zeitstempel]
- Dienst als betriebsbereit verifiziert:
- Monitoring mit zusätzlichen Alarmen reaktiviert:
## 6. Post-Mortem
- Lessons Learned:
- Korrekturmaßnahmen (mit Verantwortlichen und Fristen):
- Bericht erstellt von:
Dienstspezifische Härtung
Keycloak
- Admin-Konsolen-Beschränkung: Wenden Sie eine NetworkPolicy an, die den Zugriff auf den Keycloak-Admin-Konsolen-Port (standardmäßig 8443) auf einen dedizierten Admin-VPN-CIDR-Bereich beschränkt. Der öffentliche Ingress sollte nur zum Authentifizierungs-Endpunkt (
/authoder/realms/) leiten. - Benutzerdefiniertes Theme: Ersetzen Sie das Standard-Keycloak-Theme, um Version-Fingerprinting zu vermeiden. Ändern Sie mindestens Logo, Footer-Text und Seitentitel. Dies erschwert gezielte Angriffe auf bekannte Keycloak-CVEs.
- Standard-Benutzerregistrierung deaktivieren, falls nicht erforderlich (Hochschulen provisionieren Benutzer typischerweise via LDAP/DFN-AAI-Föderation).
- Grant-Types einschränken auf die tatsächlich benötigten (Authorization-Code-Flow für Web-Apps; implizite und Password-Grants deaktivieren).
Nextcloud
- Brute-Force-Schutz: Nextcloud verfügt über eine integrierte Ratenbegrenzung. Konfigurieren Sie:
'ratelimit.enabled' => true, 'ratelimit.limit' => 30, 'ratelimit.period' => 60, - Dateizugriffskontrolle: Setzen Sie die Nextcloud Files Access Control App ein, um Dateioperationen basierend auf Gruppenmitgliedschaft, IP-Bereich oder Tageszeit zu beschränken.
- Freigaberichtlinien: Deaktivieren Sie öffentliche Link-Freigaben standardmäßig; erlauben Sie nur Gruppen-Freigaben. Verlangen Sie Passwort und Ablaufdatum für jede externe Freigabe.
- App-Verwaltung: Entfernen Sie ungenutzte Apps (
appstoreenabled→ in config.php deaktivieren). Überprüfen Sie installierte Apps regelmäßig.
Moodle / ILIAS
- LTI-Sicherheit: Konfigurieren Sie LTI 1.3 (nicht 1.0/1.1) für die Tool-Interoperabilität. Verwenden Sie signierte Nachrichten und erzwingen Sie TLS.
- SSO-Erzwingung: Deaktivieren Sie die lokale passwortbasierte Anmeldung. Die gesamte Authentifizierung muss über Keycloak/SAML erfolgen. In Moodle:
manual- undemail-Authentifizierungs-Plugins deaktivieren; nursamloderoidcaktivieren.
In ILIAS: lokale Authentifizierung in der// Moodle config.php $CFG->auth = 'auth_saml2';ilias.ini.phpdeaktivieren. - Rollen-Audit: Überprüfen Sie regelmäßig die Zuweisung von Administrator- und Manager-Rollen. Exportieren Sie Rollenlisten monatlich und vergleichen Sie sie mit dem Sollzustand.
- Sitzungssicherheit: Erzwingen Sie HTTPS-Only-Cookies; setzen Sie das Sitzungs-Timeout auf 30 Minuten Inaktivität.
Grommunio
-
SMTP-Submission-Beschränkungen: Deaktivieren Sie Open Relay. Verlangen Sie Authentifizierung für SMTP-Submission (Port 587). Beschränken Sie SMTP AUTH auf bekannte Benutzer.
-
Ratenbegrenzung: Grommunio unterstützt
smtpd_client_connection_rate_limit. Konfigurieren Sie:smtpd_client_connection_rate_limit = 100 smtpd_client_message_rate_limit = 50 -
SPF/DKIM/DMARC: Konfigurieren Sie E-Mail-Authentifizierung für alle ausgehenden Domains. Dies verhindert, dass Ihre Domain für Spoofing-Angriffe verwendet wird:
- SPF-Einträge für alle sendenden Domains veröffentlichen.
- DKIM-Schlüssel generieren und den öffentlichen Schlüssel in DNS veröffentlichen.
- DMARC mit
p=quarantineeinrichten, nach Überwachung aufp=rejectverschärfen.
Die Absicherung von E-Mail-Kommunikation ist insbesondere im Hochschulkontext relevant, um Phishing-Angriffe auf Studierende und Beschäftigte zu erschweren. Das BSI empfiehlt in seiner IT-Grundschutz-Komponente APP.3.8 (E-Mail) die vollständige Implementierung dieser Verfahren.
BigBlueButton
- Aufzeichnungs-Zugriffskontrolle: Speichern Sie Aufzeichnungen in einem zugriffsgeschützten Bucket. Verlangen Sie Authentifizierung für die Wiedergabe. Löschen Sie Aufzeichnungen nach 90 Tagen oder gemäß institutioneller Richtlinie.
- API-Secret-Rotation: Rotieren Sie das BBB-Shared-Secret regelmäßig (oder verwenden Sie sitzungsbasierte HMAC-Schlüssel).
- Gastzugriff deaktivieren in der Standardkonfiguration; nur nach explizitem Genehmigungs-Workflow aktivieren.
- Greenlight (Frontend): Beschränken Sie die Raumerstellung auf authentifizierte Benutzer.
Element / Matrix
- Föderationsrichtlinie: Entscheiden Sie basierend auf den institutionellen Anforderungen:
- Eingeschränkte Föderation: Nur Föderation mit bekannten Hochschulen (DFN-Matrix-Homeserver) zulassen. Den Rest blockieren.
- Offene Föderation: Föderation mit allen Servern zulassen, aber auf Spam und Missbrauch überwachen.
- Raumzugriffskontrollen: Standardmäßig Räume als "Nur auf Einladung" erstellen. Öffentliche Raumliste deaktivieren, sofern nicht explizit benötigt.
- Content-Scanning: Setzen Sie einen Matrix-Content-Scanner ein, um Malware in geteilten Dateien zu blockieren.
- Ratenbegrenzung bei Registrierung: Verhindern Sie Account-Creation-Abuse durch Konfiguration von Synapse-Ratenbegrenzungen.
Schwachstellenmanagement
Aktualisierung von Abhängigkeiten
openDesk Edu verwendet Helm-Chart-Abhängigkeiten. Führen Sie helmfile deps update regelmäßig durch und testen Sie Aktualisierungen zuerst in einer Staging-Umgebung, bevor Sie sie in der Produktion einsetzen.
Empfohlener Aktualisierungsrhythmus:
| Abhängigkeitstyp | Aktualisierungsfrequenz | Reaktion auf kritische CVEs |
|---|---|---|
| Basis-Kubernetes | Vierteljährlich | Innerhalb von 7 Tagen |
| Helm-Charts | Monatlich | Innerhalb von 48 Stunden |
| Container-Images | Monatlich | Innerhalb von 24 Stunden |
| Keycloak | Pro Patch-Release | Innerhalb von 7 Tagen |
| Dienst-Apps | Pro Patch-Release | Innerhalb von 14 Tagen |
Überwachung von CVEs
Verfolgen Sie CVEs für die Stack-Komponenten:
- Keycloak: Abonnieren Sie die Keycloak-Sicherheitsadvisories.
- Kubernetes: Beobachten Sie die Kubernetes-Sicherheits-Mailingliste.
- Dienstkomponenten: Verwenden Sie Trivy zur automatisierten Container-Image-Scans in CI/CD:
# GitLab-CI-Beispiel — Container-Images bei jedem Build scannen
trivy image:
script:
- trivy image --severity CRITICAL,HIGH --exit-code 1 $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
Patch-Prozedur
- Staging-Test: Das Update in einer Staging-Umgebung deployen, die die Produktion abbildet. Integrationstests und Sicherheitsscans durchführen.
- Rolling-Update: In der Produktion mittels Helmfile inkrementell ausrollen (ein Dienst nach dem anderen).
- Verifikation: Service-Health-Endpoints, Keycloak-Authentifizierungsfluss und Datenbank-Konnektivität prüfen. Prometheus auf Anomalien überwachen.
# Beispiel für ein Rolling-Update eines einzelnen Dienstes
helmfile -e production -l name=nextcloud apply --suppress-diff
# Auf Abschluss des Rollouts warten
kubectl rollout status deployment/nextcloud -n opendesk-edu --timeout=10m
# Verifizieren
kubectl get events -n opendesk-edu --sort-by='.lastTimestamp'
Sicherheitsscans
- Trivy: Scannen Sie alle Container-Images in der Deployment-Pipeline. Blockieren Sie Deployments bei CRITICAL- oder HIGH-Findings, für die ein Fix verfügbar ist.
- Clair: Wenn Sie Harbor als Container-Registry verwenden, aktivieren Sie Clair für kontinuierliche Scans.
- kube-bench: Führen Sie wöchentliche CIS-Benchmark-Prüfungen gegen die Cluster-Knoten durch.
- kube-hunter: Führen Sie regelmäßige Scans zur Identifikation von Kubernetes-Schwachstellen durch.
- Network-Policy-Audit: Überprüfen Sie, ob alle Dienste über definierte NetworkPolicies verfügen. Verwenden Sie
kubectl get networkpolicies -n opendesk-eduund gleichen Sie mit Ihrem Policy-Dokument ab.
Incident Response
Erkennung
Die folgenden Alarme sollten in Ihrem Monitoring-Stack konfiguriert sein:
| Alarm | Auslöser | Reaktions-SLA |
|---|---|---|
| Brute-Force-Angriff | > 10 fehlgeschlagene Keycloak-Logins/min für 5 Min | < 15 Min |
| Unbekannter Admin-Login | Keycloak-Admin-Konsolen-Login außerhalb der Geschäftszeiten | < 30 Min |
| Pod-Kompromittierung | Pod-Crash-Loop + unerwartete Netzwerkverbindungen | < 15 Min |
| Datenextraktion | Ungewöhnliches Egress-Traffic-Volumen (> 1 GB/h) | < 10 Min |
| Geheimnis-Offenlegung | Secret-Store meldet unbefugten Zugriff | Sofort |
| Backup-Fehler | k8up-Job schlägt 2+ aufeinanderfolgende Male fehl | < 30 Min |
| TLS-Zertifikat abgelaufen | Zertifikatsprüfung fehlgeschlagen | < 1 Stunde |
Eindämmung (Containment)
Wenn eine Kompromittierung erkannt wird:
- Eine isolierende NetworkPolicy auf den kompromittierten Namespace oder Pod anwenden:
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: isolate-compromised namespace: opendesk-edu spec: podSelector: matchLabels: app.kubernetes.io/name: compromised-service policyTypes: - Ingress - Egress - Alle Geheimnisse des kompromittierten Dienstes rotieren (Datenbank-Credentials, API-Tokens, Keycloak-Client-Secrets).
- Das kompromittierte Deployment auf Null herunterskalieren (falls der Dienst offline genommen werden kann) oder Pods durch eine bekannte, saubere Version ersetzen.
- Die Angreifer-IP im Ingress-Controller via fail2ban oder manuelle ipBlock-Regel blockieren.
- Forensische Daten sichern — Pod-Logs vor der Rotation sichern.
Beseitigung (Eradication)
- Die Ursache identifizieren (ungepatchter CVE, Fehlkonfiguration, durchgesickertes Credential).
- Den notwendigen Patch oder die Konfigurationskorrektur einspielen.
- Backdoors oder Persistenzmechanismen entfernen (unbekannte Cron-Jobs, Sidecar-Container, modifizierte Images).
- Alle Service-Accounts und RBAC-Bindings im betroffenen Namespace auditieren.
Wiederherstellung (Recovery)
- Den Dienst aus einem bekannten, sauberen Backup wiederherstellen (k8up restic restore).
- Dienstintegrität prüfen — Datenkonsistenz, Benutzerauthentifizierung und alle Integrationen verifizieren.
- Netzwerkzugriff schrittweise nach dem Prinzip der geringsten Privilegien wiederherstellen.
- Betroffene Nutzer gemäß institutioneller Richtlinie und DSGVO Art. 34 benachrichtigen (falls personenbezogene Daten betroffen sind).
Post-Mortem
Nach der Behebung des Vorfalls dokumentieren Sie den vollständigen Zeitablauf, die Ursache, die ergriffenen Maßnahmen und die gewonnenen Erkenntnisse. Verwenden Sie die Vorlage im Abschnitt Vorlage Incident-Response-Plan. Das Post-Mortem sollte vom Sicherheitsteam überprüft und zur Aktualisierung dieses Härtungsleitfadens verwendet werden.
Referenzen
- Kubernetes Pod Security Standards
- Kubernetes NetworkPolicies
- Sealed Secrets
- External Secrets Operator
- Keycloak Server Administration Guide
- k8up — Kubernetes Backup Operator
- restic Dokumentation
- BSI IT-Grundschutz
- BSI IT-Grundschutz-Komponente APP.3.8 (E-Mail)
- DSGVO — Verordnung (EU) 2016/679
- BDSG — Bundesdatenschutzgesetz
- DFN-AAI / eduGAIN
