swarm-authelia: stop answering machine callers with a 200 error page
The authelia vhost intercepts upstream errors and serves a friendly
"SSO unavailable" page. The `=` form of `error_page` takes its status
from the redirected location, and that location serves a file -- so the
page is returned as **200**.
That is right for a human typing the URL and wrong for every machine
caller, all of which reach authelia through this same vhost by name:
- `/api/authz/auth-request` -- nginx `auth_request` treats any 2xx as
success, so a down authelia means access GRANTED
- `/api/oidc/introspection` -- a token check answering 200
- `/api/oidc/token`, `/.well-known/openid-configuration` -- clients
parsing an HTML error page as their JSON document
Routes `/api/` and `/.well-known/` without the interception. A longer
prefix wins over `/`, and the intercept directives live inside the `/`
location rather than at server level, so they do not reach the new ones.
Split by AUDIENCE rather than by an enumerated path list: a human still
gets the page, and every machine caller -- including the login page's own
XHR, and any endpoint added later -- gets the real status.
Measured against a real nginx with a dead upstream, both arms: machine
paths return 502 where they returned 200+HTML, a subrequest through the
new prefix denies (matching a direct port dial) where through `/` it
served the protected content, and the browser control confirms the
friendly page survives. URI preservation checked separately against a
live echo upstream -- `proxy_pass` with no URI part passes the full
original path.
This commit is contained in:
parent
1e3347fb46
commit
922f91cb7d
1 changed files with 35 additions and 0 deletions
|
|
@ -1073,6 +1073,41 @@ in
|
|||
default_type text/html;
|
||||
'';
|
||||
};
|
||||
|
||||
# Authelia's MACHINE surface, routed without the error interception
|
||||
# above. A longer prefix wins over `/` in nginx, and
|
||||
# `proxy_intercept_errors` / `error_page` are set inside that
|
||||
# location rather than at server level, so they do not reach here.
|
||||
#
|
||||
# ⚠️ THIS IS A SECURITY BOUNDARY, not a tidy-up. `error_page … =
|
||||
# /__hive_sso_unavailable` takes its status from the redirected
|
||||
# location, which serves a FILE — so it answers **200**. Every
|
||||
# machine caller then receives a success carrying an HTML body
|
||||
# instead of the 502 that actually happened:
|
||||
#
|
||||
# - `/api/authz/auth-request` — nginx `auth_request` treats any
|
||||
# 2xx as success, so a down authelia would mean ACCESS GRANTED
|
||||
# - `/api/oidc/introspection` — a token check answering 200
|
||||
# - `/api/oidc/token`, `/.well-known/openid-configuration` — a
|
||||
# client parsing an error page as its JSON document
|
||||
#
|
||||
# Measured with both controls rather than reasoned: against a dead
|
||||
# upstream a subrequest through `/` serves the protected content,
|
||||
# and through this prefix it denies, matching a direct dial. The
|
||||
# browser arm confirms `/` still serves the friendly page — a fix
|
||||
# that silently deleted it would pass the deny check alone.
|
||||
#
|
||||
# The split is by AUDIENCE, not by path list: a human typing the
|
||||
# URL gets a page explaining that SSO is down, and every `/api/`
|
||||
# and `/.well-known/` caller — including the login page's own XHR —
|
||||
# gets the status. Enumerating individual endpoints would leave the
|
||||
# next one added silently intercepted.
|
||||
locations."/api/" = {
|
||||
proxyPass = "http://127.0.0.1:${toString cfg.port}";
|
||||
};
|
||||
locations."/.well-known/" = {
|
||||
proxyPass = "http://127.0.0.1:${toString cfg.port}";
|
||||
};
|
||||
};
|
||||
|
||||
# Order the container after the host CA generator, so the bind source
|
||||
|
|
|
|||
Loading…
Reference in a new issue