Skip to content

feat(agent): back up the agent CA keys in the database, under a passphrase - #192

Merged
mastacontrola merged 2 commits into
masterfrom
feat/agent-ca-escrow
Nov 10, 2026
Merged

mastacontrola merged 2 commits into
masterfrom
feat/agent-ca-escrow

Conversation

@mastacontrola

Copy link
Copy Markdown
Member

Problem

The fog-agent CA keys lived only in pki/. A reinstall that lost the folder stopped setup with E_AGENT_ROOT_MISSING. The only ways out were a file backup or --new-agent-root, which forces every enrolled agent to re-enroll.

Change

  • Backup record (AgentCaEscrow, api/lib/agent-ca-escrow.js): root.key, root.pem, agent-ca.key, agent-ca.pem, encrypted with AES-256-GCM. The key comes from scrypt (N 2^17, r 8, p 1, maxmem 256 MiB). The two fingerprints are the AAD. open checks version, KDF bounds, iv and tag length before scrypt runs. No route returns the record (GET /api/v1/agentcaescrow is 403).
  • Passphrase: 6 words from the vendored EFF large wordlist (SHA-256 checked), or a supplied one of 20+ characters. It is printed once when generated, and never written to a file, Setting, log or audit row. Answers mode never generates one.
  • Setup (tools/setup/pki.js): saves the backup, replaces a stale one, and restores from it when pki/ has no root. A restore requires the backup's root and agent CA to match the recorded ones (new Setting FOG_AGENT_CA_FINGERPRINT), so an old backup cannot cut off agents enrolled since. E_AGENT_ROOT_MISMATCH never restores.
  • npm run agent-ca -- backup | restore | status for an existing install. Restore refuses every bad state before it asks for the passphrase.
  • Audit: type agent.ca, authSource setup, for save, restore, and each wrong passphrase (ADR 0003 updated).
  • Installer fix: setup dropped nothing from the require cache, so a re-run over an existing config/local.js ran its later steps on the old file. It now reads the old file once and drops it.
  • The fog-agent wire is unchanged: nothing under api/controllers/agent/, api/hooks/agent-tls/, or the agent routes.

Test

  • npm test: 484 passing. New test/lib/agent-ca-escrow.test.js and test/setup/pki-escrow.test.js: round-trip, wrong passphrase, every tamper case, KDF bounds, refusals without a prompt, one denied row per wrong try, no passphrase in audit text.
  • npm run test:install: the smoke test now uses its own PKI folder, empties it, re-runs the installer, checks the root is restored with the same fingerprint, and checks the installer output holds no passphrase.
  • Gates proven red: a broken AAD fails the round-trip test; a prompt before the CA-file check fails the two "without asking" tests.
  • Not covered by CI: the interactive prompts of npm run setup (they need a terminal), as for the other installer prompts.

🤖 Generated with Claude Code

…hrase

A reinstall that lost pki/ stopped setup with E_AGENT_ROOT_MISSING, and the
only ways out were a file backup or --new-agent-root (every agent
re-enrolls). Now a database backup plus one passphrase restores the CA.

- AgentCaEscrow: the four CA files (root and agent CA, key and cert),
  encrypted with AES-256-GCM under a scrypt key (N 2^17, r 8, p 1). The
  fingerprints are the AAD. No route returns the record (403).
- Passphrase: 6 words from the EFF large wordlist (vendored), or a
  supplied one of 20+ characters. Shown once, never stored or logged.
  Answers mode never generates one.
- setupPki saves the backup, replaces a stale one, and restores from it
  when pki/ has no root. A restore needs the recorded root and the
  recorded agent CA (new Setting FOG_AGENT_CA_FINGERPRINT), so an old
  backup cannot cut off agents enrolled since.
- npm run agent-ca -- backup | restore | status, for an existing install.
- Audit rows of type agent.ca (authSource setup) for save, restore and
  each wrong passphrase.
- Fix: setup now drops the old config/local.js from the require cache
  after it reads it, so later steps load the file it writes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@fog-workflows
fog-workflows Bot enabled auto-merge November 10, 2026 19:20
@fog-workflows
fog-workflows Bot added this pull request to the merge queue Nov 10, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Nov 10, 2026
…cond boundary

The test counted exactly one stamped server.pem. The first ensure in the
test can already stamp the fixture's pair, and two stamps in the same
second share a name, so the count was 1 or 2 depending on the clock. It
failed the merge queue for #192 on Node 26. It now checks that the
certificate changed and that an old pair was kept aside.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@mastacontrola
mastacontrola added this pull request to the merge queue Nov 10, 2026
Merged via the queue into master with commit 43d8c50 Nov 10, 2026
5 checks passed
@mastacontrola
mastacontrola deleted the feat/agent-ca-escrow branch November 10, 2026 20:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant