swarm-secret-client: hives no longer read swarm/services/*
The hive policy rendered by policy::render granted every hive cert read on secret/data/swarm/services/*, which holds each swarm service's OIDC client secret. No reader of that tree authenticates with a hive cert: grafana, the otel collector and the store forwarder each read with their own leaf, and the bao UI's secret is read by the store's granter. render() now emits two stanzas: swarm/agents/* and the hive's own swarm/hives/<hive>/*. Kind::Service had no other caller and is removed. Docs and comments that described the grant as a decision are rewritten to the current state. Closes #4960
This commit is contained in:
parent
3bfdf0dfe0
commit
2505008b83
13 changed files with 82 additions and 136 deletions
|
|
@ -60,18 +60,10 @@ pub fn hive_localpart(hive: &str) -> String {
|
|||
|
||||
/// The path holding `hive`'s matrix sender account's homeserver access token.
|
||||
///
|
||||
/// Keyed per **hive**, like [`appservice_token_path`] below and unlike the
|
||||
/// per-homeserver constant this replaced. The old path
|
||||
/// (`swarm/services/matrix/sender-token`) held **one value for the whole
|
||||
/// swarm** and sat under the [`Kind::Service`] tree that
|
||||
/// [`crate::policy::render`] grants *every* hive read on — so every hive could
|
||||
/// read, and act as, the one shared account.
|
||||
///
|
||||
/// Under [`Kind::Hive`] the grant that reaches it is the hive's **own**
|
||||
/// stanza, `secret/data/swarm/hives/<this hive>/*`, which interpolates the
|
||||
/// name: hive `alpha` reads its own token and gets a 403 on `beta`'s. Nothing
|
||||
/// was added to the policy to do that — the path moved out from under the
|
||||
/// broad grant, which is the half that makes it real.
|
||||
/// Keyed per **hive**, like [`appservice_token_path`] below. Under
|
||||
/// [`Kind::Hive`] the grant that reaches it is the hive's **own** stanza,
|
||||
/// `secret/data/swarm/hives/<this hive>/*`, which interpolates the name: hive
|
||||
/// `alpha` reads its own token and gets a 403 on `beta`'s.
|
||||
///
|
||||
/// # Errors
|
||||
/// [`Error::PathSegment`] when `hive` contains anything but `[A-Za-z0-9_-]`,
|
||||
|
|
@ -112,9 +104,8 @@ pub(crate) const CONTROLLER: &str = "swarm-controller";
|
|||
///
|
||||
/// The matrix container mints it and publishes it here; `swarm-controller`
|
||||
/// reads it to create agents' accounts. Under [`Kind::Controller`] because
|
||||
/// that is the one kind [`crate::policy::render`] grants no hive: every hive
|
||||
/// reads `agents/*`, its own `hives/<hive>/*` and `services/*`, so under any
|
||||
/// of those this admin credential would be readable by every hive.
|
||||
/// [`crate::policy::render`] grants no hive that kind: every hive reads
|
||||
/// `agents/*` and its own `hives/<hive>/*`, and nothing else.
|
||||
///
|
||||
/// # Errors
|
||||
/// Never in practice: the name segment is a constant. The `Result` is
|
||||
|
|
@ -174,18 +165,6 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_sender_token_left_the_tree_every_hive_can_read() {
|
||||
// 🩸 The whole point of the move. `policy::render` grants every hive
|
||||
// read on `secret/data/swarm/services/*` — a deliberate grant that
|
||||
// stays, because a service's OIDC secret is read with the certificate
|
||||
// of whatever hive hosts it. What must not stay is this credential
|
||||
// sitting inside it: under `services/` one shared token was readable
|
||||
// by every hive, which is one matrix identity for the whole swarm.
|
||||
let p = sender_token_path("pr1ma").expect("legal");
|
||||
assert!(!p.starts_with("swarm/services/"), "{p}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn one_hives_sender_token_is_not_another_hives() {
|
||||
// The property the per-hive path exists for: two hives never name the
|
||||
|
|
|
|||
Loading…
Reference in a new issue