Fix Authelia bypass on remote-Authelia forward_auth (asterisk-digital-ocean)

The remote-Authelia forward_auth block dialed a scheme-qualified upstream
(https://auth.example.com), which is a second Caddy hop. Caddy rewrites the
outgoing Host header to the upstream host for routing, and without an
explicit override X-Forwarded-Host picked up that rewritten value instead
of the original site's host. Authelia was evaluating every protected
domain as auth.example.com itself (bypass policy), so 2FA never triggered
for any domain behind the remote instance. Pin the forwarded headers to
the original request explicitly to fix it.
This commit is contained in:
Claude
2026-07-20 20:09:37 +00:00
parent 861b4478a8
commit 0764be44da
2 changed files with 49 additions and 0 deletions
+31
View File
@@ -173,6 +173,37 @@ service builds its own site block instead of using this helper (e.g.
`services/asterisk-digital-ocean.sh` does, deliberately, see its own
comment for why), put its auth block first there too.
**`forward_auth` to a remote Authelia over a scheme-qualified URL needs
explicit `header_up` pins.** A bare `forward_auth authelia:9091` (Authelia on
the same Docker network, one hop) is fine relying on Caddy's default
`X-Forwarded-*` headers. But `forward_auth https://auth.example.com { ... }`
(Authelia on a *different* machine, reached over its own public domain+TLS —
see `services/asterisk-digital-ocean.sh`'s remote-Authelia prompt) is a
second Caddy hop: Caddy rewrites the outgoing request's `Host` header to
`auth.example.com` so the remote Caddy can route/SNI-match it, and without an
override `X-Forwarded-Host` picks up that rewritten value instead of the
original site's host. Confirmed live: Authelia evaluated *every* protected
domain as if the request were for `auth.example.com` itself (which typically
has `policy: bypass` in `access_control.rules` so its own login portal isn't
gated behind itself) — so every domain behind the remote instance silently
passed through with no 2FA prompt, regardless of that domain's own policy.
Fix: pin the forwarded headers to the original request explicitly instead of
trusting Caddy's default derivation:
```
forward_auth https://auth.example.com {
uri /api/authz/forward-auth
copy_headers Remote-User Remote-Groups Remote-Name Remote-Email
header_up X-Forwarded-Method {method}
header_up X-Forwarded-Proto {scheme}
header_up X-Forwarded-Host {host}
header_up X-Forwarded-Uri {uri}
}
```
This only affects the remote-Authelia path — same-machine `authelia:9091`
snippets (`services/authelia.sh`) are a single hop and don't need it.
Sets two out-params (not `local` — read them after the call returns) so the
caller can tell whether Caddy actually ended up fronting the service:
+18
View File
@@ -584,9 +584,27 @@ ENV
local _remote_authelia=""
prompt_text " Remote Authelia address — a bare host:port over a private network (e.g. a NetBird mesh IP:9091), or a full https:// URL if it's on its own public domain+TLS:" "" _remote_authelia
if [[ -n "$_remote_authelia" ]]; then
# header_up lines are required here (unlike the local
# "authelia:9091" snippet in services/authelia.sh) because
# this upstream is reached over a second Caddy hop when
# given as a scheme-qualified URL (https://auth.example.com).
# Caddy rewrites the outgoing request's Host header to that
# upstream host so the remote Caddy can route/SNI-match it —
# and without an explicit override, X-Forwarded-Host picks up
# that rewritten value instead of the original site's host.
# Confirmed live: Authelia was evaluating every request as
# if it were for auth.example.com itself (which has
# policy: bypass in access_control.rules), so every domain
# silently passed through with no 2FA prompt regardless of
# its own policy. Pinning these to the original request's
# values fixes it regardless of hop count.
EXTRA_BLOCK=" forward_auth ${_remote_authelia} {
uri /api/authz/forward-auth
copy_headers Remote-User Remote-Groups Remote-Name Remote-Email
header_up X-Forwarded-Method {method}
header_up X-Forwarded-Proto {scheme}
header_up X-Forwarded-Host {host}
header_up X-Forwarded-Uri {uri}
}"
sed -i "s/^WEB_ADMIN_AUTH_DISABLED=.*/WEB_ADMIN_AUTH_DISABLED=true/" .env
log_info "Using remote Authelia at ${_remote_authelia}."