The 'Regelwerk Bindung resultiert in False' denial after login means the user is not a member of wiki-zugang (step 2.4). Record it plus the redirect-loop and outpost-offline cases so the next person recognises them fast.
13 KiB
Docusaurus-Wiki hinter Authentik (Forward-Auth)
Status: vorbereitet, nicht ausgerollt · Host: axionwiki.lab
(#0024 entschieden 2026-08-12) · Entscheidung: bei Docusaurus bleiben, Zugang per
Authentik (DOC-03/#0020)
Docusaurus ist ein statischer Site-Generator — kein Nutzermodell, kein Login.
Der Zugang wird deshalb im Reverse-Proxy davor erzwungen: Traefik fragt bei
jedem Request einen Authentik-Outpost, ob eine gültige Sitzung vorliegt, und
leitet sonst zu auth.axion1337.chat um. Erst nach Login gibt Traefik die
statischen Seiten frei. Es ist ein Alles-oder-nichts-Tor (wer in der Gruppe
wiki-zugang ist, sieht das ganze Wiki; sonst nichts) — für Bereichs-Rechte
bräuchte es BookStack (ADR-0007), das war aber ausdrücklich nicht gewollt.
⚠️ Nur für die Entwicklung — das hier ist ein Zwischenstand
Diese Fassung (Docusaurus auf Overmind unter axionwiki.lab, Forward-Auth über
den Prod-Authentik) trägt während der Entwicklung. Zwei Dinge stehen bewusst
noch aus und dürfen dabei nicht in Vergessenheit geraten:
- Das Wiki zieht in die ThreadNet Server Suite um. Es soll Teil des reproduzierbaren Stacks werden (Vision „reproduzierbar für Dritte"), nicht ein Einzelstück auf dem Lab-Host. Dann ändern sich Host, Proxy und ggf. die Auth-Anbindung erneut. → [management-Issue: Wiki in die ThreadNet Server Suite umziehen]
- Danach werden Oberflächen-Alternativen über BookStack hinaus geprüft. Die Docusaurus-Entscheidung gilt für jetzt; die breitere Evaluation (nicht nur Docusaurus vs. BookStack) kommt nach dem Umzug. → [management-Issue: Wiki-Oberfläche über BookStack hinaus prüfen]
Alles unten ist deshalb so gebaut, dass es jetzt funktioniert und beim Umzug sauber ablösbar ist (eigener Outpost, keine Verdrahtung in fremde Stacks).
Topologie
Das Wiki läuft als Dokploy-Stack auf Overmind (git.lab/homelab/wiki,
axionwiki.lab), Authentik im K3s-Cluster auf Hetzner. Deshalb ein
eigener Proxy-Outpost als Container auf Overmind, statt des eingebetteten
Outposts in Hetzner: So bleiben die Auth-Subrequests lokal auf Overmind — nur die
Login-Umleitung quert den Site-to-Site-VPN zu auth.axion1337.chat. Das passt
zur Leitlinie „das Lab hängt nicht am Prod-Host": ist eine Sitzung erst gesetzt,
liest sich das Wiki im Lab auch ohne ständige Rückfrage nach Hetzner.
Browser ──▶ Traefik (Overmind) ──forwardAuth──▶ authentik-proxy (Overmind, :9000)
│ │ Sitzung? nein ──▶ 302
└────────────── Login-Redirect ─────────────▶ auth.axion1337.chat (Hetzner, via VPN)
Teil 1 — Authentik-Blueprint (deklarativ)
Als neues Dokument in apps/authentik/authentik-blueprints.yaml einfügen
(gleiche ConfigMap wie matrix-oidc-provider.yaml). Host ist entschieden
(axionwiki.lab), also apply-fertig — trotzdem erst mit Teil 2/3 zusammen scharf
schalten.
wiki-forward-auth.yaml: |
# yaml-language-server: $schema=https://goauthentik.io/blueprints/schema.json
version: 1
metadata:
name: wiki-forward-auth
labels:
blueprints.goauthentik.io/instantiate: "true"
entries:
# Proxy-Provider im Forward-Auth-Modus. Kein internal_host (das wäre der
# Proxy-Modus) — forward_single reicht Traefik nur das Ja/Nein zurück.
- model: authentik_providers_proxy.proxyprovider
state: present
identifiers:
name: ThreadNet Wiki
id: wiki_proxy_provider
attrs:
mode: forward_single
external_host: https://axionwiki.lab
authorization_flow: !Find [authentik_flows.flow, [slug, default-provider-authorization-implicit-consent]]
invalidation_flow: !Find [authentik_flows.flow, [slug, default-provider-invalidation-flow]]
access_token_validity: hours=24
- model: authentik_core.application
state: present
identifiers:
slug: wiki
id: wiki_app
attrs:
name: ThreadNet Wiki
provider: !KeyOf wiki_proxy_provider
meta_description: Internes Docusaurus-Wiki, nur Gruppe wiki-zugang
policy_engine_mode: any
open_in_new_tab: true
# Zugangsbeschränkung: nur Mitglieder dieser Gruppe passieren das Tor.
- model: authentik_core.group
state: present
identifiers:
name: wiki-zugang
id: wiki_group
- model: authentik_policies.policybinding
state: present
identifiers:
target: !KeyOf wiki_app
group: !KeyOf wiki_group
order: 0
attrs:
enabled: true
negate: false
⚠️ Vor dem Merge von Hand verifizieren, nicht auf Flux vertrauen — ein
Blueprint-Fehler scheitert still (Lehre aus dem matrix-recovery-Fix). Nach dem
Einspielen prüfen, dass der Lauf successful ist:
kubectl exec -n authentik authentik-postgresql-0 -- sh -c \
'PGPASSWORD="$(cat "$POSTGRES_PASSWORD_FILE")" psql -U authentik -d authentik -At -c \
"SELECT name, status FROM authentik_blueprints_blueprintinstance WHERE name='"'"'wiki-forward-auth'"'"'"'
Teil 2 — Outpost + Token in Authentik (sorb, Schritt für Schritt)
Der Outpost ist der Prozess, den Traefik fragt; sein Token ist ein Credential und kommt nicht ins Repo.
2.1 — Laufende Authentik-Version feststellen (der Outpost-Container muss exakt dieselbe Version tragen, sonst verweigert Authentik die Anmeldung des Outposts):
kubectl -n authentik get deploy authentik-server \
-o jsonpath='{.spec.template.spec.containers[0].image}'; echo
# -> ghcr.io/goauthentik/server:2024.x.y --> merke dir 2024.x.y
2.2 — Outpost anlegen: Authentik-Admin → Applications → Outposts (die Liste der Outposts) → Create.
⚠️ Nicht „Outpost-Integrationen". Das ist ein anderer Menüpunkt: dort legt man eine Docker-/K8s-Service-Verbindung an, über die Authentik einen Outpost selbst ausrollt — der Dialog „Neue Outpost-Integration" bietet deshalb nur Docker oder Kubernetes und lässt sich nicht leer lassen. Brauchen wir nicht (Prod würde sonst in Overminds Docker greifen). Wenn du dort gelandet bist: Abbrechen und in Outposts wechseln.
Im Outpost-Formular:
- Name:
wiki-forward-auth - Type:
Proxy - Integration: das Dropdown auf „No integration"/leer stehen lassen (der Standard) — der Container läuft extern auf Overmind (Teil 3) und meldet sich per Token zurück. Nur wenn du dieses Feld auf Docker/K8s stellst, verlangt es eine Service-Verbindung.
- Applications: ThreadNet Wiki auswählen.
- Advanced settings →
authentik_host:https://auth.axion1337.chat(die URL, die der Container und der Browser fürs Login erreichen).
2.3 — Token abgreifen: beim neuen Outpost auf View Deployment Info (bzw.
Directory → Tokens, Eintrag ak-outpost-<id>-api) → Token kopieren. Dieser
Wert wird in Teil 3 als WIKI_OUTPOST_TOKEN gesetzt — sonst nirgends hin, nicht
loggen, nicht committen.
2.4 — Wer rein darf: Directory → Groups → wiki-zugang (vom Blueprint
angelegt) → die internen Nutzer hinzufügen. Wer nicht drin ist, bekommt nach dem
Login 403.
Teil 3 — Overmind: Outpost-Container + Traefik (git.lab/homelab/wiki)
Beides gehört in den Dokploy-Stack des Wikis. Kernpunkte zuerst, dann das Fragment:
- Gemeinsames Netz. Outpost- und Wiki-Container müssen im selben von Traefik
beobachteten Docker-Netz liegen (bei Dokploy i. d. R.
dokploy-network) — sonst findet dieforwardAuth-Adresse den Outpost nicht. - Version pinnen auf die aus 2.1 ermittelte (
proxy:2024.x.y==server). AUTHENTIK_INSECURE: "false"—auth.axion1337.chathat ein gültiges öffentliches Zertifikat; kein Lab-CA-Trust nötig, weil der Outpost nach Hetzner spricht, nicht ins Lab.- Der
/outpost.goauthentik.io/-Router bekommt die Auth-Middleware NICHT — sonst schützt sich der Login-Callback selbst aus und es entsteht eine Redirect-Schleife. - Das Token kommt als Dokploy-Environment/Secret
WIKI_OUTPOST_TOKEN, nicht im Klartext in die committete Compose-Datei.
services:
# 1) Der Proxy-Outpost — er beantwortet Traefiks forwardAuth-Frage.
authentik-proxy:
image: ghcr.io/goauthentik/proxy:2024.x.y # == laufende Authentik-Version (2.1)
restart: unless-stopped
environment:
AUTHENTIK_HOST: https://auth.axion1337.chat
AUTHENTIK_INSECURE: "false"
AUTHENTIK_TOKEN: ${WIKI_OUTPOST_TOKEN} # aus Teil 2.3 (Dokploy-Secret)
networks: [dokploy-network]
labels:
traefik.enable: "true"
traefik.docker.network: dokploy-network
# Router NUR für den Outpost-Callback-Pfad — OHNE Auth-Middleware:
traefik.http.routers.wiki-authentik.rule: "Host(`axionwiki.lab`) && PathPrefix(`/outpost.goauthentik.io/`)"
traefik.http.routers.wiki-authentik.entrypoints: websecure
traefik.http.routers.wiki-authentik.tls: "true"
traefik.http.routers.wiki-authentik.service: wiki-authentik
traefik.http.services.wiki-authentik.loadbalancer.server.port: "9000"
# 2) Der bestehende Docusaurus-Service — nur um die Auth-Middleware erweitert.
wiki:
# ... bestehendes image/build/volumes ...
networks: [dokploy-network]
labels:
traefik.enable: "true"
traefik.docker.network: dokploy-network
traefik.http.routers.wiki.rule: "Host(`axionwiki.lab`)"
traefik.http.routers.wiki.entrypoints: websecure
traefik.http.routers.wiki.tls: "true"
traefik.http.routers.wiki.middlewares: "wiki-auth@docker"
# Die forwardAuth-Middleware:
traefik.http.middlewares.wiki-auth.forwardauth.address: "http://authentik-proxy:9000/outpost.goauthentik.io/auth/traefik"
traefik.http.middlewares.wiki-auth.forwardauth.trustForwardHeader: "true"
traefik.http.middlewares.wiki-auth.forwardauth.authResponseHeaders: "X-authentik-username,X-authentik-groups,X-authentik-entitlements,X-authentik-email,X-authentik-name,X-authentik-uid,X-authentik-jwt,X-authentik-meta-jwks,X-authentik-meta-outpost,X-authentik-meta-provider,X-authentik-meta-app,X-authentik-meta-version"
networks:
dokploy-network:
external: true
Ablauf einer Anfrage (zum Nachvollziehen beim Debuggen):
- Browser →
axionwiki.lab; Traefik ruftwiki-auth→authentik-proxy:9000/.../auth/traefik. - Keine Sitzung → Outpost antwortet 302 auf
auth.axion1337.chat(Login). - Nach Login kommt der Browser auf
axionwiki.lab/outpost.goauthentik.io/callbackzurück (der Router aus Service 1, ohne Middleware), Outpost setzt das Cookie. - Erneuter Request trägt das Cookie →
auth/traefikgibt 200 + dieX-authentik-*-Header → Traefik reicht an Docusaurus durch.
Abhängigkeiten
- #0024 (Wiki-Hostname) — entschieden:
axionwiki.lab(2026-08-12).external_host, der Traefik-Host()und der Cookie-Scope zeigen alle darauf. - #0018 (Wiki-Rollout) — sollte abgeschlossen sein, bevor das Tor davor kommt.
- Site-to-Site-VPN — die Login-Umleitung und die Outpost-Konfigsync brauchen
auth.axion1337.chaterreichbar; interne Nutzer im Lab/über VPN erreichen beides.
Verifikation
curl -sI https://axionwiki.lab(unauthentifiziert) → 302 aufauth.axion1337.chat.- Login als
wiki-zugang-Mitglied → Wiki lädt. - Login als Nicht-Mitglied → 403 (Policy greift).
- Outpost-Gesundheit: im Authentik-Admin zeigt der Outpost
wiki-forward-authgrün/last seen und die passende Version. - Resilienz-Gegenprobe:
auth.axion1337.chatkurz nicht erreichbar → bestehende Sitzung liest weiter (lokaler Outpost), nur neuer Login blockiert.
Fehlerbild
- „Anfrage wurde verweigert — Regelwerk Bindung … resultiert in False" nach
dem Login: Du bist nicht in
wiki-zugang(Schritt 2.4 übersprungen). Daspolicy=Nonein der Meldung ist normal — es ist eine Gruppen-Bindung. Fix: Directory → Groups → wiki-zugang → Nutzer hinzufügen, neu einloggen. - Redirect-Schleife: der
/outpost.goauthentik.io/-Router hat versehentlich die Auth-Middleware (Teil 3) — entfernen. - Outpost bleibt in Authentik „offline"/rot: Version des
proxy-Containers passt nicht zur Server-Version (2.1) oder Token/AUTHENTIK_HOSTfalsch.
Was hier bewusst offen bleibt
- Nichts ist live geschaltet — der Blueprint liegt als Vorlage hier, nicht in der angewandten ConfigMap; der Outpost-Token ist sorbs Schritt.
- Kein Bereichs-Schutz — Grenze von Docusaurus + Forward-Auth.
- Zwischenstand — siehe „Nur für die Entwicklung" oben: Umzug in die ThreadNet Server Suite und die breitere Oberflächen-Evaluation stehen noch aus.