One page each for machined, secrets, sessiond — what each owns, what crosses its boundary, and the open gaps before it reaches the RedFlag capability-token bar. Gaps mapped to concrete RedFlag primitives (token, closure hash, canonical message, KeyID, independent verifier, binary integrity, eBPF) with file:line anchors, not doctrine-summary hand-waving. audit-status.md rolls up priority: P0 unlock/handoff attestation, P1 machined token issuance, P2 secrets caller identity, P3 per-agent UIDs, P4 binary watchdog shared-deferred with RedFlag SEC-022.
5.1 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 services-infrastructure review) makeSO_PEERCREDkernel-backed caller identity, which is what the token'sAgentIDfield is in RedFlag — but today every caller is uid 1000.
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.