Files
management/docs/issues/0088-gitops-56-networkpolicy-ausgehender-verkehr-ist-unbesch.md
Thore CimbalandClaude Opus 5 23378c41b7 docs(issues): #0088 - metadata egress blocked, and what that does not achieve
Rolled out to matrix, authentik and monitoring, verified in two namespaces rather
than assumed: DNS resolves, federation still reaches matrix.org, the metadata service
is blocked, and the private path to 10.0.0.3 is intact with Alloy reporting no errors.

The issue stays open on purpose. Its actual demand - default deny with explicit
allows - is not met; egress is still open everywhere except link-local. Federation
makes that unwritable as a list while it stays open (#0060). What is now on record is
the inventory that makes the next decision possible: monitoring and authentik have a
nameable set of destinations and could take default deny, matrix cannot.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 12:00:00 +00:00

6.6 KiB

type, id, status, created, milestone, priority, projekt, gitlab_iid, related
type id status created milestone priority projekt gitlab_iid related
issue 0088 open 2026-08-06 M1 medium gitops 56

NetworkPolicy: ausgehender Verkehr ist unbeschränkt (13 Ingress-Regeln, 1 Egress)

Adoptiert aus gitops#56 (2026-08-18, ADR-0019). Kommentare und Verlauf bleiben dort; kanonisch ist ab jetzt diese Datei.

In apps/production/networkpolicy.yaml stehen 13 Ingress-Regeln und genau ein Egress-Vorkommen. Eingehend ist der Cluster dicht, ausgehend ist er offen: Jeder Pod darf ins Internet, in andere Namespaces und an den Metadaten-Dienst.

Warum das zählt

Die Ingress-Regeln verhindern, dass jemand hineinkommt. Sie verhindern nicht, dass etwas, das schon drin ist, hinausredet — Daten abfließen lässt, Schadcode nachlädt oder sich zu einem Command-and-Control-Server verbindet. Genau das ist der Schritt, der aus einer kompromittierten Abhängigkeit einen Vorfall macht.

Besonders relevant hier, weil wir fremden Code ausführen: Synapse-Module, ClamAV, Draupnir, dazu eine große npm-Abhängigkeitskette im Client-Build.

Was zu tun ist

  1. Ist-Zustand aufnehmen: welche Pods brauchen wirklich ausgehende Verbindungen und wohin (Föderation, Let's Encrypt, Container-Registries, IONOS-API, Matrix-Push-Gateways).
  2. policyTypes: [Egress] mit Default-Deny je Namespace, dann gezielt freigeben.
  3. ⚠️ DNS zuerst freigeben (kube-dns/CoreDNS, UDP+TCP 53) — sonst steht alles, und der Fehler sieht aus wie ein Anwendungsproblem, nicht wie eine Firewall.
  4. Föderation ist der schwierige Teil: Synapse muss zu beliebigen Matrix-Servern hinaus. Das lässt sich nicht auf eine Liste eingrenzen, solange die Föderation offen ist (gitops#17) — eher über einen Egress-Proxy oder bewusst offen lassen und dokumentieren.

Rollback

NetworkPolicies sind additiv und einzeln löschbar. Der Not-Aus ist das Entfernen der Default-Deny-Regel.

Gefunden am 2026-08-06 bei einer Bestandsaufnahme der Sicherheitslage.

Schritt 1 erledigt 2026-08-19 — Bestandsaufnahme, und ein Beinahe-Fehler

Vorfrage zuerst: werden NetworkPolicies hier überhaupt durchgesetzt?

Ja, belegt. In k3s laufen Flannel und der Policy-Controller im k3s-Prozess, nicht als Pods — ihre Abwesenheit in kube-system beweist also nichts. Gemessen statt gefolgert, mit Gegenprobe:

Von nach matrix-stack-postgres:5432 Erwartung laut allow-ingress-postgres
synapse-main (matrix) verbunden erlaubt ✓ — beweist zugleich, dass dort etwas lauscht
authentik-server (authentik) abgewiesen nicht erlaubt ✓

Damit ist die bestehende Ingress-Absicherung echter Schutz — und Egress-Regeln werden echte Wirkung haben, im Guten wie im Schlechten.

Cluster-Eckdaten

Pod-CIDR 10.42.0.0/24 (ein Knoten), Service-CIDR 10.43.0.0/16, kube-dns 10.43.0.10, API 10.43.0.1. Pods: matrix 15, authentik 3, monitoring 2.

⚠️ Der naheliegende erste Schritt wäre falsch gewesen

Das übliche Muster lautet: Egress auf 0.0.0.0/0 freigeben, aber RFC1918 und den Metadaten-Dienst ausnehmen. Hier hätte das zwei Dinge zerrissen, beide über 10.0.0.3 (CFGMON im privaten Hetzner-Netz):

  1. Die gesamte Überwachung. Alloy schreibt nach http://10.0.0.3:9090/api/v1/write und http://10.0.0.3:3100/loki/api/v1/push (apps/monitoring/alloy-config.yaml). Ein RFC1918-Block hätte Metriken und Logs abgeschnitten — und zwar still, denn wer meldet den Ausfall des Meldewegs?
  2. Die TURN-Rotation. Der CronJob erreicht Gitea über hostAliases: 10.0.0.3 → rohana.axion1337.de, weil der öffentliche Weg unzuverlässig war (#0076). Ohne privaten Egress kein Rotations-Push — genau die Kette, die wir am 2026-08-18 erst wieder in Gang gebracht haben.

Nebenbefund, der #0008 endgültig schließt: Dass der Cluster Prometheus und Loki über 10.0.0.3 erreicht, ist der harte Beleg dafür, dass 9090/3100 öffentlich nicht gebraucht werden. Die dortige Schlussfolgerung („Weg A ist gegenstandslos") steht damit nicht mehr nur auf der Abwesenheit einer Firewall-Regel.

Vorschlag für Schritt 2

Nicht RFC1918 sperren. Der risikoarme, trotzdem wirksame erste Schnitt ist der Metadaten-Dienst (169.254.0.0/16, darin 169.254.169.254): der klassische Weg, aus einem übernommenen Pod Instanz-Informationen zu ziehen. Kein Dienst hier braucht ihn.

Je Namespace also eine Egress-Policy, die freigibt: DNS nach kube-system, das Cluster (10.42.0.0/16, 10.43.0.0/16), und 0.0.0.0/0 mit except: 169.254.0.0/16. Föderation, ACME, SMTP, Registry und der private Weg zu 10.0.0.3 bleiben offen — der schwierige Teil aus Punkt 4 des Issues wird damit gar nicht erst angefasst.

Rollback bleibt das Löschen der einen Policy je Namespace.

Schritt 2 ausgerollt 2026-08-19 — Metadaten-Dienst gesperrt

egress-block-metadata liegt in matrix, authentik und monitoring (Commit e7469a3). Sie erlaubt DNS nach kube-system, die Cluster-Bereiche und 0.0.0.0/0, und sperrt allein 169.254.0.0/16.

Abnahme in zwei Namespaces gemessen, nicht angenommen:

Prüfung matrix authentik
DNS löst auf
Internet raus (matrix.org, HTTP 200 — die Föderation lebt)
Metadaten-Dienst blockiert blockiert
privates Netz 10.0.0.3:9090 erreichbar erreichbar

Alloy meldet seit dem Ausrollen 0 Fehlerzeilen — der Weg nach 10.0.0.3 steht, Metriken und Logs fließen weiter.

Ehrliche Einordnung des Gewinns: Der Hetzner-Metadaten-Dienst gab hier instance-id, hostname, region, MAC und Netzkonfiguration preis; userdata und public-keys waren leer. Es lagen also keine Zugangsdaten offen, anders als im AWS-Fall, auf den diese Härtung sonst zielt. Der Schritt schließt eine Klasse, er verhindert keinen bekannten Angriffsweg.

Was dieses Issue offen lässt

Der Kern der Forderung — Default-Deny mit expliziter Freigabe — ist damit nicht erfüllt. Ausgehend darf weiterhin jeder Pod überall hin, außer ins Link-Local. Der Grund steht in Schritt 1: Solange die Föderation offen ist (#0060), lässt sich Synapse' Ziel-Menge nicht als Liste schreiben, und ein Egress-Proxy ist ein eigenes Vorhaben.

Sinnvolle nächste Stufe wäre, die Namespaces einzeln zu betrachten statt alle gleich: monitoring und authentik haben eine überschaubare, benennbare Ziel-Menge (CFGMON privat, IONOS-SMTP, ACME) — dort ist Default-Deny realistisch. matrix ist es wegen der Föderation nicht. Das Issue bleibt offen und trägt jetzt die Bestandsaufnahme, die diese Entscheidung tragfähig macht.