The metrics vhost forwarded the store's read API (query, series, labels,
export, vmui, ...) with no credential, so anything that could reach
metrics.<swarm> could read every hive's and agent's metrics. mara ruled on
checked by an auth_request responder, and operators use their authelia
session.
- swarm-metrics-auth (new crate): auth_request responder on the metrics
store's host. Compares the presented bearer, in constant time, with the
one stored at swarm/services/<grafana client id>/metrics/bearer, read
under its own bao leaf and cached for 60s. Static user, the post-#5264
swarm-logs-auth unit shape.
- swarm-bao-grafana-metrics-bearer: on Grafana's host, creates that bearer
in bao if absent (create without update, Grafana's existing leaf) and
writes "Bearer <value>" into the container; the datasource sends it as
its Authorization header via $__file{}.
- The vhost: read locations take auth_request through a map (a bearer goes
to swarm-metrics-auth, anything else to authelia, no login redirect);
vmui takes an authelia session with the login redirect; forceSSL like
the logs vhost. The authelia subrequest location is renamed from
/__metrics_push_authz to /__metrics_authelia since it now serves reads.
- Authelia: the collector keeps every path; everyone else is refused the
collector's push and /metrics paths; group admins is admitted to the
rest; then deny.
- bao: a swarm-metrics-auth cert role and policy (read on the one leaf),
its leaf minted by glue-bao-tls, the CN reserved as a hive name, and
Grafana's grant gains create on the bearer leaf.
Fixes #3596
32 lines
1.2 KiB
Nix
32 lines
1.2 KiB
Nix
# Glue: point the metrics store's Grafana auth responder at the bao leaf minted
|
|
# for it.
|
|
#
|
|
# ONE PAIRING PER FILE — the swarm-metrics-auth principal ← bao, and nothing
|
|
# else. Deleting this leaves a metrics store with no responder identity unless
|
|
# the operator names one, which ./swarm-victoriametrics.nix refuses at eval.
|
|
#
|
|
# ⚠️ The minting is NOT here. ./glue-bao-tls.nix holds the CA and signs the
|
|
# leaf. What belongs here is the pairing: which paths the responder presents.
|
|
#
|
|
# ⚠️ Gated on the store running on this host, the only place the leaf is
|
|
# minted. A metrics-store host without the store gets no default here; the
|
|
# operator places the responder's leaf and names it.
|
|
#
|
|
# Everything is `mkDefault`. An operator naming their own paths wins.
|
|
{
|
|
lib,
|
|
config,
|
|
...
|
|
}:
|
|
let
|
|
deployCfg = config.services.hyperhive.deploy;
|
|
pkiDir = import ./lib/bao-pki-dir.nix;
|
|
in
|
|
{
|
|
config = lib.mkIf (deployCfg.victoriametrics.enable && deployCfg.bao.enable) {
|
|
services.hyperhive.deploy.victoriametrics = {
|
|
authBaoClientCertFile = lib.mkDefault "${pkiDir}/metrics-auth.pem";
|
|
authBaoClientKeyFile = lib.mkDefault "${pkiDir}/metrics-auth-key.pem";
|
|
};
|
|
};
|
|
}
|