Join the older storage and authority audits to the SAF principal contract. Passwd entries are not isolation while one human-owned process still executes every agent, and the existing souveraine account is machined's—not Souvie's.\n\nKeep the readiness task honest: its current health fields inventory paths, but do not yet prove admission or the UID handling a live turn.
5.3 KiB
souveraine-machined
System-tier machine identity daemon. The root of the authority family — it holds the machine's Ed25519 seed and hands out signatures, never key material. Every other component that needs to prove machine identity asks this one to sign.
Source: src/bin/souveraine-machined.rs, src/machined/{protocol,server,signer,client}.rs.
RedFlag analog: the server's SigningService (authority that mints and
signs) in server/internal/services/capability_minter.go.
What it owns
- The machine Ed25519 seed at
/var/lib/souveraine/seed-id. - A Unix socket at
/run/souveraine/machined.sock(groupsouveraine, group-readable/writable).
The seed is a precondition, never created by the daemon. If no seed
exists, startup fails loudly. Identity creation lives in the deliberate,
guarded CLI verb souveraine machine init. Same doctrine as secrets and
sessiond; see SeedId::load in core/identity/seed.rs.
What crosses the boundary
Requests are JSON-lines over the socket. Two verbs:
- pubkey — the machine's public key (safe to share).
- sign { domain, payload_hex } — a signature over domain-separated
bytes. The signed material is
{SIGNING_CONTEXT}:{domain}:{payload}, never caller-supplied raw.domainis restricted to ASCII alnum/-/_/./,, max 64 chars; the daemon refuses anything else.
The private key never leaves the process. Callers get signatures and the public key — that is the entire surface.
Identity of the caller
SO_PEERCRED is read on every connection; uid/gid/pid are logged on every
sign request and every refusal (src/machined/server.rs:25-43). Today this
is observability, not enforcement — any process in the souveraine
group can request a signature. That is the central audit gap (below).
Today's security posture
- Domain separation prevents the daemon from being turned into an oracle
for arbitrary signatures: a signature under one domain does not validate
in another. This is the same principle as RedFlag's
CanonicalMessage(agent/internal/capability/token.go) — the signed bytes are a fixed, field-delimited string, never caller-controlled in shape. - Seeds are never daemon-generated; no background process can quietly mint a machine identity.
- The socket is group-scoped, so membership in
souveraineis the coarse gate.
Audit gaps (toward the RedFlag bar)
The target posture is RedFlag's capability-token model, read from its source (not the doctrine summary):
- Capability token = Ed25519-signed, forward-only, scoped, expiring.
RedFlag's
TokencarriesVersion(forward-only — new versions add fields, never reinterpret),Operation,IssuedAt/NotBefore/ExpiresAt, and aSignature(agent/internal/capability/token.go). machined today signs caller payloads but does not issue scoped, expiring tokens — it signs rawdomain:payloadbytes with no operation, no expiry, no closure. Gap: callers cannot present a machined-issued token to a verifier, because machined mints signatures, not tokens. - Closure hash binds the token to exactly what it authorizes. RedFlag's
ClosureHashissha256over sorted, de-duplicatedname@version#sha256lines, so neither order nor duplicates change the digest. The Souveraine analog for "what is this signature authorizing" does not exist yet — thepayload_hexis opaque to the daemon. When tokens land, the authorized thing (a verb, a target binary hash, a session) must be inside the canonical message the way RedFlag's closure is. - KeyID binds a signature to a key fingerprint. RedFlag's
KeyIDForishex(sha256(pubkey)[:16]). machined exposes the pubkey but does not advertise a fingerprint verifiers can pin; a rotating seed has no discoverable, comparable identity today. - The verifier must be independent. In RedFlag the privileged executor
(
helper/) verifies the token itself — it does not trust the agent's claim. Souveraine's analog: whatever consumes a machined signature must verify it against the pinned pubkey, not trust the relay. No such verifier is wired yet. SO_PEERCREDis logged, not enforced. Logging is necessary for audit (P3: use is visible) but not sufficient as a gate. Per-agent UIDs (the admission contract in../../../souveraine/saf/identity/02-agent-principal.md) plus per-agent worker processes makeSO_PEERCREDkernel-backed caller identity, which is what the token'sAgentIDfield is in RedFlag — but today every caller is uid 1000. The packagedsouveraineaccount is machined's machine-tier principal, not the default Souvie agent.
Binary integrity of machined itself
RedFlag's binary-attestation primitive is verify-binary <path> <expected_sha256> (helper/src/main.rs:608-667) — SHA-256 compare, exit
EXIT_INTEGRITY=21 on mismatch. It is deliberately not wired in RedFlag
either (SEC-022: "kill-on-mismatch and phone-home are deliberately not
wired"). machined has no self- or peer-integrity check today. When this
lands, the same SHA-256-compare shape applies, and — as in RedFlag — the
DAC/sudoers layer (root:root 0755, non-overwritable by the running user)
is the integrity guarantee that holds until the watchdog is wired.
See audit-status.md for where these land in priority order.