Per-instance encryption domain separation; demote deployment single-key #31
Labels
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: Cordy/Cairn#31
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Manuel dislikes the one-key-per-instance model (blast radius too large). Our
deploymentcustody mode is exactly that.deploymentcustody to dev/fallback only (default stayskeycloak-profileper-user).Small change; closes the blast-radius objection to the fallback mode.
Decision — approved with amended scope (Manuel's review, relayed by Nikola 2026-07-31):
Un-gated, scope narrowed: per-instance encryption domain separation goes ahead; the second half of the original title — demoting the
deploymentsingle-key custody mode — is dropped.keyCustody: "deployment"remains a fully supported first-class option (it's also the natural mode for small instances and the fallback when no IdP profile custody exists). Title kept for history; treat this comment as the authoritative scope.Shipped in v0.3.28 (PR #99), honoring the review verdict: deployment custody stays a full peer — not demoted. Only the domain-separation half was built.
New
storage.encryption.instanceSeed(orCAIRN_ENC_INSTANCE_SEED): with a seed set, deployment custody derives a per-instance identity via HKDF-SHA256(deploymentIdentity, seed) (stdlibcrypto/hkdf; the derived scalar is rendered with a minimal bech32 encoder validated against age's own parser as test oracle). New content encrypts to the derived identity + recovery. Test matrix proves: same master + different seeds → mutually unreadable; the bare master no longer decrypts separated content (the exact blast-radius objection); recovery always works; pre-separation data still decrypts (master retained on the decrypt side).Operational note: the seed belongs in the config secret next to the master identity — it's a separator, not a second secret, and deriving from ephemeral
/datastate would silently orphan data on pod restart. Unseeded deployments behave exactly as before.