Security playbook: what to do if the operator PC is compromised and the fleet SSH key is exposed #31

Merged
john merged 4 commits from fm/fm-ssh-key-compromise-playbook into main 2026-09-24 10:17:08 +00:00
Owner

What this adds

docs/operator-pc-compromise.md is an operational playbook for the case where the operator's PC is compromised and the fleet SSH key is exposed. It is written for someone following it under stress, possibly from another machine, while an attacker may still hold a valid key. It is grounded in this fleet's real hosts, key paths and trust paths, which were read from the pyr0-dev-infra repo. It cites secret names only, never values.

It covers:

  • a first-ten-minutes action list
  • ordered containment with abort conditions
  • rotation across every host, including the bootstrap problem
  • what else shares the compromised machine's trust (forge, CI runners, service tokens, backups)
  • establishing what the attacker actually reached
  • the partial-rotation failure state

It follows the standing rule: build and verify the replacement access before destroying the old.

How it was validated

The no-mistakes pipeline passed. Its review round fixed the key-handling order in two paths, the restic rotation order, the web2 token re-seed, and the age-key prerequisite, and its test round now proves the age key against the committed ops.sops.env. Those are the three no-mistakes(...) commits. The run was made on a head that still carried an unrelated unpushed local commit. The worker replayed the fix commits onto a clean base and checked that the result is content-identical except for that commit's removal. The documentation audience check is green.

Author's commit message

Add the operator PC compromise playbook for an exposed fleet SSH key

Ground every host, key, trust path, and command in the pyr0-dev-infra
facts: the john identity bucket, the prove-before-destroy rotation
loop with three bootstrap paths (CI converge key, provider console,
trusted old-key copy), presumptive-vs-evidence-gated rotation rings,
the Loki/journald evidence trail with its integrity limits, and the
honest gaps that need captain decisions. Registered in the audience
inventory as operator-current and routed from the README.

Files

README.md                         |   1 +
 docs/documentation-audiences.json |   4 +
 docs/operator-pc-compromise.md    | 380 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 385 insertions(+)

Open

Nothing. This is the firstmate repo, so there is no Plane story.

## What this adds `docs/operator-pc-compromise.md` is an operational playbook for the case where the operator's PC is compromised and the fleet SSH key is exposed. It is written for someone following it under stress, possibly from another machine, while an attacker may still hold a valid key. It is grounded in this fleet's real hosts, key paths and trust paths, which were read from the pyr0-dev-infra repo. It cites secret names only, never values. It covers: - a first-ten-minutes action list - ordered containment with abort conditions - rotation across every host, including the bootstrap problem - what else shares the compromised machine's trust (forge, CI runners, service tokens, backups) - establishing what the attacker actually reached - the partial-rotation failure state It follows the standing rule: build and verify the replacement access before destroying the old. ## How it was validated The no-mistakes pipeline passed. Its review round fixed the key-handling order in two paths, the restic rotation order, the web2 token re-seed, and the age-key prerequisite, and its test round now proves the age key against the committed `ops.sops.env`. Those are the three `no-mistakes(...)` commits. The run was made on a head that still carried an unrelated unpushed local commit. The worker replayed the fix commits onto a clean base and checked that the result is content-identical except for that commit's removal. The documentation audience check is green. ## Author's commit message Add the operator PC compromise playbook for an exposed fleet SSH key Ground every host, key, trust path, and command in the pyr0-dev-infra facts: the john identity bucket, the prove-before-destroy rotation loop with three bootstrap paths (CI converge key, provider console, trusted old-key copy), presumptive-vs-evidence-gated rotation rings, the Loki/journald evidence trail with its integrity limits, and the honest gaps that need captain decisions. Registered in the audience inventory as operator-current and routed from the README. ## Files ``` README.md | 1 + docs/documentation-audiences.json | 4 + docs/operator-pc-compromise.md | 380 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 385 insertions(+) ``` ## Open Nothing. This is the firstmate repo, so there is no Plane story.
Ground every host, key, trust path, and command in the pyr0-dev-infra
facts: the john identity bucket, the prove-before-destroy rotation
loop with three bootstrap paths (CI converge key, provider console,
trusted old-key copy), presumptive-vs-evidence-gated rotation rings,
the Loki/journald evidence trail with its integrity limits, and the
honest gaps that need captain decisions. Registered in the audience
inventory as operator-current and routed from the README.
no-mistakes(test): Prove age key against committed ops.sops.env, not bootstrap
All checks were successful
CI / Test coverage guard (pull_request) Successful in 1m12s
CI / Behavior portable parallel 1 (pull_request) Successful in 3m59s
CI / Behavior portable parallel 2 (pull_request) Successful in 3m13s
CI / Lint shell scripts (pull_request) Successful in 5m43s
CI / Behavior portable serial 4 (pull_request) Successful in 9m14s
CI / Behavior portable serial 1 (pull_request) Successful in 14m24s
CI / Repo invariants (pull_request) Successful in 5s
CI / Behavior portable serial 3 (pull_request) Successful in 14m5s
CI / Behavior portable serial 2 (pull_request) Successful in 17m50s
CI / Behavior tests (Herdr) (pull_request) Successful in 7m47s
67f01f85a5
john merged commit 21c211716b into main 2026-09-24 10:17:08 +00: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
john/firstmate!31
No description provided.