Watch
0
0
Fork
You've already forked hyperhive
0

swarm-nats: require the responder's store identity, and drop its no-store mode

The responder reads the callout xkey before it connects, so a responder
with no secret store no longer starts, and its "deny every agent token,
serve OIDC" mode could not run. That mode is gone: `agent_token::Store`
is built from the settings the xkey load already read, and `authorize`
takes a source rather than an `Option` of one.

On the nix side, `deploy.nats.authBaoClientCertFile` and
`authBaoClientKeyFile` are now asserted at eval when the queue is
enabled. The units' no-identity branches, the copy unit's empty-file
fallback and its "denies agent tokens" message are removed; an absent
leaf file fails `swarm-nats-auth-secrets` like an absent seed does.
This commit is contained in:
atlas 2026-10-05 22:13:58 +02:00 • committed by mara
commit 52c931c3a7
5 changed files with 193 additions and 248 deletions

View file

@ -155,8 +155,9 @@ struct Args {
agent_token_publish_subjects: Vec<String>,
/// Role on the secret store's `cert` auth mount this responder logs in
/// as to read agent credentials. The store is found through the `BAO_*`
/// environment; with none, every agent token is denied.
/// as to read the callout xkey and agent credentials. The store is found
/// through the `BAO_*` environment, which the responder does not start
/// without.
#[arg(long, default_value = "swarm-nats-auth")]
store_cert_role: String,
}
@ -219,19 +220,25 @@ async fn serve(args: &Args) -> anyhow::Result<()> {
args.hive_publish_subjects.clone(),
)?
.with_agent_token_subjects(args.agent_token_publish_subjects.clone())?;
let store = agent_token::Store::from_env(args.store_cert_role.clone());
let http = reqwest::Client::new();
let issuer = nkeys::KeyPair::from_seed(&read_secret(&args.issuer_seed_file)?)
.context("parse the account signing seed")?;
let settings = swarm_secret_client::client::Settings::from_env()
.context("reading the secret store's address and this responder's identity")?;
// Before the connect: a responder that cannot open a sealed request must
// not start answering. Read, never created here; see `xkey`.
let callout_xkey = xkey::load(
&swarm_secret_client::SecretStore::from_env(&args.store_cert_role)
.await
.context("logging in to the secret store for the callout xkey")?,
&swarm_secret_client::SecretStore::connect(
&settings,
&args.store_cert_role,
swarm_secret_client::client::DEFAULT_CERT_MOUNT,
)
.await
.context("logging in to the secret store for the callout xkey")?,
)
.await?;
tracing::info!(public_key = %callout_xkey.public_key(), "loaded the callout xkey");
let store = agent_token::Store::new(settings, args.store_cert_role.clone());
let user_seed = read_secret(&args.user_seed_file)?;
let client = async_nats::ConnectOptions::with_nkey(user_seed)
.name("swarm-nats-auth")
@ -266,7 +273,7 @@ async fn serve(args: &Args) -> anyhow::Result<()> {
// the secret proved it; `granted` says which.
Some(agent_token::Presented::Agent(token)) => (
Some(format!("agent:{}", token.agent)),
agent_token::authorize(&policy, store.as_ref(), &token).await,
agent_token::authorize(&policy, &store, &token).await,
),
Some(agent_token::Presented::Malformed(e)) => {
tracing::warn!(error = %e, "malformed agent token; denying");