gateway: pin the Host header when dialing swarm services by name

verifiedProxyTo (43ae164d) verified TLS but left Host to nixpkgs'
recommendedProxySettings, which sets Host to the CALLING vhost, not
the target. Since every consumer resolves back to this same gateway,
nginx picks the vhost to answer by Host header (not by the SNI
proxy_ssl_name already sends) — so every auth subrequest looped back
into its own vhost's auth_request, recursing until nginx's subrequest
depth limit turned it into a 500, on every domain gated by SSO.

Pin Host (and the rest of the header set nixpkgs' recommended include
would otherwise still be the one to set) inside verifiedProxyTo, and
set recommendedProxySettings = false on each of the four call sites so
nixpkgs' own copy — appended after a location's extraConfig — can't
clobber it back.
This commit is contained in:
müde 2026-08-27 20:04:40 +02:00
commit 8a0ecb307b
4 changed files with 36 additions and 0 deletions

View file

@ -517,6 +517,10 @@ in
# co-location nobody had agreed to. The name resolves here
# today and resolves off-host later without this line moving.
proxyPass = "https://${autheliaCfg.domain}/api/authz/auth-request";
# nixpkgs appends its OWN `Host $host` after extraConfig,
# which would override verifiedProxyTo's — see the comment
# on verifiedProxyTo in hive-gateway/vhost-lib.nix.
recommendedProxySettings = false;
extraConfig = ''
internal;
${gatewayCfg.lib.verifiedProxyTo autheliaCfg.domain}

View file

@ -112,12 +112,32 @@ in
# testing though — the session cache is keyed by upstream address and
# NOT by trust config, so two locations pointing at one upstream with
# different trust do not verify independently.
#
# ⚠️ Also pins `Host` (and reinstates the rest of nginx's
# `recommendedProxySettings` header set) to `name` rather than leaving
# it to be filled in later. `name` here resolves back to THIS gateway
# — every consumer dials another vhost on the same nginx, not a
# separate host — and nginx picks the vhost to answer an HTTPS request
# from the `Host` header, not from the TLS SNI that `proxy_ssl_name`
# above sends. `recommendedProxySettings`'s own `Host $host` (the
# CALLER's host, not the target) is textually appended by nixpkgs
# AFTER a location's `extraConfig` — so it always wins over a
# `proxy_set_header Host` written in the location body, and the
# subrequest loops back into the ORIGINAL vhost instead of reaching
# the target, recursing on its own `auth_request` until nginx's
# subrequest-depth limit turns it into a plain 500. Every call site
# sets `recommendedProxySettings = false` on the location for exactly
# this reason — nixpkgs' version would still clobber this one.
verifiedProxyTo = name: ''
proxy_ssl_verify on;
proxy_ssl_verify_depth 3;
proxy_ssl_trusted_certificate ${caBundle};
proxy_ssl_name ${name};
proxy_ssl_server_name on;
proxy_set_header Host ${name};
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Server $hostname;
'';
# Security headers added at the server scope on every vhost.

View file

@ -273,6 +273,10 @@ in
# frontend calls this one directly.
"= /api/whoami" = {
proxyPass = "https://${autheliaCfg.domain}/api/user/info";
# nixpkgs appends its OWN `Host $host` after extraConfig,
# which would override verifiedProxyTo's — see the comment
# on verifiedProxyTo in hive-gateway/vhost-lib.nix.
recommendedProxySettings = false;
extraConfig = ''
${swarmAuthRequest}
${gatewayCfg.lib.verifiedProxyTo autheliaCfg.domain}
@ -296,6 +300,10 @@ in
# would look like configuration and be dead weight.
"= /__hive_authelia" = {
proxyPass = "https://${autheliaCfg.domain}/api/authz/auth-request";
# nixpkgs appends its OWN `Host $host` after extraConfig,
# which would override verifiedProxyTo's — see the comment
# on verifiedProxyTo in hive-gateway/vhost-lib.nix.
recommendedProxySettings = false;
extraConfig = ''
internal;
${gatewayCfg.lib.verifiedProxyTo autheliaCfg.domain}

View file

@ -183,6 +183,10 @@ in
# pinned authelia binary, not copied from an example).
"= /__hive_authelia" = {
proxyPass = "https://${autheliaCfg.domain}/api/authz/auth-request";
# nixpkgs appends its OWN `Host $host` after extraConfig,
# which would override verifiedProxyTo's — see the comment
# on verifiedProxyTo in hive-gateway/vhost-lib.nix.
recommendedProxySettings = false;
extraConfig = ''
internal;
${gatewayCfg.lib.verifiedProxyTo autheliaCfg.domain}