swarm: give agent containers their own queue principal
Agents have authelia *users*; they had no machine identity at all, so an agent could not authenticate to the swarm queue as anything. This mints one `agent-<hive>` OIDC client per hive beside the existing `hive-<hive>` one, teaches the auth-callout responder an agent arm, and opens the queue's client port on the bridge so a container can reach it. One client per HIVE, not per agent: agents are created at runtime, and a per-agent client would make creating one a config change plus an authelia reload. The cost is that agents on a hive are indistinguishable to the broker, which is deliberate and tracked separately. The agent grant is deny-by-default twice over. An agent id matches no hive rule, so it gets a hive's status-key grant from neither; and with no agent subject configured the responder returns no grant at all rather than an empty publish list, which would be a denial wearing a grant's shape. What an agent may publish is a deployment's decision, taken through `--agent-publish-subject` the same way `--hive-publish-subject` already works. `Policy::new` now refuses two prefixes where one contains the other. The arms are tried in order, so that overlap does not error at match time - it silently hands one principal the other's grant. Not shipped here, and neither is reachable without it: no subject is configured for agents anywhere in nix, and nothing yet delivers `agent-<hive>.secret` into an agent container. Both belong to the stream that will be the first consumer.
This commit is contained in:
parent
d7ca8d922b
commit
fe9417ae52
5 changed files with 301 additions and 13 deletions
|
|
@ -82,6 +82,16 @@ 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.
|
||||
///
|
||||
/// 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,
|
||||
|
||||
/// Client ids allowed to read every hive's status. Repeatable. The
|
||||
/// default is the swarm controller, which is the only reader that exists.
|
||||
#[arg(long = "reader-client", default_values_t = [String::from("swarm-controller")])]
|
||||
|
|
@ -96,6 +106,17 @@ struct Args {
|
|||
/// subject still lands inside that hive's own namespace.
|
||||
#[arg(long = "hive-publish-subject")]
|
||||
hive_publish_subjects: Vec<String>,
|
||||
|
||||
/// Subjects an agent may publish to, with `{hive}` standing for the hive
|
||||
/// its identity names. 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
|
||||
/// decision, not this responder's. The first consumer is the agent
|
||||
/// terminal-event stream; until one is configured, an agent that connects
|
||||
/// is refused, which is loud rather than silently over-broad.
|
||||
#[arg(long = "agent-publish-subject")]
|
||||
agent_publish_subjects: Vec<String>,
|
||||
}
|
||||
|
||||
/// Read a secret file and strip surrounding whitespace.
|
||||
|
|
@ -140,9 +161,11 @@ 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(),
|
||||
swarm_queue_client::status::BUCKET.to_owned(),
|
||||
args.reader_clients.clone(),
|
||||
args.hive_publish_subjects.clone(),
|
||||
args.agent_publish_subjects.clone(),
|
||||
)?;
|
||||
let http = reqwest::Client::new();
|
||||
let issuer = nkeys::KeyPair::from_seed(&read_secret(&args.issuer_seed_file)?)
|
||||
|
|
|
|||
Loading…
Reference in a new issue