feat: pki rotation commands + operator runbooks#121
Merged
Conversation
Add the final PKI lifecycle slice (epic #104, ADR-0024): rotation/recovery tooling and operator runbooks. CLI: - inforge pki rotate <env> <name> --leaf|--intermediate <scope>|--root - --leaf documents leaf renewal (short-TTL; expiry is revocation) - --intermediate re-mints one scope's intermediate from the cold root (offline); invisible to other regions via the regional boundary - --root runs a dual-root overlap: mint a new cold root, retain the old, re-sign every intermediate from the new root with keys preserved so live leaves keep verifying; --finalize drops the old root - inforge pki recover-intermediate <env> <name> <scope>: compromise recovery (fresh-key re-mint + forced immediate host re-projection) The cold-root custody split is preserved: intermediate/root ops require the offline INFORGE_PKI_ROOT_KEY; --root verifies the caller holds the current root before rotating. internal/pki: - ReSignIntermediate re-issues an intermediate cert over its existing public key signed by a new root (key preserved) - PKI gains PreviousRoots + PreviousIntermediates (dual-root overlap state) and RootCerts() (active + retained roots) Tests prove the overlap property: the same live leaf verifies under both the old and the new root during the window. Runbooks under website/docs/runbooks/ (add a region, rotate a leaf, rotate an intermediate, rotate the root, recover a compromised intermediate), linked from cli/pki.md and ADR-0024. The root runbook calls out that mesh-root rotation is cross-repo coordination — root-anchoring consumers (the daemon fleet) must trust both roots before the old one is retired. Refs #110
- Guard intermediate rotation/recovery against an active root overlap: reissueIntermediate refuses to run while previousRoots is populated, since rolling the intermediate key mid-overlap would orphan the old-key leaves the dual-root overlap is meant to keep verifying. - Custody-gate the --finalize path like the begin-overlap path: dropping the old root now requires INFORGE_PKI_ROOT_KEY, so CI or a stale checkout cannot retire the old root before consumers have migrated. - Factor the shared CA-template into pki.intermediateTemplate (used by both GenerateIntermediate and ReSignIntermediate) so the intermediate's constraints can't drift across a root rotation. - Factor the root-decrypt -> GenerateIntermediate -> encrypt-to-CI custody sequence into mintScopeIntermediate, shared by the first-mint and re-mint paths so the offline-identity decrypt, CN convention, and CI recipient live in one place. - Runbooks: note the finalize custody gate and the mid-overlap block on intermediate rotation/recovery. Refs #110
Second code-review round on the rotation slice: - runPkiIntermediate (first-mint of a NEW scope) now refuses while a root overlap is active, matching the re-mint guard. Mid-overlap the cold root is the new root, so a first-mint would chain only to the new root — invisible to consumers still anchored on the old one — with no PreviousIntermediates counterpart. reissueIntermediate's own 'mint one with inforge pki intermediate' hint previously steered operators straight into this gap. - Extract requireRootCustody: the begin-overlap and finalize paths shared a byte-identical offline-identity decrypt gate; factoring it prevents the two security checks from drifting apart. - Broaden the no-remint-during-overlap rule to cover first-mint; note the block in the add-region runbook. Refs #110
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Final slice of the PKI epic (#104, ADR-0024): rotation/recovery tooling + operator runbooks. Closes the lifecycle started by #105–#109/#120.
CLI
inforge pki rotate <env> <name>— exactly one of:--leaf— documents leaf renewal (short-TTL leaves rotate viainforge pki renew; expiry is revocation, no CRL/OCSP). Informational, no mutation.--intermediate <scope>— re-mints one scope's intermediate from the cold root (offline, needsINFORGE_PKI_ROOT_KEY). Invisible to other regions via the mesh's regional boundary.--root— dual-root overlap: mints a new cold root, retains the old one, and re-signs every intermediate from the new root with keys preserved (live leaves keep verifying).--root --finalizedrops the old root once consumers have converged.inforge pki recover-intermediate <env> <name> <scope>— compromise recovery: same fresh-key re-mint, but a no-overlap, act-now posture (immediate renew + forced host re-projection).Custody split preserved: only the holder of
INFORGE_PKI_ROOT_KEYcan sign with the root;--rootverifies the caller holds the current root before rotating. CI never gains root-signing ability.internal/pki
ReSignIntermediate— re-issues an intermediate cert over its existing public key, signed by a new root (key preserved → existing leaves stay valid).PKIgainsPreviousRoots+PreviousIntermediates(overlap state, cleared by--finalize) andRootCerts()(the anchor set for root-anchoring consumers during overlap).Design note
The merged #107 amendment made the mesh anchor on per-scope intermediate bundles, not the root. So the runbooks state the mechanics accurately:
Runbooks
New pages under
website/docs/runbooks/(add a region, rotate a leaf, rotate an intermediate, rotate the root, recover a compromised intermediate), linked fromcli/pki.mdand ADR-0024. The root runbook calls out the cross-repo coordination caveat: mesh-root rotation requires a daemon-fleet update before the old root is retired.Acceptance
go build ./...,go test -race ./...,golangci-lint run ./..., gofmt — all clean.Refs #110