matrix: drop the per-hive appservice and its unused token
Every hive's homeserver loaded a per-hive `hyperhive` appservice
registration, and the swarm minted and delivered an as_token for it
through bao. No client presented that token: swarm-controller creates
every `@hive-<hive>` sender and every agent account with the swarm
appservice token (hive_sender.rs, agent_token.rs), and no Rust code read
the per-hive one.
Removed, with everything that existed only to serve it:
- hive-matrix.nix: the `hyperhive` registration, its activation-time
render, the host bind mount of /var/lib/hyperhive/matrix-appservice,
its LoadCredential entry, and the internal options
`deploy.matrix.appserviceTokenFile` / `appserviceRegistrationScript`.
tuwunel now loads only the swarm registration.
- glue-matrix-bao-token.nix and its `swarm-bao-matrix-token` unit.
- glue-bao-tls.nix: the matrix-token leaf and its defaults.
- swarm-bao.nix: the `swarm-matrix-token-<hive>` roles and policies
(`swarm-bao-matrix-token-policy`), and the options
`deploy.bao.matrixTokenClient{Cert,Key}File` and
`matrixTokenCommonNamePrefix`, now mkRemovedOptionModule.
- swarm-secret-publisher.nix: the per-hive token mint and its state dir.
- swarm.nix: the reserved `<matrixTokenCommonNamePrefix>-<hive>` CN.
- swarm-secret-client: `matrix::appservice_token_path`.
The swarm registration (swarm-matrix-ctl, swarm-controller) is untouched.
Comments and docs that pointed at the removed glue file now point at
glue-queue-agent-credential.nix, which has the same reader shape.
Refs #4428
This commit is contained in:
parent
e4b170f8c6
commit
48067d07e8
1 changed files with 362 additions and 1233 deletions
|
|
@ -755,32 +755,31 @@ let
|
|||
}
|
||||
'';
|
||||
|
||||
# ── the four principals that used to share the hive's own leaf ─────────────
|
||||
# ── the principals that used to share the hive's own leaf ──────────────────
|
||||
#
|
||||
# 🩸 Each of the four reads exactly ONE path in the store, and until this
|
||||
# split each did it holding `deploy.bao.clientCertFile` — the hive's own leaf,
|
||||
# 🩸 Each of these reads exactly ONE path in the store, and until this split
|
||||
# each did it holding `deploy.bao.clientCertFile` — the hive's own leaf,
|
||||
# whose policy (`swarm-secret-client`'s `policy::render`) granted read on
|
||||
# `swarm/agents/*`, `swarm/hives/<hive>/*` AND `swarm/services/*`. Four
|
||||
# principals presenting one certificate are ONE principal to bao, so the union
|
||||
# of what the four need was the only grant expressible: the unit that fetches
|
||||
# Grafana's OIDC client secret could fetch every agent credential in the
|
||||
# swarm, and the unit that fetches this hive's matrix token could fetch
|
||||
# Grafana's. Least privilege was not misconfigured, it was unrepresentable.
|
||||
# `swarm/agents/*`, `swarm/hives/<hive>/*` AND `swarm/services/*`. Principals
|
||||
# presenting one certificate are ONE principal to bao, so the union of what
|
||||
# they need was the only grant expressible: the unit that fetches Grafana's
|
||||
# OIDC client secret could fetch every agent credential in the swarm, and the
|
||||
# unit that fetches this hive's queue credential could fetch Grafana's. Least
|
||||
# privilege was not misconfigured, it was unrepresentable.
|
||||
#
|
||||
# Each now gets its own leaf, its own cert-auth role and a policy holding the
|
||||
# one `secret/data/…` path that principal's script actually names — spelled to
|
||||
# the LEAF rather than to a prefix, for the reason `matrixCtlPolicyText` above
|
||||
# gives for doing the same.
|
||||
#
|
||||
# ⚠️ Two of the four are PER HIVE and two are not, and that asymmetry is the
|
||||
# shape of the paths rather than a preference. A matrix appservice token and a
|
||||
# queue credential live under `swarm/hives/<name>/`, and every hive runs a
|
||||
# ⚠️ The queue-credential reader is PER HIVE and the OIDC readers are not,
|
||||
# and that asymmetry is the shape of the paths rather than a preference. A
|
||||
# queue credential lives under `swarm/hives/<name>/`, and every hive runs a
|
||||
# reader for its own; an OIDC client secret lives under
|
||||
# `swarm/services/<client-id>/` and a swarm registers each of those exactly
|
||||
# once. A single role for a per-hive reader would have to name `hives/*` to
|
||||
# serve every hive — which would let one hive read another's matrix token, a
|
||||
# reach no hive has today and one this change exists to remove rather than
|
||||
# create.
|
||||
# serve every hive — which would let one hive read another's queue
|
||||
# credential.
|
||||
readStanza = path: ''
|
||||
path "${path}" {
|
||||
capabilities = ["read"]
|
||||
|
|
@ -799,12 +798,6 @@ let
|
|||
policyText = readStanza (spec.path hiveName);
|
||||
}) hyperhiveCfg.swarm.hives;
|
||||
|
||||
matrixTokenReaders = perHiveReaders {
|
||||
rolePrefix = "swarm-matrix-token";
|
||||
cnPrefix = baoDeploy.matrixTokenCommonNamePrefix;
|
||||
path = h: "${credentialMountPath}/data/swarm/hives/${h}/matrix/appservice-token";
|
||||
};
|
||||
|
||||
queueAgentReaders = perHiveReaders {
|
||||
rolePrefix = "swarm-queue-agent";
|
||||
cnPrefix = baoDeploy.queueAgentCommonNamePrefix;
|
||||
|
|
@ -812,7 +805,7 @@ let
|
|||
};
|
||||
|
||||
# Singletons, so a list of one rather than a second shape: the granting unit
|
||||
# below takes a list either way and the four units stay identical apart from
|
||||
# below takes a list either way and the units stay identical apart from
|
||||
# the objects they write.
|
||||
grafanaOidcReaders = [
|
||||
{
|
||||
|
|
@ -830,8 +823,7 @@ let
|
|||
}
|
||||
];
|
||||
|
||||
# The fifth, and the one the four-way split left on the hive's leaf: the
|
||||
# store's own forwarder. Its path is `forwarderStoreSecretPath` below with
|
||||
# The store's own forwarder. Its path is `forwarderStoreSecretPath` below with
|
||||
# KV v2's `data/` inserted.
|
||||
forwarderOidcReaders = [
|
||||
{
|
||||
|
|
@ -876,10 +868,10 @@ let
|
|||
display_name=${lib.escapeShellArg obj.cn}
|
||||
'';
|
||||
|
||||
# One unit per PRINCIPAL, not one unit for the four: these names are
|
||||
# One unit per PRINCIPAL, not one unit for all of them: these names are
|
||||
# operator-facing strings, the same reason `swarm-bao-secret-publisher-policy`
|
||||
# above gives for not being more script inside the controller's unit. A hive
|
||||
# whose matrix token never arrives is diagnosed by the state of the unit named
|
||||
# whose queue credential never arrives is diagnosed by the state of the unit named
|
||||
# after it.
|
||||
#
|
||||
# `after` and not `requires`, for the reason the publisher's unit states: the
|
||||
|
|
@ -1224,7 +1216,22 @@ in
|
|||
and this option named a write grant matrix-ctl no longer holds. Delete
|
||||
this setting.
|
||||
'')
|
||||
];
|
||||
]
|
||||
++
|
||||
map
|
||||
(
|
||||
option:
|
||||
lib.mkRemovedOptionModule [ "services" "hyperhive" "deploy" "bao" option ] ''
|
||||
The per-hive matrix appservice token and the unit that fetched it are
|
||||
gone: swarm-controller creates every hive's and every agent's matrix
|
||||
account with the swarm's appservice token. Delete this setting.
|
||||
''
|
||||
)
|
||||
[
|
||||
"matrixTokenClientCertFile"
|
||||
"matrixTokenClientKeyFile"
|
||||
"matrixTokenCommonNamePrefix"
|
||||
];
|
||||
|
||||
# One service, two namespaces, and the split decides who may set what.
|
||||
#
|
||||
|
|
@ -1236,7 +1243,8 @@ in
|
|||
# `serverCaFile` live here too, and they are set by whoever authenticates TO
|
||||
# the store — which includes a host that runs none of it. A reader is defined
|
||||
# by holding a certificate the store accepts, never by sharing a host with
|
||||
# one; ./glue-matrix-bao-token.nix gates on exactly that and not on `enable`.
|
||||
# one; ./glue-queue-agent-credential.nix gates on exactly that and not on
|
||||
# `enable`.
|
||||
# Reading this block as store-runner-only is what makes an off-host reader
|
||||
# look inexpressible when it is already supported.
|
||||
#
|
||||
|
|
@ -1629,27 +1637,6 @@ in
|
|||
'';
|
||||
};
|
||||
|
||||
matrixTokenCommonNamePrefix = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "swarm-bao-matrix-token";
|
||||
example = "swarm-bao-matrix-token.svc";
|
||||
description = ''
|
||||
Prefix of the subject the store's per-hive matrix-token roles accept.
|
||||
The role for hive `h` accepts `<prefix>-h` and nothing else, and grants
|
||||
read on exactly `swarm/hives/h/matrix/appservice-token`.
|
||||
|
||||
A **prefix** rather than one subject because every hive runs its own
|
||||
reader and the path it reads carries that hive's name. One subject for
|
||||
all of them would need a `hives/*` grant, which would let one hive read
|
||||
another hive's appservice token — a reach no hive has today.
|
||||
|
||||
⚠️ Reserved as a hive name by ./swarm.nix, per hive, for the reason its
|
||||
fixed-subject siblings are: cert auth trusts the CA and
|
||||
`allowed_common_names` is the whole narrowing, so a hive whose own leaf
|
||||
carried one of these spellings would receive that grant.
|
||||
'';
|
||||
};
|
||||
|
||||
queueAgentCommonNamePrefix = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "swarm-bao-queue-agent";
|
||||
|
|
@ -1660,10 +1647,15 @@ in
|
|||
exactly `swarm/hives/h/queue/agent` — the client credential that hive's
|
||||
agent containers authenticate to the swarm queue with.
|
||||
|
||||
Per hive for the same reason
|
||||
{option}`services.hyperhive.deploy.bao.matrixTokenCommonNamePrefix` is,
|
||||
and more sharply: every hive in the swarm runs this reader, so a single
|
||||
subject would have to be granted `hives/*`.
|
||||
A **prefix** rather than one subject because every hive runs its own
|
||||
reader and the path it reads carries that hive's name. One subject for
|
||||
all of them would need a `hives/*` grant, which would let one hive read
|
||||
another hive's queue credential.
|
||||
|
||||
⚠️ Reserved as a hive name by ./swarm.nix, per hive, for the reason its
|
||||
fixed-subject siblings are: cert auth trusts the CA and
|
||||
`allowed_common_names` is the whole narrowing, so a hive whose own leaf
|
||||
carried one of these spellings would receive that grant.
|
||||
'';
|
||||
};
|
||||
|
||||
|
|
@ -1678,7 +1670,7 @@ in
|
|||
for `h`'s domain and `*.` that domain and nothing else.
|
||||
|
||||
Per hive for the reason
|
||||
{option}`services.hyperhive.deploy.bao.matrixTokenCommonNamePrefix` is:
|
||||
{option}`services.hyperhive.deploy.bao.queueAgentCommonNamePrefix` is:
|
||||
one subject for every hive could ask for any hive's certificate.
|
||||
|
||||
⚠️ Reserved as a hive name by ./swarm.nix, per hive, like its siblings.
|
||||
|
|
@ -1725,7 +1717,7 @@ in
|
|||
presents. Its grant is one path,
|
||||
`swarm/services/<collector client id>/oidc/client`, and read only.
|
||||
|
||||
A **fourth** identity rather than reuse of
|
||||
Its **own** identity rather than reuse of
|
||||
{option}`services.hyperhive.deploy.bao.grafanaOidcCommonName`: the two
|
||||
read different services' client secrets, and a collector is not
|
||||
entitled to Grafana's.
|
||||
|
|
@ -1742,46 +1734,13 @@ in
|
|||
own forwarder's OIDC client secret, presents. Its grant is one path,
|
||||
`swarm/services/<forwarder client id>/oidc/client`, and read only.
|
||||
|
||||
A **fifth** identity rather than reuse of
|
||||
Its **own** identity rather than reuse of
|
||||
{option}`services.hyperhive.deploy.bao.otelOidcCommonName`: the two
|
||||
read different clients' secrets, and the store's forwarder is not
|
||||
entitled to the swarm collector's.
|
||||
'';
|
||||
};
|
||||
|
||||
matrixTokenClientCertFile = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
default = null;
|
||||
example = "/var/lib/swarm-bao-pki/matrix-token.pem";
|
||||
description = ''
|
||||
Certificate the unit that fetches this hive's matrix appservice token
|
||||
presents to the store. Its subject must be
|
||||
`<matrixTokenCommonNamePrefix>-<this hive's name>`; cert auth matches on
|
||||
the CN and the role accepts nothing else.
|
||||
|
||||
⚠️ **Not** {option}`services.hyperhive.deploy.bao.clientCertFile`.
|
||||
Pointing this at the hive's own leaf would evaluate, deploy and log in —
|
||||
and hand a unit that reads one token a credential that reads every
|
||||
secret in the store. That is what this option exists to end.
|
||||
|
||||
No default here: ./glue-bao-tls.nix points it at the leaf it mints,
|
||||
wherever this host mints its own PKI. A deployment that reads a store on
|
||||
another host names it by hand, alongside the leaf itself — one file per
|
||||
principal placed out of band instead of one shared by four.
|
||||
'';
|
||||
};
|
||||
|
||||
matrixTokenClientKeyFile = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
default = null;
|
||||
example = "/var/lib/swarm-bao-pki/matrix-token-key.pem";
|
||||
description = ''
|
||||
Private key for
|
||||
{option}`services.hyperhive.deploy.bao.matrixTokenClientCertFile`. Both
|
||||
or neither — a certificate with no key authenticates nothing.
|
||||
'';
|
||||
};
|
||||
|
||||
queueAgentClientCertFile = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
default = null;
|
||||
|
|
@ -1789,10 +1748,17 @@ in
|
|||
description = ''
|
||||
Certificate the unit that fetches this hive's queue client credential
|
||||
presents to the store. Its subject must be
|
||||
`<queueAgentCommonNamePrefix>-<this hive's name>`.
|
||||
`<queueAgentCommonNamePrefix>-<this hive's name>`; cert auth matches on
|
||||
the CN and the role accepts nothing else.
|
||||
|
||||
⚠️ Not the hive's own leaf, for the reason
|
||||
{option}`services.hyperhive.deploy.bao.matrixTokenClientCertFile` gives.
|
||||
⚠️ **Not** {option}`services.hyperhive.deploy.bao.clientCertFile`.
|
||||
Pointing this at the hive's own leaf would evaluate, deploy and log in —
|
||||
and hand a unit that reads one credential a certificate that reads every
|
||||
secret in the store.
|
||||
|
||||
No default here: ./glue-bao-tls.nix points it at the leaf it mints,
|
||||
wherever this host mints its own PKI. A deployment that reads a store on
|
||||
another host names it by hand, alongside the leaf itself.
|
||||
'';
|
||||
};
|
||||
|
||||
|
|
@ -1816,7 +1782,7 @@ in
|
|||
{option}`services.hyperhive.deploy.bao.grafanaOidcCommonName`.
|
||||
|
||||
⚠️ Not the hive's own leaf, for the reason
|
||||
{option}`services.hyperhive.deploy.bao.matrixTokenClientCertFile` gives.
|
||||
{option}`services.hyperhive.deploy.bao.queueAgentClientCertFile` gives.
|
||||
'';
|
||||
};
|
||||
|
||||
|
|
@ -1840,7 +1806,7 @@ in
|
|||
{option}`services.hyperhive.deploy.bao.otelOidcCommonName`.
|
||||
|
||||
⚠️ Not the hive's own leaf, for the reason
|
||||
{option}`services.hyperhive.deploy.bao.matrixTokenClientCertFile` gives.
|
||||
{option}`services.hyperhive.deploy.bao.queueAgentClientCertFile` gives.
|
||||
'';
|
||||
};
|
||||
|
||||
|
|
@ -1864,7 +1830,7 @@ in
|
|||
{option}`services.hyperhive.deploy.bao.forwarderOidcCommonName`.
|
||||
|
||||
⚠️ Not the hive's own leaf, for the reason
|
||||
{option}`services.hyperhive.deploy.bao.matrixTokenClientCertFile` gives.
|
||||
{option}`services.hyperhive.deploy.bao.queueAgentClientCertFile` gives.
|
||||
'';
|
||||
};
|
||||
|
||||
|
|
@ -2924,13 +2890,11 @@ in
|
|||
'';
|
||||
};
|
||||
|
||||
# 🩸 The four principals that used to log in as the hive. See the block
|
||||
# around `perHiveReaders` for what each grant is and why the first two are
|
||||
# per hive; the four units are identical apart from the objects they
|
||||
# 🩸 The principals that used to log in as the hive. See the block around
|
||||
# `perHiveReaders` for what each grant is and why the first is per hive;
|
||||
# the units are identical apart from the objects they
|
||||
# write, so the shape lives in `readerPolicyUnit` and the difference is
|
||||
# visible here in one line each.
|
||||
systemd.services.swarm-bao-matrix-token-policy = readerPolicyUnit "write the per-hive matrix-token bao policies and cert-auth roles" matrixTokenReaders;
|
||||
|
||||
systemd.services.swarm-bao-queue-agent-policy = readerPolicyUnit "write the per-hive queue-credential bao policies and cert-auth roles" queueAgentReaders;
|
||||
|
||||
systemd.services.swarm-bao-grafana-oidc-policy = readerPolicyUnit "write Grafana's OIDC-secret-reader bao policy and cert-auth role" grafanaOidcReaders;
|
||||
|
|
@ -3139,7 +3103,6 @@ in
|
|||
"swarm-bao-controller-policy.service"
|
||||
"swarm-bao-secret-publisher-policy.service"
|
||||
"swarm-bao-matrix-ctl-policy.service"
|
||||
"swarm-bao-matrix-token-policy.service"
|
||||
"swarm-bao-queue-agent-policy.service"
|
||||
"swarm-bao-grafana-oidc-policy.service"
|
||||
"swarm-bao-otel-oidc-policy.service"
|
||||
|
|
|
|||
Loading…
Reference in a new issue