Files
axion1337.chat-gitops/apps/authentik/networkpolicy.yaml
T
Thore CimbalandClaude Opus 5 d5b59eb5e9 netpol: wave 3 — the two namespaces the issue never mentioned (#0088)
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
2026-08-21 12:00:00 +00:00

271 lines
8.3 KiB
YAML

# Default-deny ingress for the authentik namespace, with explicit allow rules for the
# traffic paths that actually need to reach in: Traefik (kube-system) for the public
# auth.axion1337.chat endpoint and ACME HTTP-01 challenges, and MAS (matrix namespace)
# for upstream OIDC calls. Egress is intentionally untouched (federation-equivalent
# outbound calls like SMTP aren't restricted here).
#
# authentik-postgresql: the Bitnami postgresql subchart's own generated NetworkPolicy
# restricted the port (5432) but not the source - any pod in any namespace could reach
# it (issue #37). Disabled via postgresql.primary.networkPolicy.enabled: false in
# authentik.yaml and replaced below with a policy scoped to authentik-server/-worker.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
namespace: authentik
spec:
podSelector: {}
policyTypes:
- Ingress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-ingress-authentik-server
namespace: authentik
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: authentik
app.kubernetes.io/component: server
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: matrix
ports:
# NetworkPolicy matches the pod's actual container port, not the Service's
# external port - the authentik-server Service maps 80->9000, 443->9443.
- protocol: TCP
port: 9000
- protocol: TCP
port: 9443
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-ingress-authentik-postgresql
namespace: authentik
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: postgresql
app.kubernetes.io/component: primary
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app.kubernetes.io/name: authentik
app.kubernetes.io/component: server
- podSelector:
matchLabels:
app.kubernetes.io/name: authentik
app.kubernetes.io/component: worker
- podSelector:
matchLabels:
app.kubernetes.io/name: authentik-backup
ports:
- protocol: TCP
port: 5432
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-ingress-acme-solver
namespace: authentik
spec:
podSelector:
matchLabels:
acme.cert-manager.io/http01-solver: "true"
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
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:
# 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:
- authentik
- postgresql
- authentik-backup
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): Authentik-Namespace, enge Regeln je Arbeitslast.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: egress-nur-intern
namespace: authentik
spec:
# Die Datenbank spricht mit niemandem ausserhalb des Clusters.
podSelector:
matchLabels:
app.kubernetes.io/name: postgresql
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-storage-box
namespace: authentik
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: authentik-backup
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
# Hetzner Storage Box, borg ueber SSH - wie die Backups in `matrix`.
- to:
- ipBlock:
cidr: 91.98.246.178/32
ports:
- protocol: TCP
port: 23
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: egress-authentik-smtp
namespace: authentik
spec:
# Server und Worker tragen beide app.kubernetes.io/name=authentik.
podSelector:
matchLabels:
app.kubernetes.io/name: authentik
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
# E-Mail-Versand ueber smtp.ionos.de:587. TRAGEND, nicht optional: die
# Blueprints nutzen Passwort-Wiederherstellung und Einladungen per Mail.
#
# /27 statt zwei /32: Der Name loest heute auf 213.165.67.97 und .113 auf,
# beide im selben Block des Anbieters. Eine dritte Adresse wuerde bei /32
# den Mailversand brechen, ohne dass jemand eine Regel im Blick haette -
# 32 Adressen der Mail-Infrastruktur eines Anbieters sind der kleinere
# Preis. (Anders als bei ClamAV: das ist kein CDN vor dem halben Internet.)
- to:
- ipBlock:
cidr: 213.165.67.96/27
ports:
- protocol: TCP
port: 587
#
# BEWUSST NICHT erlaubt: version.goauthentik.io (Versionspruefung). Liegt
# hinter Cloudflare mit wechselnden Adressen und ist nicht tragend - der
# Aufruf scheitert und Authentik protokolliert es. Wer den Fehler spaeter
# findet: das ist Absicht, kein Versehen.