Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ Firstmate's skills live in two separate places with different audiences:
- [docs/calm.md](docs/calm.md) - current Pi `/calm` behavior and supported presentation limits.
- [docs/voice-relay.md](docs/voice-relay.md) - the optional spoken interface: setup on both machines, measured round-trip cost, what a spoken answer may read, and what this build does not do yet.
- [docs/wedge-alarm.md](docs/wedge-alarm.md) - configure the active alert for an away-mode escalation delivery that gets stuck.
- [docs/bitwarden-rollout.md](docs/bitwarden-rollout.md) - the staged, gate-approved path to organization-owned Bitwarden custody for production and team credentials.
- [docs/tmux-backend.md](docs/tmux-backend.md) - current setup and limits for the tmux reference backend.
- [docs/herdr-backend.md](docs/herdr-backend.md) - current setup, safety boundaries, and limits for the experimental Herdr backend.
- [docs/zellij-backend.md](docs/zellij-backend.md) - current setup and limits for the experimental Zellij backend.
Expand Down
459 changes: 459 additions & 0 deletions bin/fm-bitwarden-ceremony.sh

Large diffs are not rendered by default.

125 changes: 125 additions & 0 deletions docs/bitwarden-rollout.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
# Bitwarden rollout for production and team credentials

This runbook is the staged path from temporary local-only credential custody to organization-owned Bitwarden custody for production and team credentials.
It is written for a normal operator: every routine action is a short checklist step, and engineering is only needed when a step says so.
Current access is preserved throughout: nothing is retired, rotated, or moved until the specific migration batch holding it is approved and verified.

## Custody boundaries this rollout does not change

- Local secrets stay in the hardened local vault (Automic Vault).
This rollout covers production and team credentials only; it never weakens, duplicates, or replaces hardened local access.
- Machine and unattended secrets are out of the initial migration.
Bitwarden Password Manager (human and team credentials) and Bitwarden Secrets Manager (machine and unattended access) are separate custody models with separate consequences.
Secrets Manager is deliberately not selected or enabled here; see the open decisions below.
- No secret value ever appears in this repo, in ceremony records, in task reports, or in chat.
Every record names credentials by label, owner, and collection only.

## Roles

- **Owner (captain)**: approves phase gates, migration batches, and retirements; holds one organization owner account.
- **Second owner/admin**: an independent person or independently held account that can recover the organization if the captain's account is lost.
- **Batch operator**: runs a migration batch's checklist; may be the captain or a delegate; never approves their own batch when dual control applies.

## Open decisions the captain must make before phase 1

These are recorded here because the rollout cannot choose them on anyone's behalf:

1. **Subscription and plan**: which Bitwarden plan and billing arrangement, chosen and purchased by the captain.
2. **Owner identities**: which two (or more) independent people or independently held accounts hold owner/admin recovery, so no single person is a recovery dependency.
3. **Retention and compliance**: any legal or contractual retention requirements that constrain export retention and deletion evidence.
4. **Machine-access architecture**: whether machine and unattended secrets later adopt Bitwarden Secrets Manager (bringing service accounts and access tokens that themselves become credentials to custody), stay on their current mechanisms, or use another store.
Until this is decided, machine and unattended secrets remain on their current access paths, and nothing in the interim may copy them into Password Manager items as a workaround.

## Credential class inventory

Inventory classes and owners before the first batch; never enumerate or record secret values while doing it.

| Class | Examples | Initial migration? | Why |
| --- | --- | --- | --- |
| Human interactive | a person's own logins to production consoles and forges | yes | core Password Manager fit |
| Shared team | credentials several people legitimately share | yes | collections give least-privilege sharing |
| Production service | database and service passwords humans hold today | yes, human copies only | the human-held copy moves; the deployed configuration is untouched |
| CI/CD tokens | pipeline and deploy tokens | deferred | machine-access decision above owns their target |
| Break-glass | emergency access used when normal paths fail | yes, last batch, dual control | highest blast radius; migrate only after the process is proven on lower-risk batches |
| Local development | developer-machine secrets | no | stays in the hardened local vault |
| Machine/unattended | service-to-service secrets no human types | no | Secrets Manager decision not made |

## Phases and gates

Each phase has an entry gate; do not start a phase until the previous phase's exit condition is met and the captain has approved moving on.

### Phase 0 - decisions and inventory (no Bitwarden footprint)

- Captain resolves the open decisions above.
- Inventory the credential classes and owners (labels only).
- Exit: decisions recorded, inventory exists, captain approves phase 1.

### Phase 1 - organization hardening (no credentials migrated)

- Captain creates the organization on the chosen plan.
- Both owner/admin recovery paths are established and independently tested: each owner proves they can sign in, and account recovery (or an equivalent second path) is confirmed before any credential arrives.
- Hardware-backed MFA is enrolled on every privileged account, with a documented MFA-loss recovery that does not depend on a single person.
- Collections and groups are created least-privilege: one collection per team or system boundary, no default all-access group, admin roles held only by the named owners.
- Joiner/mover/leaver procedure is written into the organization's own documentation: joiners get group membership only, movers change groups not items, leavers lose access by group removal and trigger rotation of anything they could have exported.
- Exit: a second owner has demonstrated recovery access, MFA is verified on all privileged accounts, and the captain approves the pilot.

### Phase 2 - pilot batch (lowest-risk shared team credentials)

- Run one full migration ceremony (below) on a small, low-risk batch.
- Run one full recovery drill (below) while the stakes are low.
- Exit: pilot batch verified, drill passed, captain approves production batches.

### Phase 3 - production batches

- Migrate remaining in-scope classes in captain-approved batches, riskiest last.
- Break-glass credentials move only under dual control: one person moves, a different person verifies, the captain approves.
- Exit: all in-scope classes migrated or explicitly deferred with a recorded reason.

### Phase 4 - routine operation

- Joiner/mover/leaver runs as written; drills run on the recovery cadence below; deferred classes wait on their owning decision.

## Migration ceremony (per batch)

Every batch follows the same ordered ceremony, and its auditable no-secret record is kept with `bin/fm-bitwarden-ceremony.sh` (its `--help` owns the record format and step gates; the tool validates structure and status only and must never be given a secret value):

1. **Init and plan**: initialize the batch record; register every item as label, owner, and target collection.
2. **Preflight**: confirm each item's current custody still works, its target collection exists with the right group access, and its owner is available for verification.
3. **Captain approval**: the captain approves this exact batch; the approval is recorded with the approver's identity.
4. **Move**: the owner (or batch operator, with the owner for dual control) creates each item in Bitwarden by signing into both sides directly; values pass through no intermediate file, chat, or tool.
5. **Verify**: each item's intended users prove real access through Bitwarden (an actual sign-in or connection using the migrated item), and anyone who should not see it confirms they cannot.
6. **Rollback point**: if verification fails, the old custody is still intact; fix or remove the Bitwarden item and re-verify - nothing has been lost.
7. **Retire old custody**: only after verification, delete or invalidate the old copy; where exposure during handling is suspected, rotate instead of merely deleting.
8. **Record**: the completed batch record (labels, owners, collections, dates, approver - never values) is the completion evidence.

The record tool refuses to mark retirement before verification and recorded approval, so a batch cannot skip its own safety order.
It also refuses to read any record it cannot fully validate - a hand-edited, truncated, or misfiled history is never reported as progress - and its `--help` owns the exact record rules.
When a record is refused, correct it back to its last valid prefix (delete only the trailing lines that are not yet true) or quarantine it outside the record directory and start a new batch; never edit it into a shape that merely satisfies the tool.

## Encrypted export and recovery drills

Design only until phase 2; no export is created outside a drill or the operational cadence.

- **What**: the organization's encrypted export (password-protected, account-independent format), never a plaintext export, with no plaintext staging step at any point.
- **Custody**: stored offline on dedicated media, at least two copies in separate physical locations.
- **Split ownership**: the export file and its encryption passphrase are held by different people, so neither holder can read it alone; the passphrase itself is written down once per holder and stored with their personal recovery material, not in any vault the export is meant to recover.
- **Restore verification**: a drill is passed only when a restore into a scratch client proves a sampled item actually opens; an unverified export is treated as no export.
- **Rotation after exposure**: if an export or passphrase may have been exposed, rotate the credentials it contained, not just the export.
- **Cadence**: refresh the export and run a restore drill at least quarterly, and immediately after any owner/admin change.
- **Retention and deletion**: superseded exports are destroyed (media erased or physically destroyed), and the drill evidence records export date, holders, restore result, and destruction of the superseded copy - never contents.

Drill evidence template (copy per drill, no secret values):

```
drill: <YYYY-MM-DD>
export-created: <YYYY-MM-DD> by <label>
copies: <location-label-1>, <location-label-2>
passphrase-holder: <label> (distinct from export holder: <label>)
restore-verified: <YYYY-MM-DD> by <label>, sampled item opened: yes/no
superseded-copy-destroyed: <YYYY-MM-DD> by <label>
notes: <free text, labels only>
```

## What this runbook never authorizes

Creating accounts or organizations, choosing or purchasing a plan, inviting users, changing billing, reading or moving secret values, changing production access, rotating credentials, or retiring old custody all require the captain's direct participation or explicit approval at the gate that names them.
4 changes: 4 additions & 0 deletions docs/documentation-audiences.json
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,10 @@
"path": "docs/arm-pretool-check.md",
"audience": "maintainer-architecture"
},
{
"path": "docs/bitwarden-rollout.md",
"audience": "operator-current"
},
{
"path": "docs/calm-mode-feasibility.md",
"audience": "maintainer-verification"
Expand Down
1 change: 1 addition & 0 deletions docs/scripts.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ The shared no-mistakes gate refusal for fleet lifecycle entrypoints is summarize
| `fm-public-followup.sh` | Reconcile and deliver typed public commitments, then rechain or explicitly retire their retained loops |
| `fm-public-followup-emit.sh` | Report one typed terminal work result into the home that owes the public reply |
| `fm-inbox.sh` | The captain's out-of-band capture surface: queue a note, dictate one, read status, ask a side question |
| `fm-bitwarden-ceremony.sh` | No-secret structure/status validator for Bitwarden migration-batch ceremony records ([bitwarden-rollout.md](bitwarden-rollout.md)) |
| `fm-voice-relay.py` | Hold the spoken conversation on this host, answer from the records, and hand real work to `fm-inbox.sh` ([voice-relay.md](voice-relay.md)) |
| `fm-voice-client.py` | The laptop end of the spoken interface: capture, playback, and turn timing over SSH; audio devices unverified |
| `fm_voice_frame.py` | The wire format both machines share, copied to the laptop beside the client |
Expand Down
Loading
Loading