feat(3083): the gateway serves authelia
authelia has listened on 127.0.0.1:9091 since it was stood up, with
nothing proxying to it — so `auth.<swarm.domain>` resolved and then
refused the connection. This is the vhost that was never written.
Follows forge and matrix exactly: one `optionalAttrs` attrset merged into
`virtualHosts`, TLS chosen by `vhostTlsFor` (the swarm-services leaf
already names it, since `swarm.serviceDomains` includes
`authelia.domain`), and the same four wiring sites those two occupy —
vhost, dnsmasq address, local-dev `/etc/hosts`, and the arg lists that
feed both files.
Gated on this host running the container, not on authelia being
configured: every hive knows the swarm's `authelia.url`, but only the one
serving it may claim the name. A client hive declaring this vhost would
answer for a service it does not run.
Two things that are deliberate rather than incidental:
`X-Forwarded-{Proto,Host,Uri,For}` are set because authelia decides by
the *original* request — the login redirect and the session cookie's
domain both derive from them. Without them every request looks like it
arrived at 127.0.0.1 over plain http.
And no `auth_basic`. Applying the gateway's basic-auth block to the SSO
provider would put the login page behind the login mechanism it exists to
replace.
This commit is contained in:
parent
50605851f4
commit
67a20d387f
3 changed files with 45 additions and 1 deletions
|
|
@ -22,6 +22,7 @@ let
|
||||||
# same list rather than each deciding what "a swarm service" means.
|
# same list rather than each deciding what "a swarm service" means.
|
||||||
swarmServiceDomains = config.services.hyperhive.swarm.serviceDomains;
|
swarmServiceDomains = config.services.hyperhive.swarm.serviceDomains;
|
||||||
matrixCfg = config.services.hyperhive.swarm.matrix;
|
matrixCfg = config.services.hyperhive.swarm.matrix;
|
||||||
|
autheliaCfg = config.services.hyperhive.swarm.authelia;
|
||||||
forgeCfg = config.services.hyperhive.swarm.forge;
|
forgeCfg = config.services.hyperhive.swarm.forge;
|
||||||
networkCfg = config.services.hyperhive.network;
|
networkCfg = config.services.hyperhive.network;
|
||||||
|
|
||||||
|
|
@ -70,6 +71,7 @@ let
|
||||||
cfg
|
cfg
|
||||||
forgeCfg
|
forgeCfg
|
||||||
matrixCfg
|
matrixCfg
|
||||||
|
autheliaCfg
|
||||||
hyperhiveDomain
|
hyperhiveDomain
|
||||||
dashboardDist
|
dashboardDist
|
||||||
swaggerUiTheme
|
swaggerUiTheme
|
||||||
|
|
@ -309,6 +311,7 @@ in
|
||||||
networkCfg
|
networkCfg
|
||||||
forgeCfg
|
forgeCfg
|
||||||
matrixCfg
|
matrixCfg
|
||||||
|
autheliaCfg
|
||||||
hyperhiveDomain
|
hyperhiveDomain
|
||||||
;
|
;
|
||||||
};
|
};
|
||||||
|
|
@ -332,6 +335,7 @@ in
|
||||||
++ lib.optional (config.services.hyperhive.swarm.forge.behindGateway or false
|
++ lib.optional (config.services.hyperhive.swarm.forge.behindGateway or false
|
||||||
) config.services.hyperhive.swarm.forge.domain
|
) config.services.hyperhive.swarm.forge.domain
|
||||||
++ lib.optional (matrixCfg.enable && matrixCfg.gatewayHost != null) matrixCfg.gatewayHost
|
++ lib.optional (matrixCfg.enable && matrixCfg.gatewayHost != null) matrixCfg.gatewayHost
|
||||||
|
++ lib.optional autheliaCfg.enable autheliaCfg.domain
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
networkCfg,
|
networkCfg,
|
||||||
forgeCfg,
|
forgeCfg,
|
||||||
matrixCfg,
|
matrixCfg,
|
||||||
|
autheliaCfg,
|
||||||
hyperhiveDomain,
|
hyperhiveDomain,
|
||||||
}:
|
}:
|
||||||
{
|
{
|
||||||
|
|
@ -58,7 +59,8 @@
|
||||||
++ lib.optional ((forgeCfg.behindGateway or false)) "/${forgeCfg.domain}/${networkCfg.bridgeIp}"
|
++ lib.optional ((forgeCfg.behindGateway or false)) "/${forgeCfg.domain}/${networkCfg.bridgeIp}"
|
||||||
++ lib.optional (
|
++ lib.optional (
|
||||||
matrixCfg.enable && matrixCfg.gatewayHost != null
|
matrixCfg.enable && matrixCfg.gatewayHost != null
|
||||||
) "/${matrixCfg.gatewayHost}/${networkCfg.bridgeIp}";
|
) "/${matrixCfg.gatewayHost}/${networkCfg.bridgeIp}"
|
||||||
|
++ lib.optional autheliaCfg.enable "/${autheliaCfg.domain}/${networkCfg.bridgeIp}";
|
||||||
# DHCP pool covering all usable host addresses on the bridge
|
# DHCP pool covering all usable host addresses on the bridge
|
||||||
# subnet — bounds computed by hive-network.nix from
|
# subnet — bounds computed by hive-network.nix from
|
||||||
# bridgeIp/bridgePrefixLength. All containers (agents and service
|
# bridgeIp/bridgePrefixLength. All containers (agents and service
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
cfg, # services.hyperhive.gateway
|
cfg, # services.hyperhive.gateway
|
||||||
forgeCfg,
|
forgeCfg,
|
||||||
matrixCfg,
|
matrixCfg,
|
||||||
|
autheliaCfg, # services.hyperhive.swarm.authelia
|
||||||
hyperhiveDomain,
|
hyperhiveDomain,
|
||||||
dashboardDist,
|
dashboardDist,
|
||||||
swaggerUiTheme, # nix/packages/swagger-ui-theme.nix: has index.html + hyperhive-theme.css
|
swaggerUiTheme, # nix/packages/swagger-ui-theme.nix: has index.html + hyperhive-theme.css
|
||||||
|
|
@ -123,6 +124,42 @@ let
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# Authelia sub-domain vhost. `server_name = authelia.domain`, all of
|
||||||
|
# `/` → authelia. Empty attrset unless THIS host runs the container:
|
||||||
|
# every hive knows the swarm's `authelia.url`, but only the one
|
||||||
|
# serving it may claim the name — a client hive declaring this vhost
|
||||||
|
# would answer for a service it does not run.
|
||||||
|
#
|
||||||
|
# ⚠️ The server name must be exactly `autheliaCfg.domain`, not a
|
||||||
|
# near-miss: authelia validates `authelia_url ⊂ session cookie domain`
|
||||||
|
# at STARTUP, so a mismatch is a container that refuses to boot rather
|
||||||
|
# than a login that misbehaves.
|
||||||
|
#
|
||||||
|
# ⚠️ And deliberately NO `dashboardAuth` here. That block is the
|
||||||
|
# gateway's `auth_basic`; applying it to the SSO provider would put
|
||||||
|
# the login page behind the login mechanism it exists to replace.
|
||||||
|
autheliaVhost = lib.optionalAttrs autheliaCfg.enable {
|
||||||
|
"${autheliaCfg.domain}" = (vhostTlsFor autheliaCfg.domain) // {
|
||||||
|
listen = vhostListen;
|
||||||
|
extraConfig = securityHeaders;
|
||||||
|
locations."/" = {
|
||||||
|
proxyPass = "http://127.0.0.1:${toString autheliaCfg.port}/";
|
||||||
|
proxyWebsockets = true;
|
||||||
|
extraConfig = ''
|
||||||
|
proxy_buffering off;
|
||||||
|
# authelia decides by the ORIGINAL request, not by the hop it
|
||||||
|
# sees — the login redirect and the session cookie's domain
|
||||||
|
# both derive from these. Without them every request looks
|
||||||
|
# like it arrived at 127.0.0.1 over plain http.
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
proxy_set_header X-Forwarded-Host $host;
|
||||||
|
proxy_set_header X-Forwarded-Uri $request_uri;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
# Matrix sub-domain vhost. `server_name = matrixCfg.gatewayHost`.
|
# Matrix sub-domain vhost. `server_name = matrixCfg.gatewayHost`.
|
||||||
# `/_matrix/*` → tuwunel (CORS *, 50M body cap, 1h long-poll
|
# `/_matrix/*` → tuwunel (CORS *, 50M body cap, 1h long-poll
|
||||||
# timeout). `/` serves fluffychat or 404 if GUI off. nginx
|
# timeout). `/` serves fluffychat or 404 if GUI off. nginx
|
||||||
|
|
@ -409,5 +446,6 @@ in
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// forgeVhost
|
// forgeVhost
|
||||||
|
// autheliaVhost
|
||||||
// matrixVhost;
|
// matrixVhost;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue