Open-source 2-of-3 policy-enforced threshold HSM: auto-signs cold→hot treasury refills under on-device Coldcard policy, no human in the loop. Includes the full operator manual + quick-start, the reference coordinator/signing code, and a signer-host bootstrap. No keys, seeds, or secrets — placeholders only. Live signet demo: https://multisighsm.mineracks.com Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
44 lines
3.6 KiB
Markdown
44 lines
3.6 KiB
Markdown
# Quick-start & operator checklist — mineracks multisig HSM
|
||
|
||
*The one-page version. Full detail + the security model: [Operator Manual](./OPERATOR-MANUAL.md). Do the
|
||
entire provisioning run on **signet/testnet first**; only move to mainnet after rehearsing a refill, a
|
||
failover, a policy change, and a restore-from-backup.*
|
||
|
||
## Provision (once)
|
||
- [ ] **1. Seeds** — generate **3 distinct** seeds, one per Coldcard (never clone one to three). Steel-backup each; store **geographically separated**.
|
||
- [ ] **2. Wallet** — build the `wsh(sortedmulti(2,k1,k2,k3))` descriptor; create the **watch-only** wallet on the node (receive `/0/*` + change `/1/*`); **record the descriptor offsite** (it's load-bearing for recovery).
|
||
- [ ] **3. Register** the 2-of-3 wallet on **each** Coldcard (so change is recognised as internal).
|
||
- [ ] **4. Policy** — per-device HSM JSON: `max_amount`, `per_period` (= ⅔ × global cap), `whitelist` (your hot-wallet deposit addresses), `period`, `wallet`, `must_log:true`.
|
||
- [ ] **4b. TOTP (only if using the surge tier)** — enrol the **same** `owner` secret on **all 3** Coldcards. **Production: the owner loads it directly over USB — never via the coordinator** (which only relays the live code at spend time).
|
||
- [ ] **5. ORDER (the #12 trap):** register wallet → enrol TOTP (4b) → **load policy → VERIFY the wallet survived on the device.**
|
||
- [ ] **6. HSM start** on each device (two-step on-device approval).
|
||
- [ ] **7. Coordinator** — set global cap `G`; whitelist; refill floor + amount; **round-robin the signer pair**; session secret `chmod 600` (**never in git**).
|
||
- [ ] **8. Placement** — 3 signers in **independent failure domains**, **≥1 offsite**. Never two keys behind one PSU/switch/host.
|
||
- [ ] **9. Verify** — within-policy refill signs · over-cap refused · off-list refused · velocity burst blocked at `G` · restore-from-backup rehearsed.
|
||
|
||
## Daily / on-call check
|
||
- [ ] **Quorum = 3/3** online, HSM-active, wallet-registered. *(Alert fires at exactly 2 — one more failure = frozen.)*
|
||
- [ ] Global velocity has headroom for the period; **no unexpected policy denials**.
|
||
- [ ] All 3 signer hosts + coordinator replica(s) up; USB/device health green.
|
||
|
||
## Sizing (memorise)
|
||
- Worst case if the **coordinator is compromised = 1.5 × per-device velocity `V`** (2 sigs burned per 1× value).
|
||
- **Set `V = ⅔ × G`** ⇒ worst case = your intended global cap `G`.
|
||
- **any-2-of-3** = 1.5× worst case **but** unattended failover · **2-auto + 1 human break-glass** = 1.0× worst case **but** no unattended failover. Pick deliberately.
|
||
|
||
## Incident cards
|
||
| Situation | Do this |
|
||
|---|---|
|
||
| **One** signer down | Run on the other two; restore + re-arm it; **do not drop a second.** |
|
||
| **Two** signers down | Spending is **frozen — safe, by design.** Restore one to resume. |
|
||
| Coordinator compromise suspected | Funds are bounded (no keys · whitelist confines destination · ≤ `1.5V`). Rotate host + secret; review denial/refill logs. |
|
||
| Large / exception spend | Use the **human break-glass** (3rd key / CKBunker), off the automated path. |
|
||
| Suspected single-key compromise | One key moves nothing. Rotate to a fresh 2-of-3; sweep funds under the old policy to the new wallet. |
|
||
|
||
## Never
|
||
- Never clone one seed to multiple devices · never co-locate two keys on a shared PSU/switch/host/hypervisor.
|
||
- Never take a **second** signer offline while one is already down.
|
||
- Never **load policy before registering** the multisig wallet (it can delete the wallet).
|
||
- Never put the coordinator **secret / seeds / descriptor in git**.
|
||
- Never hold **mainnet value on a single host running more than one signer** (no failure-domain independence).
|