Compare commits

...
12 Commits
Author SHA1 Message Date
Thore Cimbal d87c432f89 elementWeb auf v0.6.0
Release des Upstream-Anschlusses (ADR-0022). Gleicher Quellstand wie rc.3
(8ca03fe), das die Abnahme bestanden hat - nur unter Release-Nummer. Die Images
sind nicht bitgleich, weil der Build die Versionszeichenkette aus git describe
ins Artefakt backt.

Produktion laeuft damit erstmals auf einem Fork, der wieder an der
Upstream-Historie haengt.

Rueckhebel: Tag zurueck auf v0.5.4.
2026-08-19 12:00:00 +00:00
Thore Cimbal de347343b3 elementWeb auf v0.6.0-rc.3
Zweiter Anlauf des Upstream-Anschlusses (ADR-0022). Entfernt den Merge-Rest,
der rc.2 die Raumliste brach, und bringt einen typecheck-Job mit, den
docker_web als needs fuehrt - dieses Image ist das erste, das ohne bestandene
Typpruefung gar nicht haette entstehen koennen.

Abnahme steht aus, in dieser Reihenfolge: Raumliste laedt, ClamAV per Zip,
ClamAV per .png (der umgezogene Bild-Pfad), Call-Teilnehmerliste.

Rueckhebel: Tag zurueck auf v0.5.4.
2026-08-19 12:00:00 +00:00
Thore Cimbal b319f21133 Historie: rc.2-Vorfall am Tag-Kommentar festhalten
Der Block beschrieb rc.2 noch als laufenden Stand.
2026-08-19 12:00:00 +00:00
Thore Cimbal 1c3df5badb elementWeb zurueck auf v0.5.4 - rc.2 bricht die Raumliste
react-soft-crash bei sorb (Rageshake 2026-08-19 15:17, Safari):
"Setting 'feature_room_list_sections' does not appear to be a setting."
aus SettingsStore.getValue in RoomListItemViewModel.generateItemSync - also
bei jedem Raumlisteneintrag.

Fehler in der Merge-Aufloesung von ADR-0022: Upstream hat den Labs-Schalter
feature_room_list_sections entfernt (Sektionen laufen jetzt ueber
RoomList.showSections). Settings.tsx hat Upstreams Fassung uebernommen, in
RoomListItemViewModel.ts blieb die alte getValue-Zeile daneben stehen.

Der Build konnte das nicht fangen: getValue nimmt einen String, der Fehler
entsteht erst zur Laufzeit.

Kandidat kommt nach dem Fix als rc.3 zurueck.
2026-08-19 12:00:00 +00:00
Thore Cimbal 0f45266426 elementWeb auf v0.6.0-rc.2 (Upstream-Anschluss v1.12.26)
Kandidat, kein Release. Bringt den Merge aus ADR-0022 in Produktion, damit die
Abnahme an einem echten Client stattfinden kann.

Zu pruefen sind die zwei Patches, die der Merge verschieben musste:
ClamAV-Fehlermeldung im Bild-Pfad und die Call-Teilnehmerliste in der Raumliste.
Der Datei-Pfad (Zip) ist unberuehrt und diente heute als Ausgangswert - der
Scanner meldete die EICAR-Datei erwartungsgemaess zweimal, beim Senden und beim
Empfangen.

Rueckhebel: Tag zurueck auf v0.5.4.
2026-08-19 12:00:00 +00:00
Thore Cimbal d809b3f695 config(element): remove the interface path to a foreign homeserver
Decision sorb. Hides the edit button beside the server name, so the homeserver can no
longer be switched through the UI, and the 401/403 login error now names the server
rather than staying generic.

Honest about its reach, in the comment as well as here: it is a surface restriction.
MatrixChat still takes hs_url from the query string in two registration flows without
consulting this setting, so a crafted link is unaffected. Against
GHSA-wrcp-5v3v-3j6v - open since 2026-07-20, affecting everything below 1.12.22 while
we run 1.12.17 - it narrows the way in without closing it. The update in management
#0099 remains the actual fix.

The matching line went into the desktop client separately, since that one carries its
own config.json.
2026-08-19 12:00:00 +00:00
Thore Cimbal 1e65f5b3dd ci: stop creating pipelines that have no jobs to run
Pipeline 518 today was red with zero jobs - a push where no rule matched, which
GitLab still turns into a pipeline and then marks failed. The standstill check
reported it correctly, and it was the only finding standing between the scheduled
checks and green.

Acknowledging it would have been the wrong move twice over: the entry would name one
pipeline id, so the next empty pipeline files a fresh finding, and the underlying
behaviour - red without a fault - is exactly what management #0104 is about. Rules
that prevent the empty pipeline remove the class instead.

schedule comes first deliberately. The daily canonization changes no paths, so a
changes-based rule alone would drop it.
2026-08-19 12:00:00 +00:00
Thore Cimbal 3935f359f9 feat(synapse): close federation with an empty domain whitelist (#0060)
Decision sorb. Measured basis rather than preference: four months of operation with
zero destinations, zero remote users and zero rooms with outside participation, while
the federation API answered publicly - the delegation routes it over 443, so 8448
being shut never mattered.

An empty list federates with nobody and one entry opens it for exactly that domain,
so the capability stays one line away rather than gone.

The comment records what must not be done instead, because it is not obvious and it
would look correct: blocking /_matrix/federation at the edge. lk-jwt-service verifies
OpenID tokens through /_matrix/federation/v1/openid/userinfo and reaches it over the
public name - no hostAliases, ClusterFirst DNS - so a path-level block kills group
calls. Synapse serves that endpoint without an X-Matrix signature, so the whitelist
does not touch it.

Caught while validating: the first version of this edit split the auto_join block,
moving auto_join_rooms_for_guests under federation. Functionally identical after the
fragments merge, wrong to read, and fixed before pushing - the diff is now 20 added
lines and nothing moved.
2026-08-19 12:00:00 +00:00
Thore CimbalandClaude Opus 5 e7469a36b8 feat(netpol): deny pods the metadata service, leave everything else open (#0088)
First egress rule in matrix, authentik and monitoring. It allows DNS, the cluster
ranges and the whole internet, and denies only 169.254.0.0/16 - link-local, where
Hetzner serves instance metadata unauthenticated to any pod.

Deliberately narrow. The textbook cut, 0.0.0.0/0 except RFC1918, would have severed
two things here, both over 10.0.0.3 on the private Hetzner network: Alloy writes
metrics and logs there, and the TURN rotation reaches Gitea through a hostAlias to
that address. Private ranges therefore stay open.

The payoff is modest and should be stated as such: measured from a pod, the service
answers with instance-id, hostname, region, MAC and network config, while userdata
and public-keys are empty. No credentials are exposed here, unlike the AWS case this
hardening usually targets. It costs nothing though, and it closes the class.

Two preconditions checked rather than assumed, because both are the usual way this
breaks: kube-system carries kubernetes.io/metadata.name so the DNS rule actually
matches, and the cluster is IPv4-only so 0.0.0.0/0 really does cover everything.

Rollback is deleting the one policy per namespace.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 12:00:00 +00:00
Thore CimbalandClaude Opus 5 8473a1f0e5 ci: remove the CANONIZE_TOKEN probe, it did its job
Pipeline 521: the variable is visible inside the job, the push to a throwaway ref
succeeded and the ref was removed again. Combined with the token's own properties -
Maintainer, write_repository only - the monthly canonization has what it needs on
2026-09-01.

Two things the probe itself taught, kept here rather than in the removed block: an
API-triggered pipeline has source "api", not "web", so the first attempt silently
skipped the job entirely; and this repo has no "pruefen" stage, which rejected the
pipeline outright. Both would have cost the same time again next year.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 12:00:00 +00:00
Thore CimbalandClaude Opus 5 c3e42be0d1 ci: the probe never ran - an API trigger has source api, not web
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 12:00:00 +00:00
Thore CimbalandClaude Opus 5 e816d76f60 ci: drop the pruefen stage from the probe - this repo has no such stage
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 12:00:00 +00:00
8 changed files with 234 additions and 35 deletions
+22 -34
View File
@@ -3,6 +3,28 @@
# weiterhin selbststaendig aus dem Gitea-Mirror. Repo-Topologie: git.lab ist
# kanonisch, rohana/Gitea ist Push-Mirror und Flux-Quelle.
# Ohne workflow-Block legt GitLab auch dann eine Pipeline an, wenn KEIN Job auf sie
# passt - und fuehrt sie als "failed". Das ist rot ohne Fehler, und rot ohne Fehler
# gewoehnt einem das Hinsehen ab (management #0104). Real passiert am 2026-08-19,
# Pipeline 518. Diese Regeln verhindern die leere Pipeline, statt sie hinterher zu
# quittieren.
#
# Reihenfolge zaehlt: schedule zuerst, sonst faellt die taegliche Kanonisierung mit
# heraus - sie aendert keine Pfade und wuerde von der changes-Regel nie erfasst.
.pfade_mit_pipeline: &pfade_mit_pipeline
- apps/**/*
- clusters/**/*
- .gitlab-ci.yml
workflow:
rules:
- if: $CI_PIPELINE_SOURCE == "schedule"
- if: $CI_PIPELINE_SOURCE == "web"
- if: $CI_PIPELINE_SOURCE == "api"
- if: $CI_COMMIT_BRANCH == "main"
changes: *pfade_mit_pipeline
- when: never
verify:
image: alpine:3.20
rules:
@@ -200,37 +222,3 @@ canonize_wiki:
- git clone --bare --quiet https://rohana.axion1337.de/sorb/ThreadNetWiki.git /tmp/wiki.git
- GIT_SSL_CAINFO="$LABCA" git -C /tmp/wiki.git push "https://oauth2:${WIKI_CANONIZE_TOKEN}@${CI_SERVER_HOST}/axion1337.chat/threadnet-wiki.git" 'refs/heads/main:refs/heads/main'
- echo "git.lab threadnet-wiki spiegelt jetzt Gitea sorb/ThreadNetWiki (main)."
# ---------------------------------------------------------------------------
# TEMPORAER (2026-08-19): beweist, dass CANONIZE_TOKEN in der Pipeline ankommt
# und schreiben darf - OHNE main anzufassen. Laeuft nur, wenn eine Web-Pipeline
# ausdruecklich mit TEST_CANONIZE=1 gestartet wird. Wird nach dem Test entfernt.
# ---------------------------------------------------------------------------
canonize_token_test:
stage: pruefen
image: alpine:3.20
rules:
- if: $CI_PIPELINE_SOURCE == "web" && $TEST_CANONIZE == "1"
script:
- apk add --no-cache git ca-certificates >/dev/null
- export GIT_SSL_CAINFO="$CI_PROJECT_DIR/ci/lab-ca-chain.crt"
- |
if [ -z "$CANONIZE_TOKEN" ]; then
echo "FEHLT: CANONIZE_TOKEN ist im Job nicht sichtbar."
echo "Ursache meist: Variable 'protected', Pipeline laeuft aber auf einem"
echo "ungeschuetzten Branch. Genau dann bliebe die Rotation liegen."
exit 1
fi
echo "Sichtbar: CANONIZE_TOKEN ist im Job gesetzt."
URL="https://oauth2:${CANONIZE_TOKEN}@${CI_SERVER_HOST}/${CI_PROJECT_PATH}.git"
REF="canonize-token-probe-${CI_PIPELINE_ID}"
# Ausgabe wird gefiltert: git schreibt die URL bei Fehlern mit ins Log.
if git push "$URL" "HEAD:refs/heads/$REF" 2>&1 | sed 's#oauth2:[^@]*@#oauth2:***@#g'; then
echo "SCHREIBEN OK: Zweig $REF angelegt."
else
echo "SCHREIBEN FEHLGESCHLAGEN - Rolle oder Scope reichen nicht."
exit 1
fi
git push "$URL" --delete "refs/heads/$REF" 2>&1 | sed 's#oauth2:[^@]*@#oauth2:***@#g' \
&& echo "Aufgeraeumt: $REF wieder entfernt." \
|| echo "WARNUNG: $REF blieb liegen, bitte von Hand loeschen."
+53
View File
@@ -94,3 +94,56 @@ spec:
ports:
- protocol: TCP
port: 8089
---
# Egress: alles bleibt erlaubt AUSSER dem Metadaten-Dienst (management #0088).
#
# Warum so schmal? Der Lehrbuch-Schnitt (0.0.0.0/0 except RFC1918) haette hier zwei
# Dinge zerrissen, beide ueber 10.0.0.3 (CFGMON im privaten Hetzner-Netz): Alloy
# schreibt Metriken und Logs dorthin, und der TURN-Rotations-CronJob erreicht Gitea
# ueber einen hostAlias auf dieselbe Adresse. Private Netze bleiben deshalb offen.
#
# 169.254.0.0/16 ist Link-Local; darin liegt bei Hetzner unter 169.254.169.254 der
# Metadaten-Dienst, aus jedem Pod unauthentifiziert abfragbar (nachgemessen 2026-08-19:
# HTTP 200 mit instance-id, hostname, region, MAC, Netzkonfiguration). userdata und
# public-keys waren LEER - es liegen hier also keine Zugangsdaten offen. Der Gewinn ist
# entsprechend bescheiden; der Schnitt kostet aber nichts und schliesst die Klasse.
#
# ACHTUNG beim Erweitern: Sobald eine Egress-Regel fuer einen Pod existiert, gilt fuer
# ihn Default-Deny fuer alles NICHT Aufgefuehrte. Die drei Bloecke unten sind daher
# Pflicht, nicht Bequemlichkeit - insbesondere DNS: fehlt es, steht alles, und der
# Fehler sieht wie ein Anwendungsproblem aus, nicht wie eine Firewall.
#
# Rollback: diese eine Policy im Namespace loeschen.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: egress-block-metadata
namespace: authentik
spec:
podSelector: {}
policyTypes:
- Egress
egress:
# 1. DNS - zuerst, weil ohne DNS nichts geht.
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
# 2. Cluster-intern: Pods und Services (inkl. API-Server 10.43.0.1).
- to:
- ipBlock:
cidr: 10.42.0.0/16
- ipBlock:
cidr: 10.43.0.0/16
# 3. Alles uebrige - Foederation, ACME, SMTP, Registries, privates Netz -
# ausser Link-Local.
- to:
- ipBlock:
cidr: 0.0.0.0/0
except:
- 169.254.0.0/16
+1
View File
@@ -6,3 +6,4 @@ resources:
- kube-state-metrics.yaml
- alloy-config.yaml
- alloy.yaml
- networkpolicy.yaml
+53
View File
@@ -0,0 +1,53 @@
---
# Egress: alles bleibt erlaubt AUSSER dem Metadaten-Dienst (management #0088).
#
# Warum so schmal? Der Lehrbuch-Schnitt (0.0.0.0/0 except RFC1918) haette hier zwei
# Dinge zerrissen, beide ueber 10.0.0.3 (CFGMON im privaten Hetzner-Netz): Alloy
# schreibt Metriken und Logs dorthin, und der TURN-Rotations-CronJob erreicht Gitea
# ueber einen hostAlias auf dieselbe Adresse. Private Netze bleiben deshalb offen.
#
# 169.254.0.0/16 ist Link-Local; darin liegt bei Hetzner unter 169.254.169.254 der
# Metadaten-Dienst, aus jedem Pod unauthentifiziert abfragbar (nachgemessen 2026-08-19:
# HTTP 200 mit instance-id, hostname, region, MAC, Netzkonfiguration). userdata und
# public-keys waren LEER - es liegen hier also keine Zugangsdaten offen. Der Gewinn ist
# entsprechend bescheiden; der Schnitt kostet aber nichts und schliesst die Klasse.
#
# ACHTUNG beim Erweitern: Sobald eine Egress-Regel fuer einen Pod existiert, gilt fuer
# ihn Default-Deny fuer alles NICHT Aufgefuehrte. Die drei Bloecke unten sind daher
# Pflicht, nicht Bequemlichkeit - insbesondere DNS: fehlt es, steht alles, und der
# Fehler sieht wie ein Anwendungsproblem aus, nicht wie eine Firewall.
#
# Rollback: diese eine Policy im Namespace loeschen.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: egress-block-metadata
namespace: monitoring
spec:
podSelector: {}
policyTypes:
- Egress
egress:
# 1. DNS - zuerst, weil ohne DNS nichts geht.
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
# 2. Cluster-intern: Pods und Services (inkl. API-Server 10.43.0.1).
- to:
- ipBlock:
cidr: 10.42.0.0/16
- ipBlock:
cidr: 10.43.0.0/16
# 3. Alles uebrige - Foederation, ACME, SMTP, Registries, privates Netz -
# ausser Link-Local.
- to:
- ipBlock:
cidr: 0.0.0.0/0
except:
- 169.254.0.0/16
@@ -15,6 +15,8 @@ data:
config.json: |
{
"brand": "aXion1337.Chat",
"_kommentar_custom_urls": "Entscheidung sorb 2026-08-19 (management #0099). Blendet den 'Bearbeiten'-Knopf am Servernamen aus (ServerPicker.tsx) - der Homeserver ist damit ueber die Oberflaeche nicht mehr wechselbar, und die Login-Fehlermeldung benennt bei 401/403 den Server statt generisch zu bleiben (ErrorUtils.tsx). Es ist eine OBERFLAECHEN-Sperre: der hs_url-Query-Parameter wird in MatrixChat.tsx (mobile Registrierung, Registrierungs-Bestaetigung) weiterhin ohne diese Pruefung uebernommen. Gegen das offene Advisory GHSA-wrcp-5v3v-3j6v (betrifft < 1.12.22, wir laufen 1.12.17) verengt das die Flaeche, ersetzt aber NICHT das Upstream-Update aus #0099. Dieselbe Zeile muss im Desktop-Client stehen - der hat seine eigene config.json.",
"disable_custom_urls": true,
"_kommentar_bug_report": "local = der Knopf erscheint als 'Protokolle herunterladen'; die Logs bleiben auf dem Geraet und gehen an KEINEN Server. Ohne diesen Wert ist die ganze Sektion unsichtbar und Nutzer kommen gar nicht an ihre Logs (ThreadNet-Web#9). Der element.io-Endpunkt wurde am 2026-08-01 bewusst entfernt - dieser Wert holt die Faehigkeit zurueck, ohne den Abfluss.",
"bug_report_endpoint_url": "local",
"_kommentar_report_event": "Weg B (Entscheidung sorb 2026-08-15): Meldungen bleiben im event_reports-Speicher des Servers und werden ueber Element Admin gesichtet - Draupnir bekommt dafuer BEWUSST keine Server-Admin-Rechte. Ohne diesen Text sieht der Melder nach dem Absenden gar nichts und weiss nicht, ob und an wen die Meldung geht (#0045).",
@@ -69,6 +69,26 @@ data:
auto_join_rooms:
- "#onboarding:axion1337.chat"
auto_join_rooms_for_guests: false
# Foederation geschlossen (Entscheidung sorb 2026-08-19, management #0060,
# ADR-0021). Leere Liste = mit KEINEM Server foederieren; ein Eintrag hier
# oeffnet gezielt fuer diese eine Domain.
#
# Grundlage war eine Messung, keine Meinung: in vier Monaten Betrieb null
# Eintraege in `destinations`, null fremde Nutzer, null Raeume mit fremder
# Beteiligung - bei gleichzeitig oeffentlich erreichbarer Foederations-API
# (die Delegation fuehrt sie ueber 443, 8448 ist ohnehin zu).
#
# ⚠️ NICHT betroffen und darf es auch nicht sein:
# /_matrix/federation/v1/openid/userinfo. Ueber diesen Endpunkt prueft der
# MatrixRTC-Authorisation-Service (lk-jwt-service) die OpenID-Tokens, und er
# ruft ihn ueber den OEFFENTLICHEN Namen auf - das Deployment hat keine
# hostAliases und ClusterFirst-DNS. Synapse bedient ihn ohne
# X-Matrix-Signatur (REQUIRE_AUTH=False), die Whitelist greift dort also
# nicht. Wer hier auf Pfad-Ebene sperrt statt ueber diese Liste, legt die
# Gruppen-Calls lahm - genau der mrtc-Ausfall, nur mit anderer Ursache.
federation:
config: |
federation_domain_whitelist: []
room_publish:
config: |
room_list_publication_rules:
+30 -1
View File
@@ -81,6 +81,35 @@ spec:
image:
registry: rohana.axion1337.de
repository: sorb/threadnet-web
# v0.6.0-rc.2 = Anschluss an Element Web v1.12.26 (ADR-0022). Ein echter
# Merge-Commit statt Cherry-Picks; die Fork-Patches mussten umziehen,
# weil Upstream MImageBody.tsx geloescht und den Raumlisten-Inhalt nach
# RoomListItemContent ausgelagert hat. Betroffen sind genau die zwei
# Stellen, die die Abnahme pruefen muss: die ClamAV-Fehlermeldung im
# Bild-Pfad (ImageBodyViewModel.computeErrorLabel) und die
# Call-Teilnehmerliste in der Raumliste.
# Am 19.08. ausgerollt und nach wenigen Minuten zurueckgenommen: die
# Raumliste stuerzte bei jedem Eintrag ab (react-soft-crash), weil in
# RoomListItemViewModel.ts eine getValue-Zeile auf den von Upstream
# entfernten Labs-Schalter feature_room_list_sections stehenblieb -
# Sektionen laufen dort inzwischen ueber RoomList.showSections. Eine
# Leiche aus der Merge-Aufloesung, die kein Build fangen konnte:
# getValue nimmt einen String und wirft erst zur Laufzeit.
# rc.3 = derselbe Merge ohne den Rest, plus ein typecheck-Job, den
# docker_web als needs fuehrt: kein Image mehr ohne Typpruefung. Der
# web-Job baut nur, webpack wirft Typen weg - tsc hatte den Fehler die
# ganze Zeit gemeldet, gefragt hatte ihn niemand. Massstab ist "kein
# Fehler ausserhalb von node_modules", weil Upstream v1.12.26 selbst
# nicht typrein ist (matrix-js-sdk 42.2.0, in einem sauberen Checkout
# gegengeprueft).
# v0.6.0 = Abnahme auf rc.3 bestanden (19.08.), derselbe Quellstand
# 8ca03fe unter Release-Nummer. Geprueft am laufenden System, nicht nur
# am Build: Raumliste laedt, ClamAV blockt beim Senden (ein Scan-Aufruf,
# kein Upload), abgewiesene Datei zeigt die Meldung, und das .png wurde
# zugestellt, beim Herunterladen abgewiesen und die Meldung gerendert -
# damit ist der portierte Bild-Pfad belegt, nicht nur vermutet. Auch die
# Call-Teilnehmerliste, der zweite umgezogene Patch, steht richtig drin.
# Rueckhebel bleibt der Tag-Revert auf v0.5.4.
# v0.5.4 = Sender-Verifikation (threadnet-call fee9866): auf Safari
# uebersprang LiveKit den Track-Tausch stumm (sender?.replaceTrack),
# das rohe Mikro blieb auf der Leitung. Der Fork prueft und erzwingt
@@ -116,7 +145,7 @@ spec:
# Die Linie beginnt bei v0.3.0, dem ersten kanonischen CI-Build aus
# apps/web/Dockerfile - er loeste die Derivat-Images ab, deren
# Entrypoint ohne Exec-Bit /config.json still brach (ThreadNet-Web#8).
tag: v0.5.4
tag: v0.6.0
ingress:
host: axion1337.chat
+53
View File
@@ -408,3 +408,56 @@ spec:
ports:
- protocol: TCP
port: postgres
---
# Egress: alles bleibt erlaubt AUSSER dem Metadaten-Dienst (management #0088).
#
# Warum so schmal? Der Lehrbuch-Schnitt (0.0.0.0/0 except RFC1918) haette hier zwei
# Dinge zerrissen, beide ueber 10.0.0.3 (CFGMON im privaten Hetzner-Netz): Alloy
# schreibt Metriken und Logs dorthin, und der TURN-Rotations-CronJob erreicht Gitea
# ueber einen hostAlias auf dieselbe Adresse. Private Netze bleiben deshalb offen.
#
# 169.254.0.0/16 ist Link-Local; darin liegt bei Hetzner unter 169.254.169.254 der
# Metadaten-Dienst, aus jedem Pod unauthentifiziert abfragbar (nachgemessen 2026-08-19:
# HTTP 200 mit instance-id, hostname, region, MAC, Netzkonfiguration). userdata und
# public-keys waren LEER - es liegen hier also keine Zugangsdaten offen. Der Gewinn ist
# entsprechend bescheiden; der Schnitt kostet aber nichts und schliesst die Klasse.
#
# ACHTUNG beim Erweitern: Sobald eine Egress-Regel fuer einen Pod existiert, gilt fuer
# ihn Default-Deny fuer alles NICHT Aufgefuehrte. Die drei Bloecke unten sind daher
# Pflicht, nicht Bequemlichkeit - insbesondere DNS: fehlt es, steht alles, und der
# Fehler sieht wie ein Anwendungsproblem aus, nicht wie eine Firewall.
#
# Rollback: diese eine Policy im Namespace loeschen.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: egress-block-metadata
namespace: matrix
spec:
podSelector: {}
policyTypes:
- Egress
egress:
# 1. DNS - zuerst, weil ohne DNS nichts geht.
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
# 2. Cluster-intern: Pods und Services (inkl. API-Server 10.43.0.1).
- to:
- ipBlock:
cidr: 10.42.0.0/16
- ipBlock:
cidr: 10.43.0.0/16
# 3. Alles uebrige - Foederation, ACME, SMTP, Registries, privates Netz -
# ausser Link-Local.
- to:
- ipBlock:
cidr: 0.0.0.0/0
except:
- 169.254.0.0/16