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>
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
- Ist-Zustand aufnehmen: welche Pods brauchen wirklich ausgehende Verbindungen und wohin (Föderation, Let's Encrypt, Container-Registries, IONOS-API, Matrix-Push-Gateways).
policyTypes: [Egress]mit Default-Deny je Namespace, dann gezielt freigeben.- ⚠️ DNS zuerst freigeben (
kube-dns/CoreDNS, UDP+TCP 53) — sonst steht alles, und der Fehler sieht aus wie ein Anwendungsproblem, nicht wie eine Firewall. - 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):
- Die gesamte Überwachung. Alloy schreibt nach
http://10.0.0.3:9090/api/v1/writeundhttp://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? - 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.