swarm: name the agent client after its hive, not after "agent"
`agent-<hive>` reads as "the agent named <hive>" — which is the one thing that identity does not carry, since it is minted per hive. It becomes `hive-<hive>-agent`: the hive's own id, extended. The rename is not a string swap. `hive-foo-agent` satisfies the hive parse too (it strips to a hive named `foo-agent`), so the responder's agent rule now runs BEFORE its hive rule — most specific wins. Hive-first would have handed every agent its hive's grant, including writing that hive's status key, with nothing to report it: the client authenticates and is merely able to do more than it should. `Policy::new`'s overlap check goes with the prefix it was written for. The invariant the suffix form needs instead is that the suffix is non-empty: an empty one makes `strip_suffix` succeed on every hive id, so the two principals become one string and whichever arm runs first answers for both. The suffix form also introduces a collision the prefix form did not have: a hive genuinely named `foo-agent` mints `hive-foo-agent`, which is hive `foo`'s agent id. The responder cannot see it — it has no roster, deliberately — so `swarm-authelia.nix` asserts at eval that no hive name ends with the suffix. The existing duplicate-id assertion does not cover this: it fires only when both `foo` and `foo-agent` are on the roster, and with `foo-agent` alone there is no duplicate, just a hive quietly receiving its agents' grant. A test written by analogy with `the_prefix_alone_names_no_hive` failed, correctly — `hive--agent` is a hive named `-agent` under the hive parse, which this module cannot rule out. It now asserts only the part this module owns: no empty hive name is ever expanded into a subject.
This commit is contained in:
parent
fe9417ae52
commit
780df10d9d
4 changed files with 181 additions and 83 deletions
|
|
@ -82,15 +82,20 @@ struct Args {
|
|||
#[arg(long, default_value = "hive-")]
|
||||
hive_client_prefix: String,
|
||||
|
||||
/// Client-id prefix that marks an agent container. `swarm-authelia.nix`
|
||||
/// mints one machine client per roster entry as `agent-<hive>` — per
|
||||
/// **hive**, not per agent, because agents are created at runtime and a
|
||||
/// per-agent client would make creating one a config change plus a reload.
|
||||
/// Suffix that marks an agent container, appended to the hive's own client
|
||||
/// id: `swarm-authelia.nix` mints one machine client per roster entry as
|
||||
/// `hive-<name>-agent` — per **hive**, not per agent, because agents are
|
||||
/// created at runtime and a per-agent client would make creating one a
|
||||
/// config change plus a reload.
|
||||
///
|
||||
/// So this identity says which hive an agent belongs to and never which
|
||||
/// agent: two agents on one hive are indistinguishable to this responder.
|
||||
#[arg(long, default_value = "agent-")]
|
||||
agent_client_prefix: String,
|
||||
///
|
||||
/// A suffix on the hive's id rather than a prefix of its own, because
|
||||
/// `agent-<name>` reads as *the agent called `<name>`* — the one thing
|
||||
/// this identity does not carry.
|
||||
#[arg(long, default_value = "-agent")]
|
||||
agent_client_suffix: String,
|
||||
|
||||
/// Client ids allowed to read every hive's status. Repeatable. The
|
||||
/// default is the swarm controller, which is the only reader that exists.
|
||||
|
|
@ -108,7 +113,8 @@ struct Args {
|
|||
hive_publish_subjects: Vec<String>,
|
||||
|
||||
/// Subjects an agent may publish to, with `{hive}` standing for the hive
|
||||
/// its identity names. Repeatable, empty by default.
|
||||
/// its identity names — `hive-alpha-agent` expands it to `alpha`.
|
||||
/// Repeatable, empty by default.
|
||||
///
|
||||
/// Empty means agents get **no grant at all** rather than a grant that can
|
||||
/// do nothing — the identity exists, and what it may say is a deployment's
|
||||
|
|
@ -161,7 +167,7 @@ async fn main() -> anyhow::Result<()> {
|
|||
// silently over-broad grant is not.
|
||||
let policy = policy::Policy::new(
|
||||
args.hive_client_prefix.clone(),
|
||||
args.agent_client_prefix.clone(),
|
||||
args.agent_client_suffix.clone(),
|
||||
swarm_queue_client::status::BUCKET.to_owned(),
|
||||
args.reader_clients.clone(),
|
||||
args.hive_publish_subjects.clone(),
|
||||
|
|
|
|||
Loading…
Reference in a new issue