1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
// SPDX-License-Identifier: Apache-2.0
//! `dbmd key` — agent signing keys (link.md §8 `LinkMD-Sig`).
//!
//! `generate` mints the keypair LOCALLY: the secret is written to a 0600
//! file and never travels; the printed public identity is what a hub's
//! register endpoint takes. With `DBMD_AGENT_KEY_FILE` set, every
//! authenticated verb signs its request per link.md §8 instead of sending a
//! bearer — the possession proof binds one method, one path, one body, one
//! ±60s window, so a leaked transcript or log line contains nothing reusable.
use std::path::Path;
use dbmd_core::linkmd;
use crate::cli::{KeyArgs, KeyCommand};
use crate::context::Context;
use crate::error::CliResult;
/// Run `dbmd key`.
pub fn run(ctx: &Context, args: &KeyArgs) -> CliResult {
match &args.command {
KeyCommand::Generate(generate) => {
let minted = linkmd::generate_agent_key(Path::new(&generate.out))?;
if ctx.json {
println!(
"{}",
serde_json::to_string_pretty(&minted).expect("serialize")
);
} else {
println!("multikey: {}", minted.multikey);
println!("publicKeySpki: {}", minted.public_key_spki);
println!(
"key file: {} (0600 — the secret; never share, never commit)",
minted.key_file
);
println!();
println!("register the publicKeySpki with your hub, then:");
println!(
" export {}={}",
linkmd::AGENT_KEY_FILE_ENV,
minted.key_file
);
}
Ok(())
}
KeyCommand::Rotate(rotate) => {
let brain = rotate.brain.trim().trim_start_matches('@');
let cfg = linkmd::hub_config(None, Path::new("."))?;
let old_key = linkmd::load_signing_key(Path::new(&rotate.key_file))?;
let report = linkmd::rotate_brain_key(&cfg, brain, &old_key, Path::new(&rotate.out))?;
if ctx.json {
println!(
"{}",
serde_json::to_string_pretty(&report).expect("serialize")
);
} else {
println!("rotated {}: now {}", report.brain, report.multikey);
println!(
"new key file: {} (0600 — back it up; retain the old key as recovery material)",
report.key_file
);
}
Ok(())
}
}
}