Stack absichern (1/2): Perimeter, Zugang, Cluster, GitOps

Inhaltsverzeichnis
Warum ein eigener Post – und warum geteilt? #
Der Umzug auf einen Root-Server bei einem Cloud-Anbieter verändert das Bedrohungsmodell fundamental. Im Homelab bremsen ein DSL-Router mit NAT und eine wechselnde IP die dümmsten Mass-Scans noch aus. Auf einem Root-Server hängst du mit statischer IP direkt am Backbone – die ersten Scan-Versuche stehen oft schon Minuten nach dem ersten Boot in den SSH-Logs. Keine Paranoia, sondern Realität.
Dieser Zweiteiler zeigt eine pragmatische Sicherheits-Baseline für Selfhoster und kleinere Unternehmen – ohne BSI-Grundschutz-Tiefe. Ziel ist ein Niveau, bei dem der Aufwand für einen Angreifer deutlich über dem liegt, was ein privater Stack hergibt, und die üblichen automatisierten Angriffe ins Leere laufen. Es geht hier um die Entscheidungen und das Warum – die konkrete Umsetzung Schritt für Schritt folgt in einer eigenen Serie (mehr dazu im Ausblick in Teil 2).
Die Gliederung folgt dem Zwiebelprinzip – von außen nach innen, so wie Angriffe ablaufen und wie man Verteidigung priorisiert: Die äußerste Schale muss am dichtesten sein, weil sie am häufigsten getestet wird.
Teil 1 deckt die vier Infrastruktur-Schichten ab: Perimeter, Zugang, Cluster, GitOps. Teil 2 geht weiter nach innen – Dienste-Härtung, Monitoring/Incident Response, Backup-Sicherheit.
Schicht 1: Perimeter – was das Internet sieht #
Die erste Verteidigungslinie ist das, was von außen überhaupt erreichbar ist. Jeder offene Port ist eine Einladung.
Provider-Firewall #
Die meisten Cloud-Anbieter stellen eine Firewall bereit, die vor dem Server im Provider-Netz sitzt – anders als eine
lokale iptables/nftables-Regel werden verworfene Pakete hier gar nicht erst zugestellt. Das spart CPU und minimiert
die Angriffsfläche.
Ein Detail muss man vorher kennen: Provider-Firewalls unterscheiden sich technisch. Stateful filtert IPv4 wie IPv6 –
dann reicht „deny all, allow few". Stateless betrachtet nur einzelne Pakete: Rückverkehr musst du explizit erlauben
(Ephemeral-Range + ACK), und die IPv6-Abdeckung ist oft eingeschränkt oder fehlt ganz. Für einen v6-fähigen Server heißt
das: nicht blind verlassen, sondern die Regeln host-seitig in nftables spiegeln. Defense in Depth statt einer einzigen
Schicht.
Die Regel selbst ist simpel – Deny all, allow few. Offen sind exakt:
80/tcpund443/tcpfür Nextcloud und Immich (HTTPS bzw. ACME-Challenge)51820/udpfür WireGuard22/tcp(oder dein gewählter SSH-Port) – nur von deiner Heim-IP und ggf. einer Backup-IP
Der SSH-Zugang ist IP-beschränkt, nicht offen. Bei dynamischer Heim-IP ist WireGuard der Hauptzugang und SSH läuft nur über den Tunnel – die saubere Zielvariante.
SSH-Härtung #
SSH ist der Klassiker – und trotzdem das häufigste Einfallstor:
- Nur Public-Key-Auth, Password-Auth aus. Kompromisslos.
- Root-Login deaktiviert (
PermitRootLogin no), Root nur viasudo. - Port-Wechsel weg von 22 – hält keinen gezielten Angreifer auf, senkt aber den Log-Noise um ~99 %.
- Modernisierte Kex/Cipher-Liste – nur aktuelle Algorithmen (
ssh-auditzum Prüfen). - Fail2ban für SSH – bewährte, simple Jail-Regeln (für die Webdienste übernimmt Crowdsec in Teil 2). Läuft SSH nur über WireGuard, ist das Gürtel und Hosenträger – schadet nicht.
- 2FA via Hardware-Key (
libpam-u2f) oder TOTP (libpam-google-authenticator) – bei Team-Zugang Pflicht.
Proxmox-Admin-Zugang #
Das Proxmox-Web-UI (Port 8006) ist nicht öffentlich, sondern hängt an der internen VM-Netz-IP und ist nur über WireGuard erreichbar. „Aber mal schnell von unterwegs" zählt nicht – dafür ist WireGuard da, und das geht auch vom Handy in unter 30 Sekunden. Dazu:
- Separater Admin-User (kein
root@pamfür Routinebetrieb) - 2FA aktiviert (TOTP/WebAuthn ist eingebaut)
- API-Tokens mit minimalen Rechten für Automatisierung, keine Passwort-Auth
- Proxmox-Firewall aktiviert, auch wenn schon eine davor sitzt – Defense in Depth
Kernel- und OS-Härtung #
Pflichtprogramm, das in jeder Ansible-Rolle einmal definiert wird und dann auf jeder neuen VM läuft:
- Unattended-Upgrades für Security-Patches – automatisch, ohne nächtlichen Reboot
- AppArmor aktiviert (bei Debian/Ubuntu Standard, nur prüfen)
sysctl-Härtung:kernel.kptr_restrict=2,kernel.dmesg_restrict=1, ASLR an. Beirp_filteraufpassen:net.ipv4.conf.all.rp_filter=1(strict) kann mit Calicos Datapath kollidieren – Calicos eigene Vorgabe prüfen statt pauschal strict.- Swap verschlüsselt oder deaktiviert, wenn Disk-Encryption aktiv ist
- Auditd aktiviert für Admin-Aktionen – Logs gehen später an Loki
Schicht 2: Zugang und Identität #
Wer kommt rein, wie und womit? Die entscheidende Frage, weil geklaute Zugangsdaten der häufigste erfolgreiche Angriffsweg sind.
WireGuard als einziger Admin-Weg #
Die Regel ist hart: Alles, was nicht öffentlich sein muss, ist nur via WireGuard erreichbar. Kein „temporär mal kurz offen". Die WireGuard-VM ist der einzige Zugang ins interne Netz und selbst minimal (Debian minimal, nur WireGuard).
- Pre-shared Keys zusätzlich zu den Keypairs – härtet gegen zukünftige Quantum-Attacken auf die Curve25519-Keys
- Regelmäßige Rotation der statischen Client-Keys (jährlich genügt) – WireGuard-Keys haben keine Ablauffrist, die Session-Keys werden ohnehin automatisch neu ausgehandelt
- Getrennte Client-Profile pro Gerät – verlorenes Handy = nur ein Profil revoken
- AllowedIPs restriktiv auf Server-Seite – kein
0.0.0.0/0, nur die nötigen Netze
Kanidm als SSO – aber nicht für alles #
Kanidm ist der zentrale Identity-Provider für die Web-Dienste. Richtig so, aber mit Grenze: Admin-Zugänge dürfen nicht vom SSO abhängen. Ist Kanidm kompromittiert oder kaputt, darf nicht gleichzeitig der Cluster-Zugang weg sein. Daraus folgt die Admin-Account-Trennung:
| Zugang | Auth-Methode |
|---|---|
| Nextcloud, Immich, Paperless, Grafana | Kanidm SSO |
| Vaultwarden | eigene Credentials (bewusst außerhalb SSO) |
| Proxmox | eigener Account + WebAuthn |
kubectl / Flux | Client-Zertifikate bzw. SSH-Key, nicht SSO |
| SSH / WireGuard | eigene Keys, nicht SSO |
| SOPS / age-Keys | Hardware-Key (YubiKey) |
Die Admin-Identitäten sind absichtlich mehrgleisig. Im Incident-Fall (Kanidm kompromittiert, DB kaputt, Upgrade fehlgeschlagen) hast du damit immer noch einen Weg rein.
MFA-Pflicht für alles Menschliche #
Alle Nutzer-Zugänge – nicht nur Admins – haben zwingend zweiten Faktor. Kanidm erzwingt das zentral, für Dienste außerhalb SSO (Vaultwarden, Proxmox, SSH) wird es pro Dienst gesetzt. Präferenz: WebAuthn/Passkeys (phishing-resistent, beste Option) vor TOTP (akzeptabel, aber phishing-anfällig). SMS nein, auch nicht als Fallback. Für Admin-Accounts ist WebAuthn Pflicht; ein Verlust wird über einen registrierten zweiten Key abgefangen.
Schicht 3: Cluster-Härtung #
Der Cluster bringt Defaults mit, die man nicht so lassen darf. Vier Themen:
RBAC – wer darf was #
Grundregel: niemand hat cluster-admin, außer es gibt keine Alternative.
- Menschliche Admins: eigener Account pro Person,
cluster-adminnur für Break-Glass (dokumentiert, audited) - CI/CD / Flux: minimale Rechte pro Namespace, keine cluster-weiten Rechte, wenn vermeidbar
- Service Accounts: explizit pro Workload, kein
default-SA automountServiceAccountToken: falseals Pod-Default, außer der Pod braucht API-Zugriff
Steht das von Anfang an in den Helm-Values bzw. Kustomize-Overlays, ist es kein Mehraufwand.
Pod Security Admission #
PSA ist der Nachfolger von PodSecurityPolicy und kommt ohne Extra-Controller aus:
- Default für alle Namespaces:
restricted– verbietet privilegierte Container, Host-Network, Host-Pfade etc. - Ausnahmen dokumentiert und explizit:
longhorn-systembrauchtprivilegedfür Storage;monitoringebenfallsprivileged– der Node-Exporter nutzthostNetwork,hostPIDundhostPath, und genau die verbietetbaseline. Eine Stufe drunter geht hier nicht. - Enforce-Modus, nicht nur Audit – sonst läuft es ins Leere
Jede neue Ausnahme ist ein Review-Event im GitOps-Workflow, kein Durchwinken.
NetworkPolicy – aber gezielt #
Bewusster Unterschied zur reinen Cloud-Lehre: kein komplettes NetworkPolicy-Regime für jeden Namespace, weil der Firewall-first-Ansatz (Provider-Firewall + Router) die Segmentierung schon am Edge macht. Was sich trotzdem lohnt:
- Default-Deny Ingress im
kube-system-Namespace - Default-Deny Egress für Workloads ohne Internet-Bedarf – Paperless, Kanidm, Vaultwarden
- Explizite Policies für Datenbank-Namespaces – nur die App darf an ihre DB
Kein Maximalprogramm, aber die wichtigsten Fälle: Ein kompromittierter Container soll nicht beliebig weitertelefonieren.
Admission Controller #
Zusätzlich zu PSA ein gezielter Policy-Controller:
- Kyverno für das, was PSA nicht abdeckt – z. B. „Images nur aus eigener Registry", „kein
latest-Tag", „Ressourcen-Limits Pflicht" - Kein OPA/Gatekeeper zusätzlich – eins reicht
Kyverno bewusst statt Gatekeeper: Policies in YAML statt Rego, wartbarer und passt zum GitOps-Workflow.
Schicht 4: GitOps und Secrets #
Der GitOps-Workflow ist das Herz der Private Cloud – und ein Angriffsziel. Wer Repo oder SOPS-Keys kompromittiert, kompromittiert den Stack.
SOPS-Key-Management #
SOPS verschlüsselt Secrets im Repo mit age-Keys. Die Frage ist, wo die Keys liegen:
- Nicht im Repo. Offensichtlich.
- Cluster-Key als Kubernetes-Secret im Cluster (für Flux), per SOPS-Bootstrap vom Admin-Rechner deployed.
- Admin-Keys auf Hardware-Keys (YubiKey mit age-plugin-yubikey), nicht in einer Passwort-DB.
- Key-Rotation jährlich oder nach jedem Admin-Wechsel – mit
sops updatekeysüberschaubar.
Geht ein Admin, fliegt sein age-Key aus der .sops.yaml und alle Secrets werden neu verschlüsselt. Der Moment, in dem
man froh ist, dass Secrets im GitOps-Flow liegen und nicht in State-Files oder kubectl edit.
Flux-Absicherung #
Flux ist ein privilegierter Service:
- SSH-Deploy-Key statt PAT – enger Scope, revozierbar; read-only, Flux muss nicht pushen
- Image-Automation separiert – eigener Token und PR-Flow (Flux Image Automation), keine Push-Rechte im Haupt-Repo
- Notifications aktiviert – jeder Reconcile-Fehler und jede Image-Aktualisierung ist sichtbar
Supply Chain – Images signieren und prüfen #
Wo kommen die Container-Images her? Pragmatische Baseline:
- Keine
latest-Tags (per Kyverno erzwungen), Digests für kritische Infra-Images (Traefik, cert-manager, Calico) - Image-Signing eigener Images via cosign
- Trivy-Scan im CI – kritische CVEs brechen den Build
- Renovate/Dependabot – PRs statt Auto-Merge für Infra, Auto-Merge nur für App-Patch-Versionen
Kein SLSA-Level-3, aber es fängt die häufigsten Supply-Chain-Probleme ab: kompromittierte Tags, abandoned Images, bekannte CVEs im Basis-Image.
Zwischenfazit – und Übergang zu Teil 2 #
Mit Perimeter, Zugang, Cluster und GitOps stehen die vier Infrastruktur-Schichten. Was hier sitzt, fängt den Großteil der automatisierten Angriffe ab, bevor sie eine Anwendung erreichen. Die Prinzipien dieser Hälfte:
- Was nicht erreichbar ist, kann nicht angegriffen werden – Provider-Firewall, WireGuard-only für Admin
- Admin-Trennung – SSO für Dienste, separate Identitäten mit Hardware-Key für Admin
- GitOps als Sicherheitsmerkmal – jede Änderung nachvollziehbar, jeder Key rotierbar
In Teil 2 geht es eine Schale weiter rein: Dienste (Nextcloud, Immich, Vaultwarden), Monitoring mit Crowdsec sowie Loki/Prometheus, Backup-Sicherheit mit Immutability und Restore-Drills.
Dieser Artikel erschien zuerst auf LinkedIn. Gedanken dazu, Fragen oder eigene Erfahrungen mit digitaler Souveränität — ich freue mich auf die Diskussion:
Diskussion auf LinkedIn öffnen