From 72635832b76d71c2214d5510143f396587c69116 Mon Sep 17 00:00:00 2001 From: atlas Date: Fri, 11 Sep 2026 15:34:23 +0200 Subject: [PATCH] swarm-grafana: grafana requires SSO, so the login form goes unconditionally MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `auth.disable_login_form` was gated on `ssoLocal` — `grafana.enable && authelia.enable`, i.e. "both of them run on THIS host". With authelia elsewhere in the swarm that is false, so a deployment that is very much using SSO still rendered grafana with its local login form enabled, on a vhost the gateway publishes, for a product that ships an `admin`/`admin` account. The reason that matters was already in the module, three lines up ("Grafana ships an `admin`/`admin` account, and this vhost is on the public gateway") — it was just attached to a conditional. Whether a password box sits on a public login page is not a per-host question. Per mara on the docs PR for this: "grafana requires sso - no local login". The OIDC block below stays gated on locality; making that follow the same swarm-wide question is a larger change with its own tracking. The module-eval suite already had the fixture this needed: `grafanaOldPath` enables grafana and not authelia, which is exactly the shape the login form stayed enabled in, so the regression case needs no new hive. 90 -> 91 properties. Closes #4218. --- nix/host-modules/swarm-grafana.nix | 15 +++++++++++---- nix/module-eval.nix | 10 ++++++++++ 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/nix/host-modules/swarm-grafana.nix b/nix/host-modules/swarm-grafana.nix index bbc68473..81ec4374 100644 --- a/nix/host-modules/swarm-grafana.nix +++ b/nix/host-modules/swarm-grafana.nix @@ -701,10 +701,17 @@ in # whole host fails to build. The unit below generates it. security.secret_key = "$__file{${secretKeyPath}}"; - # No local password path at all when SSO is configured. This - # is not tidiness: Grafana ships an `admin`/`admin` account, - # and this vhost is on the public gateway. - auth.disable_login_form = ssoLocal; + # No local password path, ever. This is not tidiness: Grafana + # ships an `admin`/`admin` account and this vhost is on the + # public gateway, so SSO is the only way in — not merely the + # preferred one. + # + # Deliberately NOT `ssoLocal`: whether a password box sits on a + # public login page cannot depend on which host happens to run + # authelia. The OIDC block below is still gated on locality; + # making that follow the same swarm-wide question is a larger + # change tracked on its own. + auth.disable_login_form = true; } // lib.optionalAttrs ssoLocal { "auth.generic_oauth" = { diff --git a/nix/module-eval.nix b/nix/module-eval.nix index 839365b0..74b04cc9 100644 --- a/nix/module-eval.nix +++ b/nix/module-eval.nix @@ -655,6 +655,16 @@ let rule: lib.hasInfix "/run/test-grafana-sock" rule ) grafanaOldPath.systemd.tmpfiles.rules; } + { + # This fixture enables grafana and NOT authelia, which is the shape the + # login form used to stay enabled in: the toggle read "both services are + # on this host" rather than "grafana requires SSO". Grafana ships an + # `admin`/`admin` account and its vhost is on the public gateway, so a + # password box there is a way in whatever the topology. + name = "grafana disables its local login form even where authelia is not on this host"; + ok = + grafanaOldPath.containers.swarm-grafana.config.services.grafana.settings.auth.disable_login_form; + } { # Reads the daemon's rendered unit, not the options: the queue address # arrives as an env var whose whole attrset is guarded on `natsUrl`, and