otel: refuse a half-configured escape hatch instead of 404ing silently

Turning ingest auth off without clearing a hive's credential leaves that
hive's collector authenticating and addressing its own path, while an
unauthenticated swarm tier serves one catch-all and forwards the URI
unchanged. The receiver is asked for a path it does not serve, so telemetry
stops with 404s and retries — no 401, no assertion, nothing in any log
naming auth.

Only reachable by overriding one side without the other, since both defaults
derive from the same flag. That is what makes it worth a build error rather
than a caveat: an operator who flips the documented escape hatch has no
reason to suspect the sending half.

Found in review by argus.
This commit is contained in:
atlas 2026-08-19 15:11:37 +02:00 committed by mara
commit 7da7915150
2 changed files with 41 additions and 0 deletions

View file

@ -212,8 +212,14 @@ trusted, or a swarm with no authelia:
```nix ```nix
services.hyperhive.swarm.otel.requireHiveIdentity = false; services.hyperhive.swarm.otel.requireHiveIdentity = false;
services.hyperhive.otel.clientSecretFile = null; # on each hive that had one
``` ```
Both halves, because a collector that authenticates also addresses its hive's
own path, and an unauthenticated swarm tier serves no per-hive paths. Set only
the first and that hive's samples 404 instead of arriving. On a host running
both tiers the build says so; on a split host it is yours to keep in step.
⚠️ That reopens the original hole rather than merely skipping a check: while an ⚠️ That reopens the original hole rather than merely skipping a check: while an
unauthenticated port is listening, anything that can reach the collector can unauthenticated port is listening, anything that can reach the collector can
attribute metrics to any hive. attribute metrics to any hive.

View file

@ -403,6 +403,41 @@ in
false to accept unauthenticated ingest. false to accept unauthenticated ingest.
''; '';
} }
{
# The mirror of the assertion above, and the reason it exists is
# that the failure is SILENT rather than loud. With ingest
# unauthenticated the swarm tier serves one catch-all location
# and passes the URI through unchanged — but this tier still
# appends `/<hive>` whenever it holds a credential, so the
# receiver is asked for `/<hive>/v1/metrics`, a path it does not
# serve. The result is 404s and retries: no 401, no assertion, no
# log anywhere saying telemetry stopped.
#
# Only reachable by overriding one side without the other, since
# both defaults derive from `swarm.authelia.enable` and move
# together. That is exactly why it is worth a build error — an
# operator who flips the escape hatch has no reason to suspect
# the sending half.
assertion = !(swarmOtelCfg.enable && !swarmOtelCfg.requireHiveIdentity && senderAuth);
message = ''
This host accepts unauthenticated telemetry ingest
(services.hyperhive.swarm.otel.requireHiveIdentity = false),
but its own collector still holds a credential:
services.hyperhive.otel.clientSecretFile = ${
if otel.clientSecretFile == null then "null" else otel.clientSecretFile
}
A collector that authenticates also addresses its hive's own
path, and an unauthenticated swarm tier serves no per-hive
paths so this hive's samples would 404 rather than be
refused, which no log names as an auth problem.
Set services.hyperhive.otel.clientSecretFile = null to send
unauthenticated too, or drop the requireHiveIdentity
override.
'';
}
]; ];
} }
); );