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:
parent
2206b809e7
commit
2942dabc54
8 changed files with 58 additions and 110 deletions
|
|
@ -10,26 +10,9 @@ _authentik: "{{ lookup('community.hashi_vault.hashi_vault', vault_mount + '/data
|
|||
authentik_domains:
|
||||
- "auth.gymb.souveredu.ch"
|
||||
|
||||
# Internal FQDN for server-to-server calls (Nextcloud OIDC discovery,
|
||||
# token, userinfo; LDAP outpost configuration pull). Traefik rewrites
|
||||
# the Host header to `authentik_domains[0]` on these routers so authentik
|
||||
# still emits issuer URLs against the public hostname — that keeps the
|
||||
# iss claim matching what the browser sees while the traffic itself
|
||||
# stays inside the LAN (the DMZ has no hairpin-NAT for the public IP).
|
||||
authentik_host_rewrite_domains:
|
||||
- "auth.int.gymb.souveredu.ch"
|
||||
authentik_secret_key: "{{ _authentik.secret_key }}"
|
||||
authentik_postgres_password: "{{ _authentik.postgres_password }}"
|
||||
|
||||
# Dedicated FQDN for cross-host ForwardAuth (storage Traefik calling
|
||||
# /outpost.goauthentik.io/auth/traefik). Routing through the public
|
||||
# auth.gymb.* FQDN doesn't work — Authentik sees Host: auth.gymb.* and
|
||||
# routes to ASGI which 404s the outpost path. This FQDN sits outside
|
||||
# authentik_domains so the same request falls through to the embedded
|
||||
# outpost handler (which matches the protected app via X-Forwarded-Host).
|
||||
authentik_outpost_domains:
|
||||
- "outpost.auth.int.gymb.souveredu.ch"
|
||||
|
||||
# LDAP outpost (provider for nextcloud)
|
||||
authentik_ldap_apps:
|
||||
- slug: ldap
|
||||
|
|
@ -41,9 +24,10 @@ authentik_ldap_outpost:
|
|||
name: "ldap-outpost"
|
||||
token: "{{ _authentik.ldap_outpost_token }}"
|
||||
config:
|
||||
# Outpost pulls config from authentik over the internal FQDN — keeps
|
||||
# the round-trip in the LAN with a valid cert.
|
||||
authentik_host: "https://auth.int.gymb.souveredu.ch/"
|
||||
# Outpost pulls config from authentik over the public FQDN, which
|
||||
# resolves (internal DNS view) to the DMZ reverseproxy the backend
|
||||
# subnet can reach — keeps the round-trip in the LAN with a valid cert.
|
||||
authentik_host: "https://auth.gymb.souveredu.ch/"
|
||||
log_level: "info"
|
||||
|
||||
# Proxy providers (ForwardAuth) — gate downstream services behind
|
||||
|
|
|
|||
|
|
@ -3,5 +3,8 @@
|
|||
# authenticate against the authentik server it talks to.
|
||||
_authentik: "{{ lookup('community.hashi_vault.hashi_vault', vault_mount + '/data/authentik', url=vault_addr) }}"
|
||||
|
||||
authentik_outpost_ldap_host: "https://auth.int.gymb.souveredu.ch"
|
||||
# Public FQDN resolves (internal DNS view) to the DMZ reverseproxy the
|
||||
# backend subnet can reach, so the outpost->authentik round-trip stays in
|
||||
# the LAN with a valid cert and matches the iss claim authentik emits.
|
||||
authentik_outpost_ldap_host: "https://auth.gymb.souveredu.ch"
|
||||
authentik_outpost_ldap_token: "{{ _authentik.ldap_outpost_token }}"
|
||||
|
|
|
|||
|
|
@ -20,11 +20,11 @@ bookstack_admin_email: "admin@gymb.souveredu.ch"
|
|||
bookstack_admin_name: "BookStack Admin"
|
||||
|
||||
# OIDC against Authentik. BookStack compares OIDC_ISSUER strictly against
|
||||
# the `iss` claim in the discovery response. Authentik emits the public
|
||||
# auth.gymb.* hostname there (host-rewrite middleware ensures the claim
|
||||
# matches what browsers see during login), so the issuer URL must use the
|
||||
# public FQDN. Pinning auth.gymb.* in /etc/hosts below keeps the actual
|
||||
# server-to-server traffic on the LAN.
|
||||
# the `iss` claim in the discovery response, and Authentik emits the
|
||||
# public auth.gymb.* hostname there, so the issuer must use the public
|
||||
# FQDN. That FQDN resolves (internal DNS view) to the DMZ reverseproxy,
|
||||
# which the backend subnet can reach, so the server-to-server calls stay
|
||||
# in the LAN.
|
||||
bookstack_oidc_enabled: true
|
||||
bookstack_oidc_name: "Authentik"
|
||||
bookstack_oidc_issuer: "https://auth.gymb.souveredu.ch/application/o/bookstack/"
|
||||
|
|
@ -34,10 +34,3 @@ bookstack_oidc_additional_scopes: "openid profile email"
|
|||
bookstack_oidc_user_to_groups: true
|
||||
bookstack_oidc_groups_claim: "groups"
|
||||
bookstack_oidc_auto_initiate: false
|
||||
|
||||
# Pin auth.gymb.* to the application host so server-to-server OIDC calls
|
||||
# (discovery, token, userinfo, jwks) stay in the LAN and reach authentik
|
||||
# directly without hairpinning through the DMZ (which has no NAT loop
|
||||
# back to its own public IP).
|
||||
bookstack_extra_hosts:
|
||||
- "auth.gymb.souveredu.ch:172.16.19.101"
|
||||
|
|
|
|||
|
|
@ -18,12 +18,11 @@ homarr_admin_password: "{{ _homarr.admin_password }}"
|
|||
# AUTH_OIDC_AUTO_LOGIN bypasses the normal /login page.
|
||||
#
|
||||
# Issuer must match the `iss` claim authentik emits, which is always the
|
||||
# public FQDN (authentik's host-rewrite middleware aligns the claim with
|
||||
# what browsers see). Homarr (oauth4webapi) does a strict 1:1 comparison
|
||||
# between the discovery response's issuer and this URL — using the
|
||||
# internal FQDN here fails with OAUTH_JSON_ATTRIBUTE_COMPARISON_FAILED.
|
||||
# The extra_hosts pin below keeps the actual discovery/token/userinfo
|
||||
# traffic on the LAN.
|
||||
# public FQDN. Homarr (oauth4webapi) does a strict 1:1 comparison between
|
||||
# the discovery response's issuer and this URL — an internal FQDN here
|
||||
# fails with OAUTH_JSON_ATTRIBUTE_COMPARISON_FAILED. The public FQDN
|
||||
# resolves (internal DNS view) to the DMZ reverseproxy, which the backend
|
||||
# subnet can reach, so discovery/token/userinfo stay in the LAN.
|
||||
homarr_auth_providers: "credentials,oidc"
|
||||
homarr_oidc_issuer: "https://auth.gymb.souveredu.ch/application/o/homarr/"
|
||||
homarr_oidc_client_id: "homarr"
|
||||
|
|
@ -33,14 +32,6 @@ homarr_oidc_scopes: "openid profile email groups"
|
|||
homarr_oidc_groups_attribute: "groups"
|
||||
homarr_oidc_auto_login: "true"
|
||||
|
||||
# Pin the public authentik FQDN to the application host so OIDC
|
||||
# discovery (and downstream token/userinfo) calls from the homarr
|
||||
# container stay in the LAN. Without this, fetch() to auth.gymb.* would
|
||||
# hit the public IP and time out in the DMZ (no hairpin-NAT). Same
|
||||
# pattern as nextcloud_extra_hosts.
|
||||
homarr_extra_hosts:
|
||||
- "auth.gymb.souveredu.ch:172.16.19.101"
|
||||
|
||||
# Default board with shortcuts to the other gymburgdorf services. Width
|
||||
# values describe horizontal grid cells (1-10 desktop / 6 tablet / 2
|
||||
# mobile, packed left-to-right).
|
||||
|
|
|
|||
|
|
@ -62,25 +62,16 @@ nextcloud_s3_port: 443
|
|||
nextcloud_s3_ssl: true
|
||||
nextcloud_s3_usepath_style: true
|
||||
|
||||
# OIDC server-to-server discovery / token / userinfo goes to
|
||||
# auth.int.gymb.souveredu.ch (LAN, RFC1918). Nextcloud's DnsPinMiddleware
|
||||
# would otherwise block that as "local server access".
|
||||
# OIDC discovery/token/userinfo and the S3 backend both target FQDNs
|
||||
# that resolve to RFC1918 addresses (auth.gymb.* via the reverseproxy,
|
||||
# s3.int.* directly), which Nextcloud's DnsPinMiddleware would otherwise
|
||||
# block as "local server access".
|
||||
nextcloud_allow_local_remote_servers: true
|
||||
|
||||
# Share the LDAP docker network with the authentik LDAP outpost
|
||||
nextcloud_extra_networks:
|
||||
- ldap
|
||||
|
||||
# Pin the public authentik FQDN to the application host so server-to-server
|
||||
# OIDC traffic (token, userinfo, jwks — endpoints the discovery doc lists
|
||||
# under auth.gymb.* even when discovery itself is fetched via auth.int.*)
|
||||
# stays in the LAN. Without this, curl in the PHP container would hit the
|
||||
# public IP and time out in the DMZ (no hairpin-NAT). The DnsPin middleware
|
||||
# only honours /etc/hosts when allow_local_remote_servers is enabled, so
|
||||
# that flag (set above) is what makes this entry effective.
|
||||
nextcloud_extra_hosts:
|
||||
- "auth.gymb.souveredu.ch:172.16.19.101"
|
||||
|
||||
# LDAP backend (Authentik LDAP outpost)
|
||||
nextcloud_ldap_enabled: true
|
||||
nextcloud_ldap_config:
|
||||
|
|
@ -118,13 +109,12 @@ nextcloud_oidc_providers:
|
|||
display_name: "Login with Authentik"
|
||||
client_id: nextcloud
|
||||
client_secret: "{{ _authentik.nextcloud_oidc_secret }}"
|
||||
# Discovery via the internal FQDN (LAN-only) — the DMZ has no
|
||||
# hairpin-NAT for the public IP, so server-to-server calls to
|
||||
# auth.gymb.* would time out. The traefik router for auth.int.*
|
||||
# rewrites the Host header to auth.gymb.souveredu.ch before the
|
||||
# request reaches authentik, so the iss claim authentik emits still
|
||||
# matches the public hostname the browser sees during login.
|
||||
discovery_url: "https://auth.int.gymb.souveredu.ch/application/o/nextcloud/.well-known/openid-configuration"
|
||||
# Discovery via the public FQDN. It resolves (internal DNS view) to
|
||||
# the DMZ reverseproxy, which the backend subnet can now reach, so
|
||||
# the server-to-server call stays in the LAN while the iss claim and
|
||||
# all listed endpoints match the public hostname the browser sees
|
||||
# during login — no host-rewrite or /etc/hosts pin needed.
|
||||
discovery_url: "https://auth.gymb.souveredu.ch/application/o/nextcloud/.well-known/openid-configuration"
|
||||
scope: "openid email profile"
|
||||
unique_uid: true
|
||||
mapping:
|
||||
|
|
|
|||
|
|
@ -23,18 +23,13 @@ opnform_admin_name: "OpnForm Admin"
|
|||
opnform_admin_email: "admin@gymb.souveredu.ch"
|
||||
opnform_admin_password: "{{ _opnform.admin_password }}"
|
||||
|
||||
# OIDC against Authentik. Discovery via the internal FQDN keeps
|
||||
# server-to-server traffic in the LAN; Authentik's host-rewrite router
|
||||
# rewrites the Host header to auth.gymb.* before the request reaches
|
||||
# authentik so the iss claim still matches the public hostname browsers
|
||||
# see during login.
|
||||
# OIDC against Authentik. The public auth.gymb.* FQDN resolves (internal
|
||||
# DNS view) to the DMZ reverseproxy, which the backend subnet can reach,
|
||||
# so OpnForm's discovery/token/userinfo calls stay in the LAN while the
|
||||
# iss claim matches the public hostname browsers see during login.
|
||||
opnform_oidc_enabled: true
|
||||
# Issuer must use the public auth.gymb.* FQDN: OpnForm does OIDC
|
||||
# discovery and then validates the token's `iss` claim against this
|
||||
# value. Authentik emits the public hostname in `iss` (its host-rewrite
|
||||
# middleware keeps the claim aligned with what browsers see), so an
|
||||
# internal-FQDN issuer here would fail iss validation. The extra_hosts
|
||||
# pin below keeps the actual discovery/token/userinfo traffic on the LAN.
|
||||
# Issuer must use the public FQDN: OpnForm validates the token's `iss`
|
||||
# claim against this value, and Authentik emits the public hostname there.
|
||||
opnform_oidc_issuer: "https://auth.gymb.souveredu.ch/application/o/opnform/"
|
||||
opnform_oidc_client_id: "opnform"
|
||||
opnform_oidc_client_secret: "{{ _opnform.oidc_client_secret }}"
|
||||
|
|
@ -53,10 +48,3 @@ opnform_oidc_force_login: true
|
|||
# Break-glass: /login?bypass=1 reaches the email form when the IdP is
|
||||
# down.
|
||||
opnform_oidc_sso_entrypoint: true
|
||||
|
||||
# Pin auth.gymb.* to the application host so server-to-server OIDC
|
||||
# calls (token, userinfo, jwks — endpoints discovery returns under the
|
||||
# public hostname even when discovery itself is fetched via auth.int.*)
|
||||
# stay in the LAN.
|
||||
opnform_extra_hosts:
|
||||
- "auth.gymb.souveredu.ch:172.16.19.101"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue