authentik and monitoring carried only the metadata block, so every pod there could reach anything. Both now follow the pattern from matrix: the broad policy keeps an exclusion list and stays as the catch-all, and each workload gets a rule of its own. The destinations were read, not guessed. Alloy ships to 10.0.0.3 on 3100 and 9090 - taken from its running configuration. Authentik sends mail through smtp.ionos.de:587, and that is load-bearing rather than optional: the blueprints use password recovery and invitations by mail. The database and kube-state-metrics speak to nobody outside. Mail gets a /27 rather than two /32. The name resolves to .97 and .113 today, both in the provider's own block; a third address would break mail with nobody watching a rule, and thirty-two addresses of one provider's mail infrastructure is the smaller price. That is the opposite call to ClamAV on purpose - this is not a CDN in front of half the internet. Deliberately not allowed: authentik's version check. It sits behind Cloudflare with rotating addresses and nothing depends on it, so the call fails and gets logged. The manifest says so, because whoever finds that error later should know it is intended. Congruence checked in both namespaces before pushing: excluded and narrowly ruled are the same sets. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F2Q4Ri8NGwyTZzScvKnWFM
131 lines
4.0 KiB
YAML
131 lines
4.0 KiB
YAML
---
|
|
# 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:
|
|
# Waehlt alle Pods AUSSER denen mit eigener, engerer Regel (#0088).
|
|
# Bleibt als Auffangnetz: Eine kuenftige Arbeitslast ohne eigene Policy
|
|
# landet hier - Metadaten gesperrt, Rest offen - statt voellig ungeregelt.
|
|
# ⚠️ Der Ausschluss MUSS hier stehen: NetworkPolicies sind additiv.
|
|
podSelector:
|
|
matchExpressions:
|
|
- key: app.kubernetes.io/name
|
|
operator: NotIn
|
|
values:
|
|
- alloy
|
|
- kube-state-metrics
|
|
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
|
|
---
|
|
# Welle 3 (#0088): Monitoring-Namespace, enge Regeln je Arbeitslast.
|
|
apiVersion: networking.k8s.io/v1
|
|
kind: NetworkPolicy
|
|
metadata:
|
|
name: egress-nur-intern
|
|
namespace: monitoring
|
|
spec:
|
|
# Liefert Metriken, holt selbst nichts von aussen.
|
|
podSelector:
|
|
matchLabels:
|
|
app.kubernetes.io/name: kube-state-metrics
|
|
policyTypes:
|
|
- Egress
|
|
egress:
|
|
- to:
|
|
- namespaceSelector:
|
|
matchLabels:
|
|
kubernetes.io/metadata.name: kube-system
|
|
ports:
|
|
- protocol: UDP
|
|
port: 53
|
|
- protocol: TCP
|
|
port: 53
|
|
- to:
|
|
- ipBlock:
|
|
cidr: 10.42.0.0/16
|
|
- ipBlock:
|
|
cidr: 10.43.0.0/16
|
|
---
|
|
apiVersion: networking.k8s.io/v1
|
|
kind: NetworkPolicy
|
|
metadata:
|
|
name: egress-ops-host
|
|
namespace: monitoring
|
|
spec:
|
|
podSelector:
|
|
matchLabels:
|
|
app.kubernetes.io/name: alloy
|
|
policyTypes:
|
|
- Egress
|
|
egress:
|
|
- to:
|
|
- namespaceSelector:
|
|
matchLabels:
|
|
kubernetes.io/metadata.name: kube-system
|
|
ports:
|
|
- protocol: UDP
|
|
port: 53
|
|
- protocol: TCP
|
|
port: 53
|
|
- to:
|
|
- ipBlock:
|
|
cidr: 10.42.0.0/16
|
|
- ipBlock:
|
|
cidr: 10.43.0.0/16
|
|
# Der operating-Host im PRIVATEN Netz: Logs nach Loki (3100), Metriken per
|
|
# remote_write nach Prometheus (9090). Beide Ziele aus der laufenden
|
|
# Alloy-Konfiguration gelesen, nicht angenommen.
|
|
- to:
|
|
- ipBlock:
|
|
cidr: 10.0.0.3/32
|
|
ports:
|
|
- protocol: TCP
|
|
port: 3100
|
|
- protocol: TCP
|
|
port: 9090
|