NodeVault credential form and node fingerprints

Task 5292 · Done · Coder · created · updated

## Original requirement (epic 5269, verbatim) Build NodeVault feature: - Is a product that can be activated on a billing plan (once it lands in 5246) - When NodeVault is activated for an org, Org Admin can start Setup in Settings / NodeVault, that initiates a stepper: - Explanation with a diagram - On the backend System generates a Temporary NodeVault Key and sends it to all nodes (encoding each with node key) in the organization. Nodes store it in a secure place (next to other sensitive information, such as node token) - Generate NodeVault Key / Upload NodeVault Key. When Generate NodeVault Key - browser generates a key-pair (same algo as Temporary) encodes it with Temporary NodeVault Key public key and sends to CP to fan out to all nodes. Stores public key in the DB - Migrate credentials to NodeVault: all, select. Backend goes through all credentials that user selected and that are KMS encoded, decodes them and re-encodes them with NodeVault Key public key. No cred logging. - Show the result to the user - Credentials get a checkbox NodeVault (on by default for each new cred) - Credentials remember their current NodeVault key hash - When a broker requests a credentials and the credential is NodeVault, the broker uses the private NodeVault Key to decode it - Admin can rotate the NodeVault in Settings / NodeVault. The rotation procedure is a stepper: - Generate / Upload - same as at Setup - Migrate credentials: some of the creds may still be KMS - offer to migrate them - The new key is encrypted with current key (in browser) and fanned out to all nodes. Nodes decode and store the new key, keeping the old one - CP goes through each key and sends them to nodes to rekey. Nodes decode the cred, reencode it with new public and send them back to CP - All these workflows must be resilient and retry when something fails. Use DBOS to make it as reliable and idempotent as it gets Goal: reliable, provable way of Jaah not seeing and not being able to obtain access to client's credentials with all paths hermetic and auditable. ## Settled inputs (binding — realize, do not reopen) Full documents: BA PRD = Task 5273's `prd` artifact; Architecture = Task 5274's `architecture` artifact (`task_read` 5273 / 5274, then `task_read_artifact`). READ the architecture sections this child names — §2 crypto constructions, §3.2 data model, §4 interface contracts are PINNED and every child builds against them exactly. Binding decisions: D1 node-only (CP-consumed creds stay KMS) · D2 per-node identity key pairs (NIK) replace the CP temp key · D3 Jaah-hosted nodes included · D4 mandatory passphrase backup, no Jaah escrow · D5 later-joining nodes get the key automatically from a peer · D6 NodeVault is a plan parameter with per-org override · D7 OAuth2 excluded · D8 old keys kept until admin retires (refused while any credential uses it) · D9 passive-breach-proof + audited, no claim vs malicious Jaah · D11 plan off after setup ⇒ existing NV creds keep working, setup/rotation/migration/retire/new-NV frozen · D12 Test disabled for NV · D13 rogue-node enrollment is detectable (audit + node list), not impossible · E1 vendor `cryptography` into jaahd · E2 rotation chain-wraps new key under CURRENT key (K1: rotation does not recover from a leaked current key) · E3 DBOS for every workflow (carve-out from ADR-0074) · E4 AC-9.3 dropped (no admin notification on key delivery) · E5 node key files daemon-owned 0600 in a 0700 dir. Pinned crypto (arch §2): RSA-4096 e=65537 RSAES-OAEP SHA-256/MGF1-SHA-256 everywhere; AES-256-GCM 12-byte nonce; key hash = hex(sha256(SPKI DER)); envelope key id `nv:<hash>`; secret envelope = ADR-0137 v2 tier-2 unchanged; key blob `{v:1,k,alg,ek,n,ct}` AAD `nodevault.key|v1|<org_id>|<key_hash>|<recipient>`; backup PBKDF2-SHA256 600k. SECURITY SURFACE: this epic is credentials/crypto. Never log/checkpoint/return a secret value, private key, data key, passphrase or backup. The merge needs the security review lane or human approval per branching policy. Quality bar: "technically passes" is the floor. A build that satisfies the words but leaks key material to the CP, marks a step done before the node acknowledged it, or shows raw ids/stack traces to the user FAILS this child. ## This child — scope (HOW) Architecture child C8, credential-form + Nodes + Audit part (arch §3.6). apps/web: - Credential form (`pages/credentials/CredentialEditPage.tsx:324,613-624,1337-1345`): NodeVault checkbox fed by `GET /api/credentials/nodevault-state` and, for an existing row, `GET /api/credentials/{id}/nodevault-eligibility`; checked by default for a new credential when state=active and the type is eligible; unchecked + disabled with one-line reason otherwise (ineligible type, in-use consumer named, not set up, not in plan/frozen). When checked, `sealSecret` gets the seal key from `GET /api/nodevault/seal-key` instead of getCredentialSealKey. Unchecking clears secret fields and makes them required. Test button disabled with reason. List and detail show the key hash (short 12) for NV credentials. - Nodes page (`pages/Nodes.tsx:721`): NIK fingerprint line per node. - Audit view: a "NodeVault" filter. - Playwright request capture on credential save: no plaintext test value in any request. ## Acceptance criteria carried by this child (PRD, verbatim unless marked amended) - AC-5.1 (A8). Create and edit forms show a **NodeVault** checkbox. It is **checked by default** for a new credential when NodeVault is set up and the type is eligible. For an ineligible type, or before setup, it is unchecked and disabled with a one-line reason. *Verify:* create a generic API-key credential (checked) and an OAuth2 one (disabled, "OAuth2 credentials can't use NodeVault"). - AC-5.2. A secret typed into a NodeVault credential is sealed **in the browser** under the NodeVault public key (extending ADR-0137's browser sealing). The CP never receives the plaintext. *Verify:* Playwright request capture on save contains no plaintext test value. The DB envelope names the NodeVault key hash. - AC-5.5 (display). The credential list and detail show the key hash. - AC-5.8 (UI). Uncheck the box and see the secret fields cleared and required. Save, and the envelope names the KMS key. - AC-5.9 (UI). Test is disabled for NodeVault credentials with the reason "Testing runs on Jaah's servers, which can't open NodeVault credentials." - AC-3.1 (console half). The org's Nodes page shows a key fingerprint for each node, matching `jaah nodevault fingerprint`. - AC-9.2. Org Owners and Admins can see NodeVault events in the console without operator help. *Verify:* log in as org admin and filter Audit by NodeVault. Out of scope: Do NOT build Settings → NodeVault or the steppers; do NOT change KMS sealing for non-NV credentials; do NOT enable Test for NV. Epic out of scope (PRD §6, verbatim): Don't change encryption or consumption for CP-consumed credentials (forge/git, Jira, Slack, notify targets, cloud-launch AWS, org shared store, LLM, Bedrock, Stripe, embeddings, headscale, MFA stay on ADR-0137 KMS; consumers aren't re-plumbed to nodes). Don't touch tier 1 (CREDENTIAL_ENCRYPTION_KEY). Don't change the node-token mechanism (`node_credentials.py`, /etc/skynet/node.env), the login-seal keys (ADR-0133), or the `jaah-credential` broker names for git, GitHub, Bedrock and account credentials. No OAuth2 in NodeVault; don't alter `oauth2_tokens.py`. Don't build anything in 5246's area beyond the one NodeVault plan parameter. No hosted-node hardening and no "Jaah-hosted" label. No node-side Test button, node-side project env resolution, transcript redaction, BYOK/XKS or external secret references (F1–F8 deferred). No Jaah-held escrow of any NodeVault private key or backup. No logging of any secret value, private key, wrapped-key blob contents or backup passphrase anywhere (logs, activity events, DBOS, Slack, task summaries). No admin notification on key delivery (AC-9.3 dropped, E4). Done means: - Playwright: create API-key credential (checkbox checked by default, saves, request capture has no plaintext, DB envelope k = nv:<hash>); OAuth2 credential checkbox disabled with exact text; uncheck flow clears + requires secrets; Test disabled with exact text — cite. - Nodes page shows fingerprint equal to `jaah nodevault fingerprint` on a local node; Audit NodeVault filter shows NodeVault events — cite/screenshot. - Checkbox reason text and labels follow ui-copy-standards; no raw slugs shown. - `./dc check full` green; PR merged into develop through the security review lane / approval; rendered report cites file:line per AC and the observed output of every oracle above. Required checks: test-stack

Outcome

NodeVault checkbox and in-browser sealing on the credential form, key hash in list and detail, node identity fingerprints, Audit NodeVault filter. Full gate green; human security approval; #4685 merged. Deferred: frozen-plan seal-key vs editing NV secrets.

Pull request

Artifacts

Activity

  • Draft
  • Ready
  • Runner started
  • Awaiting response
  • Awaiting response
  • Runner resumed
  • Runner ended (done)