swarm-nats-auth: verify an agent's own token against the store
An `auth_token` spelled `swarm-agent.<agent>.<secret>` is no longer sent
to introspection. The responder reads `swarm/agents/<agent>/queue` with
an identity of its own, checks that the stored object names the same
agent, compares the secret in constant time, and grants the subjects
`--agent-token-publish-subject` lists with `{agent}` expanded. Every
other outcome denies: a malformed token, no store identity, nothing
stored, a failed or slow lookup, a different secret. A token without
the prefix takes the OIDC path unchanged.
The journal's `auth request` line names such a caller `agent:<agent>`;
the hive-shared credential keeps `hive-<h>-agent`.
The new principal: a `swarm-nats-auth` cert-auth role and policy with
read on `secret/data/swarm/agents/+/queue` alone, a leaf signed by the
store's PKI glue, and `glue-nats-auth-bao-identity.nix` pairing the two.
The copy unit delivers the identity into the queue's container, and an
absent leaf is delivered empty so the responder still starts and only
agent tokens are refused.
The policy and role are written by `swarm-bao-nats-auth-policy`, logged in
as the bao granter: both names fall under its `swarm-*` globs, so the
deploy writes them with no operator step. module-eval counts it among the
granting units, so every generic granting-unit case covers it.
The secret compare uses `subtle`, already in the lock file through the
TLS stack; no workspace crate offered one directly.
This commit is contained in:
parent
fc97c237dc
commit
9bad58d86d
14 changed files with 846 additions and 51 deletions
|
|
@ -754,6 +754,18 @@ let
|
|||
}
|
||||
];
|
||||
|
||||
# The queue's auth-callout responder, which checks the secret an agent
|
||||
# presents against the one stored for it. One leaf under every agent: `+` is
|
||||
# one path segment, where `*` globs only at the end and would reach every
|
||||
# other credential an agent holds.
|
||||
natsAuthReaders = [
|
||||
{
|
||||
name = "swarm-nats-auth";
|
||||
cn = baoDeploy.natsAuthCommonName;
|
||||
policyText = readStanza "${credentialMountPath}/data/swarm/agents/+/queue";
|
||||
}
|
||||
];
|
||||
|
||||
# The role name IS the policy name, as for the three service principals
|
||||
# above: the role attaches the policy by spelling it identically, and one
|
||||
# string for both objects removes the way they drift apart.
|
||||
|
|
@ -1438,6 +1450,24 @@ in
|
|||
'';
|
||||
};
|
||||
|
||||
natsAuthCommonName = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "swarm-nats-auth";
|
||||
description = ''
|
||||
Subject the store's `swarm-nats-auth` cert-auth role accepts: the
|
||||
identity the queue's auth-callout responder presents to read agent
|
||||
queue credentials, `swarm/agents/<agent>/queue` and nothing else under
|
||||
an agent.
|
||||
|
||||
Its own principal rather than
|
||||
{option}`services.hyperhive.deploy.bao.natsCommonName`: that one
|
||||
issues the queue's TLS leaf from a host unit, this one reads secrets
|
||||
from inside the queue's container.
|
||||
|
||||
⚠️ Reserved as a hive name by ./swarm.nix, like its siblings.
|
||||
'';
|
||||
};
|
||||
|
||||
matrixCtlHiveName = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = toString hyperhiveCfg.hiveName;
|
||||
|
|
@ -2021,6 +2051,7 @@ in
|
|||
"swarm-bao-services-issuer-policy"
|
||||
"swarm-bao-nats-tls-policy"
|
||||
"swarm-bao-agent-pki"
|
||||
"swarm-bao-nats-auth-policy"
|
||||
];
|
||||
|
||||
# 🚫 No `swarm.otel.scrapeTargets.bao` entry any more, and its absence is
|
||||
|
|
@ -2723,6 +2754,8 @@ in
|
|||
|
||||
systemd.services.swarm-bao-forwarder-oidc-policy = readerPolicyUnit "write the store forwarder's OIDC-secret-reader bao policy and cert-auth role" forwarderOidcReaders;
|
||||
|
||||
systemd.services.swarm-bao-nats-auth-policy = readerPolicyUnit "write the queue responder's agent-credential-reader bao policy and cert-auth role" natsAuthReaders;
|
||||
|
||||
# A FOURTH sibling, same shape and same reasons as the two above. This
|
||||
# one is what turns `swarm-services-issuer` from a declaration into a
|
||||
# grant: a bao policy reaches nothing until a login role hands it to a
|
||||
|
|
|
|||
Loading…
Reference in a new issue