-- The key a node's secrets are sealed to, and the sealed secrets themselves. -- -- The arrangement is the opposite of encrypting a credential column. There, the control plane can -- read every secret it stores, so a copy of its database is a copy of every credential in the -- mesh, and encryption at rest only means somebody needs the process rather than the file. Here -- the value is sealed to the node that will use it before it is written, so **this table holds -- nothing usable** -- which is what makes novox/hq ADR 0004's "compromise of a node is compromise -- of that node" true of secrets and not only of identity. -- -- It also costs the ability to audit by value, and that is the right trade rather than an -- oversight: a `where value like ...` over an encrypted column returns zero rows and proves -- nothing, so the audit was never real. What is answerable here is which node holds what, which -- is the question rotation actually asks. alter table node add column sealing_key text; create table secret ( -- What it is for. The provision as required -- `database` -- not the module answering it. name text not null, consumer uuid not null references node(id) on delete cascade, provider uuid not null references node(id) on delete cascade, -- The same value, sealed twice: once to each end. Two blobs rather than one shared key, -- because a key both ends hold is a key the mesh must also hold to distribute. -- -- The plaintext is never written. It exists for the length of one function call, is sealed to -- both recipients, and is discarded -- so rotation means generating a new one rather than -- reading the old one back, which is the only version of rotation that is honest about what -- the mesh knows. for_consumer text not null, for_provider text not null, -- Which key each was sealed to. A node that regenerates its sealing key can no longer open -- what was sealed to the old one, and this is what lets that be reported rather than -- discovered as a service that will not start. consumer_key text not null, provider_key text not null, created_at timestamptz not null default now(), primary key (name, consumer, provider) ); create index secret_by_provider on secret (provider);