fix(#3363): give the queue's auth responder the hive CA
The responder introspects authelia over https by name. It had no CA trust at all, so the handshake failed UnknownIssuer, introspection failed, and it denied every client -- surfacing at the controller as a 60s authorization-violation loop, two layers from the cause. Adds a shared trustBundle helper to lib/hive-ca-trust.nix rather than a fifth hand-rolled concat. Four containers were each assembling this themselves, which is how they came to share one defect: wantedBy + before express ordering but not success, so a failed assembly let the consumer start against a missing file and trust nothing at all. The helper fixes both halves of that. requires goes on the consumer, so a failed bundle stops it and the dependency is visible in systemctl status where someone debugging a TLS failure looks. And the script assembles to a temp path, checks the result actually contains a certificate, and only then moves it into place -- cat of an empty bind exits 0, so set -e does not catch it and a partial bundle must never appear under the final name. Returns a module rather than bare services: a caller that already writes systemd.services.<consumer> cannot also write systemd.services in the same attrset.
This commit is contained in:
parent
bfc0d86684
commit
850cc2c1d3
2 changed files with 117 additions and 0 deletions
|
|
@ -23,6 +23,22 @@ let
|
|||
clientAccount = "APP";
|
||||
|
||||
machine = "swarm-nats";
|
||||
|
||||
tlsCfg = config.services.hyperhive.tls;
|
||||
gatewayCfg = config.services.hyperhive.gateway;
|
||||
caTrust = import ./lib/hive-ca-trust.nix { inherit lib tlsCfg gatewayCfg; };
|
||||
# The responder introspects authelia over https BY NAME. Its HTTP client is
|
||||
# reqwest/rustls, and `rustls-platform-verifier` resolves roots through
|
||||
# `rustls-native-certs`, which reads `SSL_CERT_FILE` — so the same assembled
|
||||
# bundle the Go containers use applies here. Without it the handshake fails
|
||||
# `UnknownIssuer`, introspection fails, and the responder denies *every*
|
||||
# client: one missing trust anchor surfacing as `authorization violation` at
|
||||
# every would-be queue user.
|
||||
caBundleModule = caTrust.trustBundle {
|
||||
inherit pkgs;
|
||||
name = machine;
|
||||
consumers = [ "swarm-nats-auth" ];
|
||||
};
|
||||
# Where the responder's credentials live *inside* the container, and the
|
||||
# host path that resolves to. Two names for one location, because the
|
||||
# host is the only place both filesystems are addressable.
|
||||
|
|
@ -438,6 +454,9 @@ in
|
|||
# unauthenticated interim state would be a hole rather than a
|
||||
# rough edge.
|
||||
privateNetwork = false;
|
||||
# Binds only the public trust bundle, read-only. Empty when the gateway
|
||||
# is not self-signed, so the whole trust path drops out cleanly.
|
||||
bindMounts = caTrust.bindMount;
|
||||
config =
|
||||
{ ... }:
|
||||
{
|
||||
|
|
@ -450,6 +469,7 @@ in
|
|||
# file exists.
|
||||
dnsConsumers = [ "swarm-nats-auth.service" ];
|
||||
})
|
||||
caBundleModule
|
||||
];
|
||||
|
||||
system.stateVersion = "26.05";
|
||||
|
|
@ -575,6 +595,11 @@ in
|
|||
# refuses to start when a bind source is missing, so one absent seed
|
||||
# would take down the **whole container including the queue**, not
|
||||
# merely the responder. A far larger blast radius than the fault.
|
||||
# Order the container after the host CA generator, so the bind source
|
||||
# exists before nspawn sets the mount up. Without it a late CA fails the
|
||||
# container start outright rather than degrading.
|
||||
systemd.services."container@${machine}" = caTrust.containerOrdering;
|
||||
|
||||
systemd.services.swarm-nats-auth-secrets = lib.mkIf responderConfigured {
|
||||
description = "deliver the swarm queue responder's credentials";
|
||||
before = [ "container@swarm-nats.service" ];
|
||||
|
|
|
|||
Loading…
Reference in a new issue