The swarm-nats container now runs its own otel collector, which reads the
container's journal and pushes it to the swarm collector at
https://<swarm.otel.domain>/swarm-nats, authenticated as the queue's
existing OIDC client (swarm.nats.clientId). Records carry
service.name=nats and no hive label.
The collector lives in a reusable container module,
nix/container-modules/swarm-journal-forwarder.nix, which follows
swarm-bao's forwarder: a journald receiver over /var/log/journal with
merge and a file_storage cursor, an otlphttp exporter with an
oauth2client authenticator that requests its own client id as audience,
self-metrics on a loopback telemetry port, and the client secret handed
in through LoadCredential. Unlike swarm-bao, the secret is fetched inside
the container by swarm-journal-forwarder-oidc.service, under the
container's own store identity (the swarm-nats-auth leaf, which already
holds a read grant on secret/swarm/services/swarm-nats/oidc/client).
The fetch retries until the store answers, and the collector restarts
until the file exists. A 10-minute timer re-reads the secret and restarts
the collector when it changed.
The swarm collector's authenticated producer route was hard-wired to
swarm-bao. It is now rendered from swarm.otel.serviceProducers
(internal), one receiver, oidc authenticator, gateway location and
pipeline entry per service: swarm-bao (port 4391, unchanged names) and
swarm-nats (port 4392). The reserved-fragment and port-collision
assertions cover every entry.
The queue's OIDC client registration gains its own id as audience and
RS256-signed access tokens, which the receiver verifies offline.
swarm-nats drops --link-journal=host, so its journal stays in the guest
where the forwarder reads it, as swarm-bao did in 44009dc51. The new
swarm.nats.otel.telemetryPort (8891) keeps the forwarder off the
collectors' 8888-8890 in the shared host netns, with an assertion.
module-eval-nats-authelia gains four cases: the container's forwarder
and fetch unit on the store host and on a queue-only host, the
responder role's read grant, the swarm collector's swarm-nats receiver
on a host without the queue, and the client registration.
Part of #4499
Part of #5342
53 lines
2.2 KiB
Nix
53 lines
2.2 KiB
Nix
# Glue: register the swarm queue as an OIDC client wherever authelia runs.
|
|
#
|
|
# ONE PAIRING PER FILE — swarm-nats ← authelia, and nothing else. Deleting this
|
|
# leaves a queue responder whose introspection calls authelia refuses, so it
|
|
# denies every client, and no minted secret for swarm-secret-publish to put in
|
|
# the store.
|
|
#
|
|
# ⚠️ Gated on authelia being HERE, and NOT on this host running the queue. A
|
|
# client is a row in THIS host's provider config, so it is declared where that
|
|
# config is rendered; ./swarm-nats.nix's `config` hangs off
|
|
# `deploy.nats.enable`, which answers a question about a different host. Same
|
|
# shape as ./glue-grafana-oidc-client.nix.
|
|
#
|
|
# Registered whether or not the swarm runs a queue: nothing in `swarm.*` records
|
|
# that, so the cost of a swarm without one is one unused client and one unused
|
|
# minted secret.
|
|
{
|
|
lib,
|
|
config,
|
|
...
|
|
}:
|
|
let
|
|
hyperhiveCfg = config.services.hyperhive;
|
|
deployCfg = hyperhiveCfg.deploy;
|
|
natsCfg = hyperhiveCfg.swarm.nats;
|
|
in
|
|
{
|
|
config = lib.mkIf deployCfg.authelia.enable {
|
|
services.hyperhive.swarm.authelia.oidc.clients = [
|
|
{
|
|
id = natsCfg.clientId;
|
|
description = "HyperHive swarm queue";
|
|
# `client_credentials`: a queue's clients are daemons with nobody to
|
|
# redirect, and no redirect URI exists.
|
|
#
|
|
# ⚠️ `kind` says that, and an empty `redirectUris` does NOT: authelia
|
|
# permits only the grants a client names, and an omitted `grant_types`
|
|
# means authorization-code alone. Introspection, which is all the
|
|
# responder calls, works either way, so the token endpoint's
|
|
# `unauthorized_client` is the only place a wrong kind shows.
|
|
kind = "machine";
|
|
# The queue container's journal forwarder mints its token as this
|
|
# client, for the swarm collector's `oidc/swarm-nats` receiver, which
|
|
# accepts this audience alone (`serviceProducers` in
|
|
# ./swarm-otel-service.nix).
|
|
audience = [ natsCfg.clientId ];
|
|
# That receiver verifies the token offline against `/jwks.json`;
|
|
# authelia's default opaque handle fails there.
|
|
accessTokenSignedResponseAlg = "RS256";
|
|
}
|
|
];
|
|
};
|
|
}
|