id: node
title: A host proves what it is once, and issues credentials to the sessions on it
status: open
crates: [didbot-agentd, didbot-attest]
dependsOn: [credentials, attestation]
exitCriterion: >
A machine holding a node credential issues a session credential to a hook that
asks for one, a machine without one is refused, and many hooks starting at
once produce one provisioning request per session rather than one per hook. #
credentials states the shape and names this as its first
item: the shape mirrors SPIFFE — a node attests once, a local component issues
credentials, and the workload talks to the server itself. This epic is that
local component, split out because it is a process with a lifetime, an install
story and a privilege boundary of its own, and those do not fit inside a
bullet.
Both were on the table. The hook is the simpler answer and it does not survive
contact with a busy machine.
A hook is a short-lived process spawned per tool call. Putting the node
credential in it means every one of those processes reads the credential off
disk, so the blast radius of anything that can observe a process is the whole
node identity rather than one session. And a machine running several sessions
and their subagents fires many hooks at once, each asking the server for an
account, so provisioning arrives as a stampede with nowhere to be coalesced.
A long-lived component fixes both: one process holds the credential, and it is
the natural place to serialise and rate-limit what reaches the server.
The cost is honest and worth writing down: it is another thing to install,
supervise and version on every agent host, and deploy already
notes that agent hosts are their own deployment. dev-setup's
service/profile/binding model is where it has to fit.
The argument above was written about code that did not exist. What it
described as a daemon was one short-lived process per event, reading its state
from a plaintext file. The reasoning holds; it was describing the design
rather than the build.
Two things it did not anticipate make it stronger. subagents
gives every context an account, so a fan-out of parallel subagents acting at
once is the same burst moved to the busiest moment rather than the quietest.
And cred-delivery has this process perform the write,
which is what keeps a credential out of every place the model can read.