@zincapp/znvault-cli 4.22.1 → 4.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/lmk-ceremony.d.ts +3 -0
- package/dist/commands/lmk-ceremony.d.ts.map +1 -0
- package/dist/commands/lmk-ceremony.js +597 -0
- package/dist/commands/lmk-ceremony.js.map +1 -0
- package/dist/commands/lmk-escrow.d.ts.map +1 -1
- package/dist/commands/lmk-escrow.js +73 -5
- package/dist/commands/lmk-escrow.js.map +1 -1
- package/dist/commands/lmk-preflight.d.ts +3 -0
- package/dist/commands/lmk-preflight.d.ts.map +1 -0
- package/dist/commands/lmk-preflight.js +117 -0
- package/dist/commands/lmk-preflight.js.map +1 -0
- package/dist/commands/lmk-restore-drill.d.ts +3 -0
- package/dist/commands/lmk-restore-drill.d.ts.map +1 -0
- package/dist/commands/lmk-restore-drill.js +160 -0
- package/dist/commands/lmk-restore-drill.js.map +1 -0
- package/dist/commands/lmk.d.ts.map +1 -1
- package/dist/commands/lmk.js +4 -0
- package/dist/commands/lmk.js.map +1 -1
- package/dist/index.js +35 -2
- package/dist/index.js.map +1 -1
- package/dist/lib/bsk-source.d.ts +21 -0
- package/dist/lib/bsk-source.d.ts.map +1 -0
- package/dist/lib/bsk-source.js +89 -0
- package/dist/lib/bsk-source.js.map +1 -0
- package/dist/lib/ceremony/gates.d.ts +126 -0
- package/dist/lib/ceremony/gates.d.ts.map +1 -0
- package/dist/lib/ceremony/gates.js +270 -0
- package/dist/lib/ceremony/gates.js.map +1 -0
- package/dist/lib/ceremony/system.d.ts +36 -0
- package/dist/lib/ceremony/system.d.ts.map +1 -0
- package/dist/lib/ceremony/system.js +176 -0
- package/dist/lib/ceremony/system.js.map +1 -0
- package/dist/lib/ceremony/workspace.d.ts +54 -0
- package/dist/lib/ceremony/workspace.d.ts.map +1 -0
- package/dist/lib/ceremony/workspace.js +98 -0
- package/dist/lib/ceremony/workspace.js.map +1 -0
- package/dist/lib/config/index.d.ts +1 -1
- package/dist/lib/config/index.d.ts.map +1 -1
- package/dist/lib/config/index.js +1 -1
- package/dist/lib/config/index.js.map +1 -1
- package/dist/lib/config/profile.d.ts +14 -0
- package/dist/lib/config/profile.d.ts.map +1 -1
- package/dist/lib/config/profile.js +22 -0
- package/dist/lib/config/profile.js.map +1 -1
- package/dist/lib/config.d.ts +1 -1
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +1 -1
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/db/index.d.ts +9 -1
- package/dist/lib/db/index.d.ts.map +1 -1
- package/dist/lib/db/index.js +9 -0
- package/dist/lib/db/index.js.map +1 -1
- package/dist/lib/db/key-lifecycle.d.ts +86 -0
- package/dist/lib/db/key-lifecycle.d.ts.map +1 -0
- package/dist/lib/db/key-lifecycle.js +182 -0
- package/dist/lib/db/key-lifecycle.js.map +1 -0
- package/dist/lib/db/lmk-escrow.d.ts +18 -0
- package/dist/lib/db/lmk-escrow.d.ts.map +1 -1
- package/dist/lib/db/lmk-escrow.js +25 -0
- package/dist/lib/db/lmk-escrow.js.map +1 -1
- package/dist/lib/db/preflight.d.ts +42 -0
- package/dist/lib/db/preflight.d.ts.map +1 -0
- package/dist/lib/db/preflight.js +165 -0
- package/dist/lib/db/preflight.js.map +1 -0
- package/dist/lib/kcv.d.ts +34 -0
- package/dist/lib/kcv.d.ts.map +1 -0
- package/dist/lib/kcv.js +89 -0
- package/dist/lib/kcv.js.map +1 -0
- package/dist/lib/lmk-escrow-restore.d.ts +6 -2
- package/dist/lib/lmk-escrow-restore.d.ts.map +1 -1
- package/dist/lib/lmk-escrow-restore.js +1 -1
- package/dist/lib/lmk-escrow-restore.js.map +1 -1
- package/dist/lib/lmk-escrow.d.ts +14 -1
- package/dist/lib/lmk-escrow.d.ts.map +1 -1
- package/dist/lib/lmk-escrow.js +5 -1
- package/dist/lib/lmk-escrow.js.map +1 -1
- package/dist/lib/preflight.d.ts +93 -0
- package/dist/lib/preflight.d.ts.map +1 -0
- package/dist/lib/preflight.js +129 -0
- package/dist/lib/preflight.js.map +1 -0
- package/dist/lib/restore-drill.d.ts +73 -0
- package/dist/lib/restore-drill.d.ts.map +1 -0
- package/dist/lib/restore-drill.js +185 -0
- package/dist/lib/restore-drill.js.map +1 -0
- package/dist/lib/sentinel-client.d.ts +26 -0
- package/dist/lib/sentinel-client.d.ts.map +1 -0
- package/dist/lib/sentinel-client.js +165 -0
- package/dist/lib/sentinel-client.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lmk-ceremony.d.ts","sourceRoot":"","sources":["../../src/commands/lmk-ceremony.ts"],"names":[],"mappings":"AAyBA,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,WAAW,CAAC;AAoLzC,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAygBjE"}
|
|
@@ -0,0 +1,597 @@
|
|
|
1
|
+
// Path: znvault-cli/src/commands/lmk-ceremony.ts
|
|
2
|
+
//
|
|
3
|
+
// `znvault superadmin lmk escrow ceremony` — the escrow ceremony as a command
|
|
4
|
+
// rather than a script.
|
|
5
|
+
//
|
|
6
|
+
// WHY A COMMAND. A script goes stale, gets edited without a trace, and if it
|
|
7
|
+
// dies halfway it leaves nothing behind. A command is versioned, released and
|
|
8
|
+
// tested — and, more to the point, it can write to `key_lifecycle_operations`
|
|
9
|
+
// (zn-vault migration 093) who ran the ceremony, when, and how far it got.
|
|
10
|
+
//
|
|
11
|
+
// WHAT IT DOES AND DOES NOT DO. It owns the state machine and the gates. It
|
|
12
|
+
// does NOT copy key material for you: fetching the legacy BSK, the mini-CA and
|
|
13
|
+
// the Sentinel configuration is `ssh` and `scp`, and wrapping that in a CLI
|
|
14
|
+
// would add a large, fragile surface for no safety. The operator performs those
|
|
15
|
+
// copies into the RAM workspace; the command refuses to advance until it has
|
|
16
|
+
// verified the result.
|
|
17
|
+
//
|
|
18
|
+
// That division is the honest one. The command can only guarantee what it can
|
|
19
|
+
// check, and what it can check is exactly where a ceremony fails silently:
|
|
20
|
+
// a workspace that is not really in RAM, a key that is not really the right
|
|
21
|
+
// key, a device that is not really the copy you think.
|
|
22
|
+
import { hostname, userInfo } from 'node:os';
|
|
23
|
+
import { readFileSync } from 'node:fs';
|
|
24
|
+
import { resolve } from 'node:path';
|
|
25
|
+
import * as output from '../lib/output.js';
|
|
26
|
+
import { LocalDBClient, isLocalDbAvailable } from '../lib/db/index.js';
|
|
27
|
+
import { KeyLifecycleOperations } from '../lib/db/key-lifecycle.js';
|
|
28
|
+
import { getVersion } from '../lib/version.js';
|
|
29
|
+
import { assertCeremonyIsOurs, assertCopyLabel, assertKeyMatchesEnvelope, assertKeyMatchesExpectedKcv, assertNoOtherCeremonyRunning, assertNotTheOtherCopy, assertRouteComplete, assertTransitionAllowed, } from '../lib/ceremony/gates.js';
|
|
30
|
+
import { readAndVerifyLmkEscrowBundle } from '../lib/lmk-escrow.js';
|
|
31
|
+
import { assertRamBacked, assertTornDown, CEREMONY_MOUNT_POINT } from '../lib/ceremony/workspace.js';
|
|
32
|
+
import { createRamWorkspace, describeDevice, destroyRamWorkspace, indexingEnabled, listEscrowDevices, } from '../lib/ceremony/system.js';
|
|
33
|
+
/**
|
|
34
|
+
* Minimum vault release whose schema this command relies on (migration 093).
|
|
35
|
+
*
|
|
36
|
+
* 1.68.0 and not 1.67.x: migration 093 is not in 1.67.1. `schemaPresent()` is
|
|
37
|
+
* the check that actually guards — this is what the record and the refusal
|
|
38
|
+
* MESSAGE claim, and a message that names a release which does not carry the
|
|
39
|
+
* table sends the reader to look in the wrong place.
|
|
40
|
+
*/
|
|
41
|
+
const MIN_RELEASE = '1.68.0';
|
|
42
|
+
const WORKSPACE_MB = 64;
|
|
43
|
+
function requireLocalDb() {
|
|
44
|
+
if (!isLocalDbAvailable()) {
|
|
45
|
+
throw new Error('The ceremony is local-only: it needs direct PostgreSQL access to read the ' +
|
|
46
|
+
'root-key envelopes and to record the operation. Set DATABASE_URL (an SSH ' +
|
|
47
|
+
'tunnel to the cluster is fine) and try again.');
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/** Open the lifecycle store, refusing clearly if the schema is not deployed. */
|
|
51
|
+
async function lifecycle() {
|
|
52
|
+
const ops = new KeyLifecycleOperations();
|
|
53
|
+
if (!(await ops.schemaPresent())) {
|
|
54
|
+
await ops.close();
|
|
55
|
+
throw new Error('This deployment has no key_lifecycle_operations table, so a ceremony cannot ' +
|
|
56
|
+
`be recorded. It arrives with zn-vault migration 093 (release ${MIN_RELEASE}). ` +
|
|
57
|
+
'Refusing to run an unrecorded ceremony — the record is the point.');
|
|
58
|
+
}
|
|
59
|
+
return ops;
|
|
60
|
+
}
|
|
61
|
+
/** The in-flight ceremony, or a clear refusal. */
|
|
62
|
+
async function requireActive(ops) {
|
|
63
|
+
const active = await ops.active();
|
|
64
|
+
if (active === null) {
|
|
65
|
+
throw new Error("No ceremony is in progress. Start one with 'ceremony start'.");
|
|
66
|
+
}
|
|
67
|
+
if (active.kind !== 'ESCROW_SNAPSHOT') {
|
|
68
|
+
throw new Error(`The operation in progress is a ${active.kind}, not a ceremony. Do not run a ` +
|
|
69
|
+
'ceremony alongside it: the bundle and the inventory would describe ' +
|
|
70
|
+
'different moments.');
|
|
71
|
+
}
|
|
72
|
+
// Every fact the gates judge is gathered on THIS machine.
|
|
73
|
+
assertCeremonyIsOurs(active, hostname());
|
|
74
|
+
return active;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Move to the next phase, refusing any move the route does not allow.
|
|
78
|
+
*
|
|
79
|
+
* The gate lives HERE rather than in each subcommand because an audit found the
|
|
80
|
+
* subcommands each jumped to a fixed phase from wherever the ceremony happened
|
|
81
|
+
* to be — so `start` then `teardown` then `finish` recorded a COMPLETED
|
|
82
|
+
* ceremony that had done nothing at all. One choke point, and every caller
|
|
83
|
+
* passes through it.
|
|
84
|
+
*/
|
|
85
|
+
async function advance(ops, active, phase, detail) {
|
|
86
|
+
assertTransitionAllowed(active.phase, phase);
|
|
87
|
+
await ops.advance({
|
|
88
|
+
operationId: active.operationId,
|
|
89
|
+
expectedEpoch: active.epoch,
|
|
90
|
+
phase,
|
|
91
|
+
nodeId: hostname(),
|
|
92
|
+
...(detail ? { detail } : {}),
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* What was recorded for the most recent event of this phase.
|
|
97
|
+
*
|
|
98
|
+
* Reading the ceremony's OWN append-only record is the point: it is the one
|
|
99
|
+
* source in reach that the operator cannot retype at the moment it is checked.
|
|
100
|
+
*/
|
|
101
|
+
async function recordedDetail(ops, operationId, phase) {
|
|
102
|
+
const history = await ops.history(operationId);
|
|
103
|
+
// The LAST event for the phase: `material` repeats, and a re-check supersedes
|
|
104
|
+
// what it re-checked.
|
|
105
|
+
const match = [...history].reverse().find((event) => event.phase === phase);
|
|
106
|
+
return match?.detail ?? null;
|
|
107
|
+
}
|
|
108
|
+
function recordedString(detail, key) {
|
|
109
|
+
const value = detail?.[key];
|
|
110
|
+
return typeof value === 'string' ? value : null;
|
|
111
|
+
}
|
|
112
|
+
/** The phase a copy is recorded under. */
|
|
113
|
+
function phaseForCopy(copy) {
|
|
114
|
+
return copy === 'A' ? 'write-a' : 'write-b';
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* The workspace device this ceremony proved to be RAM-backed.
|
|
118
|
+
*
|
|
119
|
+
* @throws if no workspace was ever recorded — which means there is nothing to
|
|
120
|
+
* tear down and the ceremony is not where the caller thinks it is.
|
|
121
|
+
*/
|
|
122
|
+
async function recordedWorkspaceDevice(ops, operationId) {
|
|
123
|
+
const device = recordedString(await recordedDetail(ops, operationId, 'workspace'), 'device');
|
|
124
|
+
if (device === null) {
|
|
125
|
+
throw new Error('This ceremony has no recorded workspace, so there is no device that was ' +
|
|
126
|
+
'ever proven to be RAM-backed. Nothing to tear down.');
|
|
127
|
+
}
|
|
128
|
+
return device;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Refuse a path that is not inside the RAM workspace.
|
|
132
|
+
*
|
|
133
|
+
* Checking a key that sits on the SSD and recording the 'material' phase for it
|
|
134
|
+
* is a check that measured the wrong thing: the point of the phase is that the
|
|
135
|
+
* material was handled in volatile memory.
|
|
136
|
+
*/
|
|
137
|
+
function assertInsideWorkspace(path, what) {
|
|
138
|
+
const absolute = resolve(path);
|
|
139
|
+
if (absolute !== CEREMONY_MOUNT_POINT && !absolute.startsWith(`${CEREMONY_MOUNT_POINT}/`)) {
|
|
140
|
+
throw new Error(`${what} is at ${absolute}, outside the ceremony workspace ` +
|
|
141
|
+
`(${CEREMONY_MOUNT_POINT}). Key material is handled in the RAM volume and ` +
|
|
142
|
+
'nowhere else; verifying a copy that lives somewhere else would record a ' +
|
|
143
|
+
'precaution that was not taken.');
|
|
144
|
+
}
|
|
145
|
+
return absolute;
|
|
146
|
+
}
|
|
147
|
+
export function registerLmkCeremonyCommands(escrow) {
|
|
148
|
+
const ceremony = escrow
|
|
149
|
+
.command('ceremony')
|
|
150
|
+
.description('Escrow ceremony with recorded state and enforced gates. Records who ran ' +
|
|
151
|
+
'it, when, and how far it got, in key_lifecycle_operations.');
|
|
152
|
+
// ---------------------------------------------------------------- start ---
|
|
153
|
+
ceremony
|
|
154
|
+
.command('start')
|
|
155
|
+
.description('Claim the ceremony slot and run the preflight gates')
|
|
156
|
+
.option('--operator <who>', 'Who is performing it (defaults to the login name)')
|
|
157
|
+
.option('--json', 'Output as JSON')
|
|
158
|
+
.action(async (options) => {
|
|
159
|
+
requireLocalDb();
|
|
160
|
+
const ops = await lifecycle();
|
|
161
|
+
try {
|
|
162
|
+
// Not "is anything running?" then INSERT — that is the race the index
|
|
163
|
+
// exists to close. But a friendly message beforehand costs nothing.
|
|
164
|
+
assertNoOtherCeremonyRunning(await ops.active());
|
|
165
|
+
const operator = options.operator ?? userInfo().username;
|
|
166
|
+
const claimed = await ops.claim({
|
|
167
|
+
phase: 'preflight',
|
|
168
|
+
ownerNodeId: hostname(),
|
|
169
|
+
ownerPrincipal: operator,
|
|
170
|
+
minRelease: MIN_RELEASE,
|
|
171
|
+
detail: { cliVersion: getVersion() },
|
|
172
|
+
});
|
|
173
|
+
if (!claimed.ok) {
|
|
174
|
+
assertNoOtherCeremonyRunning(claimed.active);
|
|
175
|
+
throw new Error('The ceremony slot was taken between the check and the claim.');
|
|
176
|
+
}
|
|
177
|
+
const devices = listEscrowDevices();
|
|
178
|
+
const payload = {
|
|
179
|
+
operationId: claimed.operation.operationId,
|
|
180
|
+
operator,
|
|
181
|
+
host: hostname(),
|
|
182
|
+
cliVersion: getVersion(),
|
|
183
|
+
devices: devices.map((d) => ({
|
|
184
|
+
mountPoint: d.mountPoint,
|
|
185
|
+
usbSerial: d.usbSerial,
|
|
186
|
+
volumeLabel: d.volumeLabel,
|
|
187
|
+
indexing: indexingEnabled(d.mountPoint),
|
|
188
|
+
})),
|
|
189
|
+
};
|
|
190
|
+
if (options.json === true) {
|
|
191
|
+
output.json(payload);
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
output.section('Escrow ceremony started');
|
|
195
|
+
output.keyValue({
|
|
196
|
+
Operation: payload.operationId,
|
|
197
|
+
Operator: operator,
|
|
198
|
+
Host: payload.host,
|
|
199
|
+
CLI: payload.cliVersion,
|
|
200
|
+
});
|
|
201
|
+
if (devices.length === 0) {
|
|
202
|
+
output.warn('No datAshur device is mounted. Unlock and mount both before continuing.');
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
output.table(['Mount point', 'USB serial', 'Label', 'Spotlight'], payload.devices.map((d) => [
|
|
206
|
+
d.mountPoint,
|
|
207
|
+
d.usbSerial ?? '(unreadable)',
|
|
208
|
+
d.volumeLabel,
|
|
209
|
+
d.indexing === true ? 'INDEXING — turn it off' : d.indexing === false ? 'off' : 'unknown',
|
|
210
|
+
]));
|
|
211
|
+
}
|
|
212
|
+
output.info("Next: 'ceremony workspace' to create the RAM-backed working volume.");
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
finally {
|
|
216
|
+
await ops.close();
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
// --------------------------------------------------------------- status ---
|
|
220
|
+
ceremony
|
|
221
|
+
.command('status')
|
|
222
|
+
.description('Where the ceremony is, and the whole route it travelled')
|
|
223
|
+
.option('--json', 'Output as JSON')
|
|
224
|
+
.action(async (options) => {
|
|
225
|
+
requireLocalDb();
|
|
226
|
+
const ops = await lifecycle();
|
|
227
|
+
try {
|
|
228
|
+
const active = await ops.active();
|
|
229
|
+
if (active === null) {
|
|
230
|
+
if (options.json === true)
|
|
231
|
+
output.json({ active: null });
|
|
232
|
+
else
|
|
233
|
+
output.info('No ceremony or other key-lifecycle operation is in progress.');
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
const history = await ops.history(active.operationId);
|
|
237
|
+
if (options.json === true) {
|
|
238
|
+
output.json({ active, history });
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
output.section(`In progress: ${active.kind}`);
|
|
242
|
+
output.keyValue({
|
|
243
|
+
Operation: active.operationId,
|
|
244
|
+
Phase: active.phase,
|
|
245
|
+
Operator: active.ownerPrincipal,
|
|
246
|
+
Host: active.ownerNodeId,
|
|
247
|
+
Started: active.startedAt,
|
|
248
|
+
});
|
|
249
|
+
output.table(['#', 'Phase', 'State', 'At'], history.map((e) => [String(e.seq), e.phase, e.state, e.at]));
|
|
250
|
+
}
|
|
251
|
+
finally {
|
|
252
|
+
await ops.close();
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
// ------------------------------------------------------------ workspace ---
|
|
256
|
+
ceremony
|
|
257
|
+
.command('workspace')
|
|
258
|
+
.description('Create the RAM-backed working volume, and PROVE it is in RAM')
|
|
259
|
+
.action(async () => {
|
|
260
|
+
requireLocalDb();
|
|
261
|
+
const ops = await lifecycle();
|
|
262
|
+
try {
|
|
263
|
+
const active = await requireActive(ops);
|
|
264
|
+
const facts = createRamWorkspace(WORKSPACE_MB);
|
|
265
|
+
// The gate, not the return code. A failed mount leaves the mount point
|
|
266
|
+
// as an ordinary directory and every write below lands on the SSD,
|
|
267
|
+
// silently. See workspace.ts.
|
|
268
|
+
assertRamBacked(facts);
|
|
269
|
+
await advance(ops, active, 'workspace', { device: facts.device, imagePath: facts.imagePath });
|
|
270
|
+
output.success(`Workspace ready at ${CEREMONY_MOUNT_POINT} (${facts.device}, ${facts.imagePath ?? '?'})`);
|
|
271
|
+
output.info('Copy the key material INTO this directory and nowhere else, then check ' +
|
|
272
|
+
"each item with 'ceremony check-key'.");
|
|
273
|
+
}
|
|
274
|
+
finally {
|
|
275
|
+
await ops.close();
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
// ------------------------------------------------------------ check-key ---
|
|
279
|
+
ceremony
|
|
280
|
+
.command('check-key <path>')
|
|
281
|
+
.description('Verify a key file against its recorded fingerprint before it is escrowed')
|
|
282
|
+
.option('--against-envelope <providerId>', "Compare against root_key_envelopes (e.g. 'sentinel')")
|
|
283
|
+
.option('--expect-kcv <kcv1:...>', 'Compare against a known fingerprint (for the legacy BSK)')
|
|
284
|
+
.option('--label <name>', 'What this key is, for the message', 'key')
|
|
285
|
+
.action(async (path, options) => {
|
|
286
|
+
requireLocalDb();
|
|
287
|
+
if ((options.againstEnvelope === undefined) === (options.expectKcv === undefined)) {
|
|
288
|
+
throw new Error('Pass exactly one of --against-envelope or --expect-kcv.');
|
|
289
|
+
}
|
|
290
|
+
const ops = await lifecycle();
|
|
291
|
+
const db = new LocalDBClient();
|
|
292
|
+
let key = null;
|
|
293
|
+
try {
|
|
294
|
+
const active = await requireActive(ops);
|
|
295
|
+
// The workspace was proven RAM-backed when it was CREATED, and the
|
|
296
|
+
// process then exited. Minutes pass while material is copied in. If the
|
|
297
|
+
// volume was unmounted in between, the mount point survives as an
|
|
298
|
+
// ordinary directory on the SSD and quietly absorbs everything — the
|
|
299
|
+
// documented failure, reintroduced as a check-then-use gap. So prove it
|
|
300
|
+
// again, here, against the device this ceremony recorded.
|
|
301
|
+
const absolute = assertInsideWorkspace(path, 'The key file');
|
|
302
|
+
assertRamBacked(describeDevice(await recordedWorkspaceDevice(ops, active.operationId)));
|
|
303
|
+
key = readFileSync(absolute);
|
|
304
|
+
if (options.againstEnvelope !== undefined) {
|
|
305
|
+
const envelope = await db.getRootKeyEnvelope(options.againstEnvelope);
|
|
306
|
+
if (envelope === null) {
|
|
307
|
+
throw new Error(`No envelope recorded for provider '${options.againstEnvelope}'. Without it ` +
|
|
308
|
+
'there is nothing to check the key against, and an unchecked key is how ' +
|
|
309
|
+
'an escrow ends up holding the wrong one.');
|
|
310
|
+
}
|
|
311
|
+
assertKeyMatchesEnvelope(key, envelope);
|
|
312
|
+
output.success(`${options.label ?? 'key'} matches the '${envelope.providerId}' envelope (${envelope.kcv})`);
|
|
313
|
+
// The KCV goes into the record, not just the message: an acta written
|
|
314
|
+
// from this trail should not have to trust that someone read the
|
|
315
|
+
// screen correctly. A KCV is publishable by construction.
|
|
316
|
+
await advance(ops, active, 'material', {
|
|
317
|
+
checked: options.label, against: envelope.providerId, kcv: envelope.kcv,
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
else if (options.expectKcv !== undefined) {
|
|
321
|
+
assertKeyMatchesExpectedKcv(key, options.expectKcv, options.label ?? 'key');
|
|
322
|
+
output.success(`${options.label ?? 'key'} matches ${options.expectKcv}`);
|
|
323
|
+
await advance(ops, active, 'material', {
|
|
324
|
+
checked: options.label, against: 'recorded fingerprint', kcv: options.expectKcv,
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
finally {
|
|
329
|
+
key?.fill(0);
|
|
330
|
+
await db.close();
|
|
331
|
+
await ops.close();
|
|
332
|
+
}
|
|
333
|
+
});
|
|
334
|
+
// --------------------------------------------------------- check-device ---
|
|
335
|
+
//
|
|
336
|
+
// A CHECK, and it no longer pretends to be more. The previous version looked
|
|
337
|
+
// the device up BY the serial the operator typed and then "verified" that the
|
|
338
|
+
// device it found had that serial — a tautology that could only ever pass,
|
|
339
|
+
// while the failure it claimed to prevent (both bundles on one stick) stayed
|
|
340
|
+
// wide open. What actually binds a copy to a device is `confirm-copy` below,
|
|
341
|
+
// which compares against the serial already recorded for the other copy.
|
|
342
|
+
ceremony
|
|
343
|
+
.command('check-device')
|
|
344
|
+
.description('Show whether the device you mean is mounted, before writing to it')
|
|
345
|
+
.requiredOption('--copy <label>', 'Which copy this should be: A or B')
|
|
346
|
+
.requiredOption('--serial <serial>', 'The USB serial recorded for that copy')
|
|
347
|
+
.action(async (options) => {
|
|
348
|
+
requireLocalDb();
|
|
349
|
+
const ops = await lifecycle();
|
|
350
|
+
try {
|
|
351
|
+
const active = await requireActive(ops);
|
|
352
|
+
const copy = assertCopyLabel(options.copy);
|
|
353
|
+
const devices = listEscrowDevices();
|
|
354
|
+
const match = devices.find((d) => d.usbSerial === options.serial);
|
|
355
|
+
if (match === undefined) {
|
|
356
|
+
throw new Error(`No mounted device has USB serial ${options.serial}. Mounted: ` +
|
|
357
|
+
`${devices.map((d) => `${d.mountPoint}=${d.usbSerial ?? '?'}`).join(', ') || '(none)'}.`);
|
|
358
|
+
}
|
|
359
|
+
const other = copy === 'A' ? 'B' : 'A';
|
|
360
|
+
assertNotTheOtherCopy(options.serial, copy, recordedString(await recordedDetail(ops, active.operationId, phaseForCopy(other)), 'serial'));
|
|
361
|
+
output.success(`${match.mountPoint} is mounted with serial ${options.serial}.`);
|
|
362
|
+
output.info(`Write copy ${copy}: znvault superadmin lmk escrow snapshot --mount ` +
|
|
363
|
+
`${match.mountPoint} --copy-label ${copy} …`);
|
|
364
|
+
output.info(`Then record it: ceremony confirm-copy --copy ${copy} --serial ${options.serial} ` +
|
|
365
|
+
'--bundle <file on the device>');
|
|
366
|
+
}
|
|
367
|
+
finally {
|
|
368
|
+
await ops.close();
|
|
369
|
+
}
|
|
370
|
+
});
|
|
371
|
+
// --------------------------------------------------------- confirm-copy ---
|
|
372
|
+
//
|
|
373
|
+
// THE PHASE IS RECORDED AFTER THE WRITE, AND ONLY IF THE WRITE IS THERE.
|
|
374
|
+
// Previously `check-device` advanced to write-a/write-b BEFORE anything was
|
|
375
|
+
// written, and no command ever checked that a bundle had landed — so the trail
|
|
376
|
+
// could read `write-a, write-b, teardown, COMPLETED` for a ceremony whose
|
|
377
|
+
// devices were empty. The phases described intentions. Now they describe a
|
|
378
|
+
// bundle that was read back OFF the device and verified.
|
|
379
|
+
ceremony
|
|
380
|
+
.command('confirm-copy')
|
|
381
|
+
.description('Verify the bundle actually on the device, and record that copy')
|
|
382
|
+
.requiredOption('--copy <label>', 'Which copy this is: A or B')
|
|
383
|
+
.requiredOption('--serial <serial>', 'USB serial of the device it was written to')
|
|
384
|
+
.requiredOption('--bundle <path>', 'The bundle file, on that device')
|
|
385
|
+
.action(async (options) => {
|
|
386
|
+
requireLocalDb();
|
|
387
|
+
const ops = await lifecycle();
|
|
388
|
+
try {
|
|
389
|
+
const active = await requireActive(ops);
|
|
390
|
+
const copy = assertCopyLabel(options.copy);
|
|
391
|
+
const devices = listEscrowDevices();
|
|
392
|
+
const match = devices.find((d) => d.usbSerial === options.serial);
|
|
393
|
+
if (match === undefined) {
|
|
394
|
+
throw new Error(`No mounted device has USB serial ${options.serial}, so there is nothing ` +
|
|
395
|
+
'to verify. Plug in the device the bundle was written to.');
|
|
396
|
+
}
|
|
397
|
+
const other = copy === 'A' ? 'B' : 'A';
|
|
398
|
+
assertNotTheOtherCopy(options.serial, copy, recordedString(await recordedDetail(ops, active.operationId, phaseForCopy(other)), 'serial'));
|
|
399
|
+
// The bundle has to be ON the device. Verifying a copy that still sits
|
|
400
|
+
// in the workspace would pass while the device stayed empty.
|
|
401
|
+
const bundlePath = resolve(options.bundle);
|
|
402
|
+
if (!bundlePath.startsWith(`${match.mountPoint}/`)) {
|
|
403
|
+
throw new Error(`${bundlePath} is not on ${match.mountPoint}. The point of this step is ` +
|
|
404
|
+
'that the bundle reached the device — a copy verified anywhere else ' +
|
|
405
|
+
'leaves the device empty and the record saying otherwise.');
|
|
406
|
+
}
|
|
407
|
+
const report = readAndVerifyLmkEscrowBundle(bundlePath);
|
|
408
|
+
if (report.copyLabel.toUpperCase() !== copy) {
|
|
409
|
+
throw new Error(`That bundle is labelled copy ${report.copyLabel}, not ${copy}. Writing ` +
|
|
410
|
+
'it here would leave two copies with the same label and no way to tell ' +
|
|
411
|
+
'from the bundles which device is missing.');
|
|
412
|
+
}
|
|
413
|
+
await advance(ops, active, phaseForCopy(copy), {
|
|
414
|
+
copy,
|
|
415
|
+
serial: options.serial,
|
|
416
|
+
mountPoint: match.mountPoint,
|
|
417
|
+
bundlePath,
|
|
418
|
+
bundleId: report.bundleId,
|
|
419
|
+
bskKcv: report.bskKcv,
|
|
420
|
+
recoverability: report.recoverability,
|
|
421
|
+
});
|
|
422
|
+
output.success(`Copy ${copy} verified on ${match.mountPoint}: bundle ${report.bundleId}, ` +
|
|
423
|
+
`BSK ${report.bskKcv}, ${report.recoverability}.`);
|
|
424
|
+
}
|
|
425
|
+
finally {
|
|
426
|
+
await ops.close();
|
|
427
|
+
}
|
|
428
|
+
});
|
|
429
|
+
// --------------------------------------------------------------- verify ---
|
|
430
|
+
//
|
|
431
|
+
// Both copies, at the same time, on two different devices. `confirm-copy` can
|
|
432
|
+
// only ever see one device at a time, so on its own it cannot rule out that
|
|
433
|
+
// the second copy went onto the first stick after the first was unplugged.
|
|
434
|
+
// This is the step that makes "two copies in two places" an observed fact.
|
|
435
|
+
ceremony
|
|
436
|
+
.command('verify')
|
|
437
|
+
.description('Re-read BOTH bundles, from both devices, at the same time')
|
|
438
|
+
.action(async () => {
|
|
439
|
+
requireLocalDb();
|
|
440
|
+
const ops = await lifecycle();
|
|
441
|
+
try {
|
|
442
|
+
const active = await requireActive(ops);
|
|
443
|
+
const recorded = await Promise.all(['A', 'B'].map(async (copy) => {
|
|
444
|
+
const detail = await recordedDetail(ops, active.operationId, phaseForCopy(copy));
|
|
445
|
+
const serial = recordedString(detail, 'serial');
|
|
446
|
+
const bundlePath = recordedString(detail, 'bundlePath');
|
|
447
|
+
if (serial === null || bundlePath === null) {
|
|
448
|
+
throw new Error(`Copy ${copy} was never confirmed, so there is nothing to verify. Run ` +
|
|
449
|
+
`'ceremony confirm-copy --copy ${copy} …' first.`);
|
|
450
|
+
}
|
|
451
|
+
return { copy, serial, bundlePath };
|
|
452
|
+
}));
|
|
453
|
+
const [a, b] = recorded;
|
|
454
|
+
if (a.serial === b.serial) {
|
|
455
|
+
throw new Error(`Both copies were recorded against the same device (${a.serial}). That is ` +
|
|
456
|
+
'one stick holding both bundles and another holding none.');
|
|
457
|
+
}
|
|
458
|
+
const mounted = listEscrowDevices();
|
|
459
|
+
const results = recorded.map((r) => {
|
|
460
|
+
if (!mounted.some((d) => d.usbSerial === r.serial)) {
|
|
461
|
+
throw new Error(`Copy ${r.copy} (serial ${r.serial}) is not mounted. Both devices must ` +
|
|
462
|
+
'be present for this check — that is what it is for.');
|
|
463
|
+
}
|
|
464
|
+
const report = readAndVerifyLmkEscrowBundle(r.bundlePath);
|
|
465
|
+
return { ...r, bundleId: report.bundleId, bskKcv: report.bskKcv };
|
|
466
|
+
});
|
|
467
|
+
const [ra, rb] = results;
|
|
468
|
+
if (ra.bskKcv !== rb.bskKcv) {
|
|
469
|
+
throw new Error(`The two copies hold different bootstrap keys (${ra.bskKcv} and ` +
|
|
470
|
+
`${rb.bskKcv}). One of them will not open this deployment.`);
|
|
471
|
+
}
|
|
472
|
+
await advance(ops, active, 'verify', {
|
|
473
|
+
copies: results.map((r) => ({ copy: r.copy, serial: r.serial, bundleId: r.bundleId })),
|
|
474
|
+
bskKcv: ra.bskKcv,
|
|
475
|
+
});
|
|
476
|
+
output.success('Both copies verified, on two distinct devices, holding the same key.');
|
|
477
|
+
output.table(['Copy', 'USB serial', 'Bundle'], results.map((r) => [r.copy, r.serial, r.bundleId]));
|
|
478
|
+
output.info("Next: 'ceremony teardown' to destroy the RAM workspace.");
|
|
479
|
+
}
|
|
480
|
+
finally {
|
|
481
|
+
await ops.close();
|
|
482
|
+
}
|
|
483
|
+
});
|
|
484
|
+
// ------------------------------------------------------------- teardown ---
|
|
485
|
+
ceremony
|
|
486
|
+
.command('teardown [device]')
|
|
487
|
+
.description('Destroy the RAM workspace and PROVE it is gone')
|
|
488
|
+
.action(async (device) => {
|
|
489
|
+
requireLocalDb();
|
|
490
|
+
const ops = await lifecycle();
|
|
491
|
+
try {
|
|
492
|
+
const active = await requireActive(ops);
|
|
493
|
+
// THE DEVICE COMES FROM THE RECORD, not from argv. It used to come from
|
|
494
|
+
// argv and was never compared with anything: a typo destroyed nothing,
|
|
495
|
+
// reported success — `hdiutil detach` on a device that does not exist
|
|
496
|
+
// fails quietly and the checks then observe that the nonexistent device
|
|
497
|
+
// is indeed gone — and left the real RAM disk attached with the
|
|
498
|
+
// bootstrap key in it. The optional argument is now only a cross-check.
|
|
499
|
+
const recordedDevice = await recordedWorkspaceDevice(ops, active.operationId);
|
|
500
|
+
if (device !== undefined && device !== recordedDevice) {
|
|
501
|
+
throw new Error(`This ceremony's workspace is ${recordedDevice}, not ${device}. Tearing ` +
|
|
502
|
+
`down ${device} would report success while ${recordedDevice} stayed ` +
|
|
503
|
+
'attached with key material in it.');
|
|
504
|
+
}
|
|
505
|
+
const facts = destroyRamWorkspace(recordedDevice);
|
|
506
|
+
// Unmounting is not destroying: the RAM still holds the bytes and the
|
|
507
|
+
// device can be remounted by anyone.
|
|
508
|
+
assertTornDown(facts);
|
|
509
|
+
await advance(ops, active, 'teardown', { device: recordedDevice });
|
|
510
|
+
output.success(`${recordedDevice} unmounted and detached; the workspace is gone.`);
|
|
511
|
+
output.info("Close the ceremony with 'ceremony finish'.");
|
|
512
|
+
}
|
|
513
|
+
finally {
|
|
514
|
+
await ops.close();
|
|
515
|
+
}
|
|
516
|
+
});
|
|
517
|
+
// --------------------------------------------------------------- finish ---
|
|
518
|
+
ceremony
|
|
519
|
+
.command('finish')
|
|
520
|
+
.description('Close the ceremony as COMPLETED')
|
|
521
|
+
.action(async () => {
|
|
522
|
+
requireLocalDb();
|
|
523
|
+
const ops = await lifecycle();
|
|
524
|
+
try {
|
|
525
|
+
const active = await requireActive(ops);
|
|
526
|
+
// Over the RECORDED ROUTE, not the current phase. Checking only "are we
|
|
527
|
+
// at teardown?" let a ceremony that had done nothing but start and tear
|
|
528
|
+
// down close as COMPLETED — and COMPLETED is the word somebody reads
|
|
529
|
+
// years later, on the day the escrow is all that is left.
|
|
530
|
+
const history = await ops.history(active.operationId);
|
|
531
|
+
assertRouteComplete(history.map((e) => e.phase));
|
|
532
|
+
const verified = await recordedDetail(ops, active.operationId, 'verify');
|
|
533
|
+
await ops.finish({
|
|
534
|
+
operationId: active.operationId,
|
|
535
|
+
expectedEpoch: active.epoch,
|
|
536
|
+
outcome: 'COMPLETED',
|
|
537
|
+
nodeId: hostname(),
|
|
538
|
+
...(verified ? { detail: verified } : {}),
|
|
539
|
+
});
|
|
540
|
+
output.success(`Ceremony ${active.operationId} closed as COMPLETED.`);
|
|
541
|
+
output.info('The bundle ids, the KCV and both serials are in the record: ceremony status.');
|
|
542
|
+
}
|
|
543
|
+
finally {
|
|
544
|
+
await ops.close();
|
|
545
|
+
}
|
|
546
|
+
});
|
|
547
|
+
// ---------------------------------------------------------------- abort ---
|
|
548
|
+
ceremony
|
|
549
|
+
.command('abort')
|
|
550
|
+
.description('Close the ceremony as ABANDONED, keeping the reason')
|
|
551
|
+
.requiredOption('--reason <text>', 'Why it was abandoned — the next person will read this')
|
|
552
|
+
.option('--force', 'Abandon even if the RAM workspace could not be destroyed')
|
|
553
|
+
.action(async (options) => {
|
|
554
|
+
requireLocalDb();
|
|
555
|
+
const ops = await lifecycle();
|
|
556
|
+
try {
|
|
557
|
+
const active = await requireActive(ops);
|
|
558
|
+
// ABANDONING CLEANS UP, because nothing else can. Abandoning frees the
|
|
559
|
+
// slot, and `teardown` needs an active ceremony — so an abort that left
|
|
560
|
+
// the workspace behind would strand a mounted RAM volume holding the
|
|
561
|
+
// bootstrap key with no command able to destroy it. The hint that used
|
|
562
|
+
// to say "run teardown afterwards" was advice that could not be taken.
|
|
563
|
+
const device = recordedString(await recordedDetail(ops, active.operationId, 'workspace'), 'device');
|
|
564
|
+
if (device !== null) {
|
|
565
|
+
try {
|
|
566
|
+
assertTornDown(destroyRamWorkspace(device));
|
|
567
|
+
output.info(`RAM workspace ${device} destroyed.`);
|
|
568
|
+
}
|
|
569
|
+
catch (error) {
|
|
570
|
+
if (options.force !== true) {
|
|
571
|
+
throw new Error(`The ceremony has NOT been abandoned: its RAM workspace ${device} ` +
|
|
572
|
+
'could not be destroyed, and abandoning would free the slot while ' +
|
|
573
|
+
'leaving key material mounted with no command able to reach it. ' +
|
|
574
|
+
`Deal with it by hand ('hdiutil detach ${device}'), then abort again. ` +
|
|
575
|
+
'To abandon anyway, add --force. Underlying reason: ' +
|
|
576
|
+
(error instanceof Error ? error.message : String(error)));
|
|
577
|
+
}
|
|
578
|
+
output.warn(`Abandoning with --force: ${device} may still be attached WITH KEY ` +
|
|
579
|
+
'MATERIAL IN IT. Destroy it by hand, now.');
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
await ops.finish({
|
|
583
|
+
operationId: active.operationId,
|
|
584
|
+
expectedEpoch: active.epoch,
|
|
585
|
+
outcome: 'ABANDONED',
|
|
586
|
+
nodeId: hostname(),
|
|
587
|
+
error: options.reason,
|
|
588
|
+
});
|
|
589
|
+
output.warn(`Ceremony ${active.operationId} abandoned at phase '${active.phase}'.`);
|
|
590
|
+
output.info('The slot is free and the workspace is gone.');
|
|
591
|
+
}
|
|
592
|
+
finally {
|
|
593
|
+
await ops.close();
|
|
594
|
+
}
|
|
595
|
+
});
|
|
596
|
+
}
|
|
597
|
+
//# sourceMappingURL=lmk-ceremony.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lmk-ceremony.js","sourceRoot":"","sources":["../../src/commands/lmk-ceremony.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lmk-escrow.d.ts","sourceRoot":"","sources":["../../src/commands/lmk-escrow.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"lmk-escrow.d.ts","sourceRoot":"","sources":["../../src/commands/lmk-escrow.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAuJzC,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAmK5D"}
|