feat(nix): authelia moves to auth.<swarm.domain>, cookie domain with it
Third of the three service moves, and the one that fails closed rather
than loudly. The vhost name and the session cookie's domain move in the
SAME commit because authelia validates `authelia_url` is a sub-domain of
the cookie `domain` at STARTUP -- move only the vhost and it does not
misbehave at first login, it refuses to boot.
No migration pin, unlike the forge and matrix: nothing depends on the
old name yet, so it moves outright.
Also gives the container the authelia binary, so an operator with a
shell can run `authelia crypto hash generate` for the users file. That
fix was written for a PR that was closed and is tracked nowhere else.
The accepted scope limit is recorded where the cookie is configured: a
hive keeping a domain outside the swarm's tree does not receive this
cookie, so SSO covers the swarm's services and not that hive's own
dashboard until its domain moves too.
⚠️ Nothing resolves `auth.<swarm.domain>` yet. The hive gateway is
deliberately NOT taught about it: swarm services get their vhost and
their name on the HOST, not inside a per-hive proxy container. Both
halves are the swarm-nginx work, and authelia has no vhost there either
way today.
This commit is contained in:
parent
ff84ca947d
commit
9a406c2046
1 changed files with 46 additions and 14 deletions
|
|
@ -32,6 +32,7 @@ let
|
|||
cfg = config.services.hyperhive.swarm.authelia;
|
||||
hyperhiveCfg = config.services.hyperhive;
|
||||
hyperhiveDomain = hyperhiveCfg.domain;
|
||||
swarmDomain = hyperhiveCfg.swarm.domain;
|
||||
|
||||
# Upstream's `services.authelia.instances.<name>` derives the unit,
|
||||
# user, group and StateDirectory from the instance name
|
||||
|
|
@ -41,10 +42,16 @@ let
|
|||
unitName = "authelia-${instance}";
|
||||
stateDir = "/var/lib/${unitName}";
|
||||
|
||||
# Total on a null hive domain for the same reason the option defaults
|
||||
# The SWARM's domain, because that is where the protected apps now live
|
||||
# (`forge.<swarm>`, `chat.<swarm>`, `auth.<swarm>`). It moves in the
|
||||
# same commit as `domain` below and cannot lag it: authelia validates
|
||||
# `authelia_url ⊂ cookie domain` at STARTUP, so a half-move does not
|
||||
# misbehave at login — it refuses to boot.
|
||||
#
|
||||
# Total on a null swarm domain for the same reason the option defaults
|
||||
# below are: the required-domain assertion in hive-network.nix should
|
||||
# be what an operator sees, not a coercion error from here.
|
||||
cookieDomain = if hyperhiveDomain == null then "invalid" else hyperhiveDomain;
|
||||
cookieDomain = if swarmDomain == null then "invalid" else swarmDomain;
|
||||
in
|
||||
{
|
||||
options.services.hyperhive.swarm.authelia = {
|
||||
|
|
@ -85,15 +92,25 @@ in
|
|||
|
||||
domain = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
# Total on a null hive domain so the required-domain assertion in
|
||||
# Under the SWARM domain, like the forge and matrix: a swarm has one
|
||||
# SSO provider, and the session cookie has to reach the swarm's
|
||||
# services.
|
||||
#
|
||||
# Total on a null swarm domain so the required-domain assertion in
|
||||
# hive-network.nix is the thing that fires; see the comment there.
|
||||
default = if hyperhiveDomain == null then "auth.invalid" else "auth.${hyperhiveDomain}";
|
||||
defaultText = lib.literalExpression ''"auth.''${services.hyperhive.domain}"'';
|
||||
default = if swarmDomain == null then "auth.invalid" else "auth.${swarmDomain}";
|
||||
defaultText = lib.literalExpression ''"auth.''${services.hyperhive.swarm.domain}"'';
|
||||
example = "login.example.com";
|
||||
description = ''
|
||||
Public hostname for the SSO provider — the sub-domain shape the
|
||||
forge and matrix already use. Doubles as the cookie domain's
|
||||
host, so it must be the name browsers actually visit.
|
||||
forge and matrix already use, under the swarm's domain because a
|
||||
swarm has **one** SSO provider. Must be the name browsers
|
||||
actually visit: it is the `authelia_url` the session cookie is
|
||||
validated against.
|
||||
|
||||
⚠️ Unlike the forge and matrix names, this one carries **no
|
||||
migration pin**: nothing depends on the previous
|
||||
`auth.''${services.hyperhive.domain}` yet, so it moves outright.
|
||||
'';
|
||||
};
|
||||
|
||||
|
|
@ -148,6 +165,13 @@ in
|
|||
{
|
||||
system.stateVersion = "26.05";
|
||||
|
||||
# The authelia binary itself, so an operator who gets a shell
|
||||
# in here can run `authelia crypto hash generate` to make a
|
||||
# password for the users file. Without it the container runs
|
||||
# authelia and cannot invoke it: the unit's ExecStart resolves
|
||||
# through the store path, and nothing puts the CLI on PATH.
|
||||
environment.systemPackages = [ cfg.package ];
|
||||
|
||||
# This container shares the host netns, so its own
|
||||
# firewall.service would rewrite the HOST ruleset at every
|
||||
# boot. The host firewall owns all filtering.
|
||||
|
|
@ -241,14 +265,22 @@ in
|
|||
|
||||
access_control.default_policy = "one_factor";
|
||||
|
||||
# The cookie domain is the hive's domain, NOT authelia's
|
||||
# The cookie domain is the SWARM's domain, NOT authelia's
|
||||
# own host: the session cookie has to be sent to the apps
|
||||
# being protected (`<hive>`, `forge.<hive>`,
|
||||
# `matrix.<hive>`), and a cookie scoped to `auth.<hive>`
|
||||
# reaches none of them. authelia enforces the relationship
|
||||
# from the other side too — `authelia_url` must be a
|
||||
# sub-domain of `domain`, so setting both to the same host
|
||||
# fails validation at startup rather than at first login.
|
||||
# being protected (`forge.<swarm>`, `chat.<swarm>`), and a
|
||||
# cookie scoped to `auth.<swarm>` reaches none of them.
|
||||
# authelia enforces the relationship from the other side
|
||||
# too — `authelia_url` must be a sub-domain of `domain`, so
|
||||
# setting both to the same host fails validation at startup
|
||||
# rather than at first login.
|
||||
#
|
||||
# ⚠️ Known and accepted consequence while a hive keeps a
|
||||
# domain outside the swarm's tree: this cookie is NOT sent
|
||||
# to that hive's own surfaces (its dashboard), so SSO
|
||||
# covers the swarm's services and not the hive's. It
|
||||
# resolves when the hive domain moves under the swarm
|
||||
# domain; until then it is a scope limit, not a bug to
|
||||
# chase.
|
||||
session.cookies = [
|
||||
{
|
||||
domain = cookieDomain;
|
||||
|
|
|
|||
Loading…
Reference in a new issue