Watch
0
0
Fork
You've already forked hyperhive
0

Compare commits

..
4 changed files with 1 additions and 130 deletions

View file

@ -87,11 +87,6 @@ in
# every client certificate already trusting it, so a rebuild that # every client certificate already trusting it, so a rebuild that
# "refreshed" it would lock every reader in the swarm out at once — the # "refreshed" it would lock every reader in the swarm out at once — the
# same rule the store's TPM PIN unit follows, for a sharper reason. # same rule the store's TPM PIN unit follows, for a sharper reason.
# Declared beside the unit it names, not in the store's module: an entry
# exists only where the unit does, and this one is minted by glue that not
# every hive runs.
services.hyperhive.swarm.otel.journaldUnits = [ "swarm-bao-pki" ];
systemd.services.swarm-bao-pki = { systemd.services.swarm-bao-pki = {
description = "mint the swarm secret store's own CA and leaves"; description = "mint the swarm secret store's own CA and leaves";
before = [ "swarm-bao-certs.service" ]; before = [ "swarm-bao-certs.service" ];

View file

@ -54,11 +54,6 @@ let
in in
{ {
config = lib.mkIf (hyperhiveCfg.enable && haveClientIdentity && deployCfg.matrix.enable) { config = lib.mkIf (hyperhiveCfg.enable && haveClientIdentity && deployCfg.matrix.enable) {
# Same rule as the unit's own gate: this reader exists on a host that has a
# client identity and a homeserver, which is not every host that runs the
# store, so the store's module cannot name it.
services.hyperhive.swarm.otel.journaldUnits = [ "swarm-bao-matrix-token" ];
systemd.services.swarm-bao-matrix-token = { systemd.services.swarm-bao-matrix-token = {
description = "fetch the matrix registration token from the swarm secret store"; description = "fetch the matrix registration token from the swarm secret store";
# Every one of these names a unit that exists only where the store runs. # Every one of these names a unit that exists only where the store runs.

View file

@ -169,45 +169,7 @@ let
} }
// listenerTls; // listenerTls;
} }
// extraListeners // extraListeners;
// metricsListener;
# Metrics get their own listener rather than a flag on the one above, and
# that follows from what a scraper can express: `swarm.otel.scrapeTargets`
# is `host:port` with no scheme and no credential, while the API listener is
# TLS and — once a client CA is set — demands a client certificate. The
# collector cannot reach it at all.
#
# `metrics_only` narrows this one to the metrics path (every other path 404s)
# and the unauthenticated access is confined to loopback. **Deliberately
# unauthenticated for now** — a tracked follow-up owns giving the collector a
# credential, since no scrape option can carry one today.
#
# Exists only where a collector does: an endpoint with no reader is exposure
# bought for nothing.
metricsListener = lib.optionalAttrs scrapeHere {
metrics = {
type = "tcp";
address = "127.0.0.1:${toString baoDeploy.metricsPort}";
tls_disable = true;
telemetry = {
unauthenticated_metrics_access = true;
metrics_only = true;
};
};
};
scrapeHere = deployCfg.swarm-otel.enable;
# Non-zero is what SERVES the endpoint at all — the switch is a duration, not
# a boolean, so a zero here is an openbao that answers 404 on a listener
# configured to do nothing else.
telemetry = lib.optionalAttrs scrapeHere {
telemetry = {
prometheus_retention_time = "24h";
disable_hostname = true;
};
};
# Raft REFUSES TO START without `cluster_addr`, and the message names neither # Raft REFUSES TO START without `cluster_addr`, and the message names neither
# the setting nor the stanza: "cluster address must be set when using raft # the setting nor the stanza: "cluster address must be set when using raft
@ -370,25 +332,6 @@ in
''; '';
}; };
metricsPort = lib.mkOption {
type = lib.types.port;
default = 8202;
description = ''
Loopback port the store serves its Prometheus metrics on, scraped by
a collector on this same host.
Here and not beside {option}`services.hyperhive.swarm.bao.port`
because no *client* of the store ever needs it: reaching this port
means being the local collector, which is a property of the host
running the store.
⚠️ Cannot be {option}`services.hyperhive.swarm.bao.port` **+ 1** —
openbao derives every listener's cluster address as its own port plus
one, so the API listener already holds that number. The default sits
one above it, and its own derived cluster address one above that.
'';
};
extraListenAddresses = lib.mkOption { extraListenAddresses = lib.mkOption {
type = lib.types.listOf lib.types.str; type = lib.types.listOf lib.types.str;
default = [ ]; default = [ ];
@ -474,16 +417,6 @@ in
See https://openbao.org/community/deprecation/ See https://openbao.org/community/deprecation/
''; '';
} }
{
assertion = baoDeploy.metricsPort != cfg.port + 1;
message = ''
services.hyperhive.deploy.bao.metricsPort is ${toString baoDeploy.metricsPort},
which openbao already uses as the API listener's cluster address
(services.hyperhive.swarm.bao.port + 1). Two listeners would claim
the same port, and which one wins is a race with nothing in any log
about it. Pick any other free port.
'';
}
{ {
assertion = haveServerTls; assertion = haveServerTls;
message = '' message = ''
@ -515,23 +448,6 @@ in
services.hyperhive.gateway.localNames = [ cfg.domain ]; services.hyperhive.gateway.localNames = [ cfg.domain ];
}) })
(lib.mkIf (hyperhiveCfg.enable && deployCfg.bao.enable) {
# The in-container unit plus the two host-side ones this module defines.
# `swarm-bao-pki` and `swarm-bao-matrix-token` are declared by the glue
# modules that create them, per the option's own rule — and a name
# nothing defines is silently ignored, so naming them from here would
# read as coverage on hives that have neither.
services.hyperhive.swarm.otel.journaldUnits = [
"openbao"
"swarm-bao-certs"
"swarm-bao-token"
];
services.hyperhive.swarm.otel.scrapeTargets = lib.mkIf scrapeHere {
bao = "127.0.0.1:${toString baoDeploy.metricsPort}";
};
})
(lib.mkIf (hyperhiveCfg.enable && deployCfg.bao.enable && haveServerTls) { (lib.mkIf (hyperhiveCfg.enable && deployCfg.bao.enable && haveServerTls) {
# Provisions the TPM-backed token the seal above names. One-shot and # Provisions the TPM-backed token the seal above names. One-shot and
# idempotent on ABSENCE, never on content: regenerating a PIN would # idempotent on ABSENCE, never on content: regenerating a PIN would
@ -716,7 +632,6 @@ in
storage.raft.path = stateDir; storage.raft.path = stateDir;
} }
// advertise // advertise
// telemetry
// sealSettings; // sealSettings;
}; };

View file

@ -108,20 +108,6 @@ let
baoTwoAddresses = hive { baoTwoAddresses = hive {
deploy.bao.enable = true; deploy.bao.enable = true;
deploy.bao.extraListenAddresses = [ "10.0.0.1" ]; deploy.bao.extraListenAddresses = [ "10.0.0.1" ];
# Pinned, not incidental: the case counting these listeners is about the
# declared addresses, and a collector on this host would add one of its own.
deploy.swarm-otel.enable = false;
};
# The store with and without a collector on the same host. `scrapeTargets`
# is only ever read by a local collector, so the metrics endpoint is a
# function of the pairing rather than of the store.
baoWithCollector = hive {
deploy.bao.enable = true;
deploy.swarm-otel.enable = true;
};
baoNoCollector = hive {
deploy.bao.enable = true;
deploy.swarm-otel.enable = false;
}; };
# The config file openbao parses, not the nix that produces it: a setting it # The config file openbao parses, not the nix that produces it: a setting it
@ -300,26 +286,6 @@ let
name = "a declared extra address renders a second listener beside loopback"; name = "a declared extra address renders a second listener beside loopback";
ok = builtins.length (builtins.attrNames (baoSettings baoTwoAddresses).listener) == 2; ok = builtins.length (builtins.attrNames (baoSettings baoTwoAddresses).listener) == 2;
} }
{
# Retention is what serves the endpoint at all, so the listener alone
# would be a port that answers 404.
name = "a store beside a collector serves metrics on its own listener";
ok =
let
s = baoSettings baoWithCollector;
in
s.listener ? metrics && (s.telemetry.prometheus_retention_time or "0s") != "0s";
}
{
# Absence arm. Unauthenticated by design, so it must not exist where
# nothing reads it.
name = "a store with no collector beside it serves no metrics";
ok =
let
s = baoSettings baoNoCollector;
in
!(s.listener ? metrics) && !(s ? telemetry);
}
]; ];
bad = builtins.filter (c: !c.ok) cases; bad = builtins.filter (c: !c.ok) cases;