Before anything else: NetworkPolicy really is enforced here. k3s runs flannel and the policy controller inside its own process, so the absence of pods in kube-system proves nothing - measured instead, with a counter-probe. synapse-main reaches matrix's postgres and authentik-server does not, exactly as allow-ingress-postgres says. So the existing ingress rules are real protection and egress rules will bite. The textbook first step - allow 0.0.0.0/0 but except RFC1918 and the metadata service - would have cut two things here, both over 10.0.0.3, CFGMON on the private Hetzner network. Alloy remote-writes metrics and logs there, so monitoring would have gone silent, and nothing reports the failure of the reporting path. And the TURN rotation reaches Gitea through a hostAlias to that address because the public route was unreliable, so the rotation push would have died a day after we got it working again. That also settles #0008 harder than the absence of a firewall rule could: the cluster reaches Prometheus and Loki privately, so 9090 and 3100 are demonstrably not needed publicly. Proposed step 2 is therefore narrower and nearly risk-free: block only the metadata service, 169.254.0.0/16, while leaving federation, ACME, SMTP, registries and the private path open. Nobody here needs the metadata service, and the hard part of this issue - federation to arbitrary servers - is not touched at all. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
90 lines
4.8 KiB
Markdown
90 lines
4.8 KiB
Markdown
---
|
|
type: issue
|
|
id: "0088"
|
|
status: open
|
|
created: 2026-08-06
|
|
milestone: M1
|
|
priority: medium
|
|
projekt: gitops
|
|
gitlab_iid: "56"
|
|
related: []
|
|
---
|
|
# NetworkPolicy: ausgehender Verkehr ist unbeschränkt (13 Ingress-Regeln, 1 Egress)
|
|
|
|
> Adoptiert aus [gitops#56](https://git.lab/axion1337.chat/axion1337.chat-gitops/-/issues/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.
|