refactor(demo-gymburgdorf): drop DNS workarounds now backend can reach DMZ

The firewall now permits the backend subnet (172.16.19.0/24) to reach the
DMZ reverseproxy on 443, so server-to-server calls can use the public
FQDN over the reverseproxy instead of the previous workarounds:

- Remove the `*_extra_hosts` pins from nextcloud, opnform, bookstack and
  homarr; their OIDC discovery/issuer now uses the public auth.gymb.* FQDN
  (verified: discovery returns 200 with the public iss over the reverseproxy).
- Switch nextcloud OIDC discovery_url from auth.int.* to auth.gymb.*.
- Drop authentik_host_rewrite_domains and authentik_outpost_domains; point
  the LDAP outpost (both host_vars) at the public auth.gymb.* FQDN.
- Repoint the garage-webui ForwardAuth from the never-functional dedicated
  outpost FQDN to auth.gymb.*. The embedded outpost only serves the auth
  path when Host is a configured authentik_domain and matches the protected
  app via X-Forwarded-Host, so auth.gymb.* stays pinned to the application
  host on storage to bypass the reverseproxy's X-Forwarded-Host stripping.

The *.int.* names and their cert SANs are kept: the DMZ verifies the
backend cert (acme cert_mode) and connects by name, so they remain
structural to the DMZ->backend hop. The console.s3 DMZ route limitation
is pre-existing and tracked separately.
This commit is contained in:
Simon Bärlocher 2026-06-05 13:49:30 +02:00
parent 2206b809e7
commit 2942dabc54
No known key found for this signature in database
GPG key ID: 63DE20495932047A
8 changed files with 58 additions and 110 deletions

View file

@ -14,17 +14,19 @@ garage_use_ssl: true
garage_webui_enabled: true
# Gate the WebUI behind authentik (admins-only, via policy-binding on the
# authentik proxy app). Replaces the htpasswd Basic-Auth — AUTH_USER_PASS
# is dropped from the compose env when this is true. The forwardauth URL
# uses a dedicated outpost-only FQDN that's deliberately outside
# authentik_domains so Authentik routes it to the embedded outpost (not
# ASGI). The public auth.gymb.* FQDN would 404 here — Authentik routes
# any Host matching an auth-domain to ASGI which doesn't serve the outpost
# path. The outpost itself then matches the protected app via
# X-Forwarded-Host (Traefik forwards it via trustForwardHeader=true).
# The FQDN is pinned to the application host via traefik_extra_hosts so
# the request stays in the LAN.
# is dropped from the compose env when this is true.
#
# The embedded outpost only serves the /outpost.goauthentik.io/auth path
# when the request reaches authentik with Host set to a configured
# authentik_domain (auth.gymb.*); it then matches the protected app
# (console.s3.*) via X-Forwarded-Host. So the ForwardAuth must hit the
# app-host's `authentik` router (Host(auth.gymb), passHostHeader=true) —
# NOT the DMZ reverseproxy (strips X-Forwarded-Host) and NOT the auth.int
# rewrite router (overwrites X-Forwarded-Host). auth.gymb.* is therefore
# pinned to the application host in storage/traefik.yml so this single hop
# preserves the forwarded headers and stays in the LAN.
garage_webui_authentik_forward_auth: true
garage_webui_authentik_forward_auth_url: "https://outpost.auth.int.gymb.souveredu.ch/outpost.goauthentik.io/auth/traefik"
garage_webui_authentik_forward_auth_url: "https://auth.gymb.souveredu.ch/outpost.goauthentik.io/auth/traefik"
# Kept for completeness — only used when authentik ForwardAuth is off.
garage_webui_username: "admin"
garage_webui_password: "{{ _garage.webui_password | default('disabled') }}"

View file

@ -1,18 +1,12 @@
---
# Local traefik needs to reach authentik for the ForwardAuth subrequest
# the garage-webui router fires. The public IP is unreachable from this
# subnet (no DMZ hairpin), so pin both auth FQDNs directly at the
# application host where authentik runs. Without this the forwardauth
# middleware would time out and every garage-console request would 502.
# - auth.gymb.* covers any future server-to-server traffic on the public
# FQDN.
# - outpost.auth.int.gymb.* is the dedicated outpost endpoint actually
# used by the ForwardAuth middleware (see garage.yml). It exists only
# to skip Authentik's ASGI handler, which 404s the outpost path when
# Host is one of the configured authentik_domains.
# The garage-webui ForwardAuth middleware fires a subrequest to authentik
# (see garage.yml). It must reach the app-host's `authentik` router
# directly — going via the DMZ reverseproxy strips X-Forwarded-Host, which
# breaks the embedded outpost's app matching. The internal DNS view points
# auth.gymb.* at the reverseproxy, so pin it to the application host here
# to force the single direct hop that preserves the forwarded headers.
traefik_extra_hosts:
- "auth.gymb.souveredu.ch:172.16.19.101"
- "outpost.auth.int.gymb.souveredu.ch:172.16.19.101"
# Services hosted on `storage` that the DMZ reverseproxy should forward
# public traffic to. See application/traefik.yml for the mechanism.
@ -24,8 +18,11 @@ traefik_dmz_exposed_services:
protocol: https
- name: garage-webui
domain: console.s3.gymb.souveredu.ch
# No internal FQDN/cert SAN for console.s3 yet — would need an
# extra_domain on garage-webui. Until then this route will 500
# against the storage backend (cert mismatch on raw IP).
# Pre-existing limitation, orthogonal to the DNS cleanup: the DMZ
# verifies the storage backend cert (acme cert_mode), but with no
# backend_host set it connects by IP, which the storage cert has no
# SAN for, so this route fails the TLS verify. Fixing it needs the
# garage role to expose a console extra_domain (e.g. console.s3.int.*)
# for the backend_host + cert SAN — tracked separately.
port: 443
protocol: https