docs(config): design encrypted local-settings store (VA-29) #29

Merged
nrupard merged 2 commits from plan/encrypted-settings-store-VA-29 into main 2026-05-21 21:06:53 +02:00
Owner

Closes VA-29 (planning ticket: deliverable is this design doc).

Adds docs/local-settings-store.md, the pinned design for replacing the plaintext .msh config with an encrypted at-rest local-settings store. No agent code changes.

Decisions pinned

  • Threat model: filename-blind byte exfiltration (backup/snapshot/raw-block recovery). Running-host and read-write attackers explicitly out of scope, with an honesty note that filename-as-key is void once the name travels with the bytes, hence the paired install_secret.
  • Full .msh key inventory (swept from crates/) with move targets: every key moves into the encrypted store, none needs plaintext bootstrap.
  • Storage: whole-file AEAD blob, not SQLite. A flat key-value map (today's MshConfig BTreeMap) does not justify a SQL engine, and whole-file crypto makes SQLCipher's page-level crypto redundant. The ticket title's "SQLite" is deliberately overridden, with the reasoning recorded.
  • KDF: HKDF-SHA-384 (ring). Argon2/PBKDF2 rejected: the input is a high-entropy secret, not a password.
  • Cipher: ChaCha20-Poly1305 (ring), software-constant-time for the headless ARM targets, fresh random nonce per write.
  • Locator: filename = base32(SHA-384(install_secret)[..20]).vss; secret in a 0600 sidecar excluded from the backup set. Resolves the ticket's agent_id open question (platform enum, not per-install; node_id lives in the sled store opened after config load).
  • Bootstrap, migration (.msh -> .vss, rotate to .msh.bak), operator inspection subcommands, and corruption/recovery flows all spelled out.

Follow-up

VA-30 (implementation) is described in section 14 / scope and should be opened with the scope locked. I was blocked from creating it automatically; see PR discussion.

Closes VA-29 (planning ticket: deliverable is this design doc). Adds `docs/local-settings-store.md`, the pinned design for replacing the plaintext `.msh` config with an encrypted at-rest local-settings store. No agent code changes. ## Decisions pinned - Threat model: filename-blind byte exfiltration (backup/snapshot/raw-block recovery). Running-host and read-write attackers explicitly out of scope, with an honesty note that filename-as-key is void once the name travels with the bytes, hence the paired `install_secret`. - Full `.msh` key inventory (swept from `crates/`) with move targets: every key moves into the encrypted store, none needs plaintext bootstrap. - Storage: whole-file AEAD blob, **not** SQLite. A flat key-value map (today's `MshConfig` BTreeMap) does not justify a SQL engine, and whole-file crypto makes SQLCipher's page-level crypto redundant. The ticket title's "SQLite" is deliberately overridden, with the reasoning recorded. - KDF: HKDF-SHA-384 (`ring`). Argon2/PBKDF2 rejected: the input is a high-entropy secret, not a password. - Cipher: ChaCha20-Poly1305 (`ring`), software-constant-time for the headless ARM targets, fresh random nonce per write. - Locator: filename = `base32(SHA-384(install_secret)[..20]).vss`; secret in a `0600` sidecar excluded from the backup set. Resolves the ticket's `agent_id` open question (platform enum, not per-install; `node_id` lives in the sled store opened after config load). - Bootstrap, migration (`.msh` -> `.vss`, rotate to `.msh.bak`), operator inspection subcommands, and corruption/recovery flows all spelled out. ## Follow-up VA-30 (implementation) is described in section 14 / scope and should be opened with the scope locked. I was blocked from creating it automatically; see PR discussion.
docs(config): design encrypted local-settings store (VA-29)
All checks were successful
Check / clippy + fmt + tests (pull_request) Successful in 1m22s
5bc5efc769
Pins the replacement for the plaintext .msh config: a whole-file AEAD blob (HKDF-SHA-384 + ChaCha20-Poly1305, both from ring) keyed off a 256-bit install_secret whose hash names the file. Records the threat model (filename-blind byte exfiltration), the full .msh key inventory with move targets, and the bootstrap / migration / inspection / recovery flows. Deliberately rejects SQLite: a flat key-value map does not justify a SQL engine, and whole-file encryption makes page-level crypto (SQLCipher) redundant.

Planning ticket only; no agent code changes here.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
docs(config): point design doc at impl ticket VA-33
All checks were successful
Check / clippy + fmt + tests (pull_request) Successful in 1m22s
42270cab03
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
nrupard deleted branch plan/encrypted-settings-store-VA-29 2026-05-21 21:06:53 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/vervain-agent!29
No description provided.