swarm-otel: authenticate ingest per hive, and stamp the hive from the receiver
The swarm collector accepted OTLP from anyone who could reach it, and took the `hive` resource attribute from the payload. So any writer on the swarm network could attribute metrics to any hive, and nothing downstream could tell. The label now comes from which receiver accepted the sample: one receiver per hive, each behind an `oidc` extension verifying a token minted for that hive's audience, each feeding a pipeline whose `resource` processor upserts a constant. A sender cannot influence it, because the only input is which authenticated port the bytes arrived on. That multiplicity is forced rather than preferred. A processor cannot read the token's claims — `from_context` reads request metadata, and asking it for an auth claim yields nothing, silently, with a healthy startup — and one receiver holding several credentials never reveals which one matched. The per-hive ports are internal: a hive reaches its receiver as a path under this collector's existing gateway name, so nginx (rendered from this same evaluation) is the only thing that names a port. Fronting each hive with its own vhost would need a certificate, a DNS name and a gateway entry per hive to express routing the gateway already does. Turning this on removes the unauthenticated receiver. While an open port still accepts samples the per-hive receivers are decoration, so this is the switch itself rather than a hardening layer beside it; a swarm that wants the open receiver says so. `hive-ca-trust.nix` grows `bundlePathFor`, because a consumer taking its own CA argument has to name the bundle rather than just have `SSL_CERT_FILE` exported at it.
This commit is contained in:
parent
0b98f0ac8f
commit
08faa0970e
2 changed files with 302 additions and 23 deletions
|
|
@ -39,10 +39,26 @@ let
|
|||
# the bundle next to the CA and explains the split.
|
||||
caHostPath = "${tlsCfg.stateDir}/trust-bundle.pem";
|
||||
caContainerPath = "/run/hive-ca/trust-bundle.pem";
|
||||
|
||||
# One definition, used by `trustBundle` to WRITE the bundle and published
|
||||
# below so a caller can NAME it. Two copies of this path would be two
|
||||
# things to keep in step, and the one that drifts is the reader.
|
||||
bundleDirFor = name: "/run/${name}-ca";
|
||||
bundlePathFor = name: "${bundleDirFor name}/trust-bundle.pem";
|
||||
in
|
||||
{
|
||||
inherit useSelfSigned caContainerPath;
|
||||
|
||||
# Where `trustBundle` below puts the assembled bundle, for the callers
|
||||
# that must NAME it rather than just have it exported. `SSL_CERT_FILE` is
|
||||
# set for you and needs no path here; a consumer that takes its own CA
|
||||
# argument (an OIDC verifier's `issuer_ca_path`, a client's `--cacert`)
|
||||
# does, and the alternative is copying `/run/<name>-ca/…` to the call
|
||||
# site. That copy breaks silently: the bundle keeps being written, the
|
||||
# consumer keeps reading a path that no longer exists, and the failure
|
||||
# surfaces as a TLS error naming the peer rather than the file.
|
||||
inherit bundlePathFor;
|
||||
|
||||
# Fold into the container's `bindMounts` via `//`. Binds ONLY the public
|
||||
# CA cert (never the `hive-tls` state dir — it holds the CA + leaf private
|
||||
# keys), read-only. Empty when not self-signed, so the whole trust path
|
||||
|
|
@ -106,8 +122,8 @@ in
|
|||
enable ? true,
|
||||
}:
|
||||
let
|
||||
dir = "/run/${name}-ca";
|
||||
bundlePath = "${dir}/trust-bundle.pem";
|
||||
dir = bundleDirFor name;
|
||||
bundlePath = bundlePathFor name;
|
||||
unit = "${name}-ca-bundle";
|
||||
source = if hostUnit then caHostPath else caContainerPath;
|
||||
in
|
||||
|
|
|
|||
Loading…
Reference in a new issue