]> git.proxmox.com Git - proxmox-backup.git/blame - src/bin/proxmox_tape/encryption_key.rs
update to proxmox-sys 0.2 crate
[proxmox-backup.git] / src / bin / proxmox_tape / encryption_key.rs
CommitLineData
feb1645f 1use anyhow::{bail, Error};
d5a48b5c
DM
2use serde_json::Value;
3
6ef1b649
WB
4use proxmox_router::{cli::*, ApiHandler, RpcEnvironment};
5use proxmox_schema::api;
25877d05 6use proxmox_sys::linux::tty;
d5a48b5c 7
5839c469
DM
8use pbs_api_types::{
9 Fingerprint, Kdf, DRIVE_NAME_SCHEMA, TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA,
10 PASSWORD_HINT_SCHEMA,
11};
12
eb5e0ae6 13use pbs_datastore::paperkey::{PaperkeyFormat, generate_paper_key};
5839c469 14use pbs_config::tape_encryption_keys::{load_key_configs,complete_key_fingerprint};
86fb3877 15
5839c469 16use proxmox_backup::api2;
d5a48b5c
DM
17
18pub fn encryption_key_commands() -> CommandLineInterface {
19
20 let cmd_def = CliCommandMap::new()
21 .insert("list", CliCommand::new(&API_METHOD_LIST_KEYS))
22 .insert(
23 "create",
feb1645f
DM
24 CliCommand::new(&API_METHOD_CREATE_KEY)
25 )
301b8aa0
DM
26 .insert(
27 "change-passphrase",
28 CliCommand::new(&API_METHOD_CHANGE_PASSPHRASE)
29 .arg_param(&["fingerprint"])
30 .completion_cb("fingerprint", complete_key_fingerprint)
31 )
69b8bc3b
DM
32 .insert(
33 "show",
34 CliCommand::new(&API_METHOD_SHOW_KEY)
35 .arg_param(&["fingerprint"])
36 .completion_cb("fingerprint", complete_key_fingerprint)
37 )
64b83c3d
DM
38 .insert(
39 "paperkey",
40 CliCommand::new(&API_METHOD_PAPER_KEY)
41 .arg_param(&["fingerprint"])
42 .completion_cb("fingerprint", complete_key_fingerprint)
43 )
feb1645f
DM
44 .insert(
45 "restore",
46 CliCommand::new(&API_METHOD_RESTORE_KEY)
d5a48b5c
DM
47 )
48 .insert(
49 "remove",
50 CliCommand::new(&api2::config::tape_encryption_keys::API_METHOD_DELETE_KEY)
51 .arg_param(&["fingerprint"])
52 .completion_cb("fingerprint", complete_key_fingerprint)
53 )
54 ;
55
56 cmd_def.into()
57}
58
64b83c3d
DM
59#[api(
60 input: {
61 properties: {
62 fingerprint: {
63 schema: TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA,
64 },
65 subject: {
d1d74c43 66 description: "Include the specified subject as title text.",
64b83c3d
DM
67 optional: true,
68 },
69 "output-format": {
70 type: PaperkeyFormat,
71 optional: true,
72 },
73 },
74 },
75)]
76/// Generate a printable, human readable text file containing the encryption key.
77///
78/// This also includes a scanable QR code for fast key restore.
79fn paper_key(
80 fingerprint: Fingerprint,
81 subject: Option<String>,
82 output_format: Option<PaperkeyFormat>,
83) -> Result<(), Error> {
84
85 let (config_map, _digest) = load_key_configs()?;
86
87 let key_config = match config_map.get(&fingerprint) {
88 Some(key_config) => key_config,
89 None => bail!("tape encryption key '{}' does not exist.", fingerprint),
90 };
91
92 let data: String = serde_json::to_string_pretty(&key_config)?;
93
94 generate_paper_key(std::io::stdout(), &data, subject, output_format)
95}
96
69b8bc3b
DM
97#[api(
98 input: {
99 properties: {
100 fingerprint: {
101 schema: TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA,
102 },
103 "output-format": {
104 schema: OUTPUT_FORMAT,
105 optional: true,
106 },
107 },
108 },
109)]
d1d74c43 110/// Print the encryption key's metadata.
69b8bc3b
DM
111fn show_key(
112 param: Value,
113 rpcenv: &mut dyn RpcEnvironment,
114) -> Result<(), Error> {
115
116 let output_format = get_output_format(&param);
117
118 let info = &api2::config::tape_encryption_keys::API_METHOD_READ_KEY;
119 let mut data = match info.handler {
120 ApiHandler::Sync(handler) => (handler)(param, info, rpcenv)?,
121 _ => unreachable!(),
122 };
123
6ef1b649 124 let options = proxmox_router::cli::default_table_format_options()
69b8bc3b 125 .column(ColumnConfig::new("kdf"))
770a36e5
WB
126 .column(ColumnConfig::new("created").renderer(pbs_tools::format::render_epoch))
127 .column(ColumnConfig::new("modified").renderer(pbs_tools::format::render_epoch))
69b8bc3b
DM
128 .column(ColumnConfig::new("fingerprint"))
129 .column(ColumnConfig::new("hint"));
130
131 format_and_print_result_full(&mut data, &info.returns, &output_format, &options);
132
133 Ok(())
134}
135
301b8aa0
DM
136#[api(
137 input: {
138 properties: {
139 kdf: {
140 type: Kdf,
141 optional: true,
142 },
143 fingerprint: {
144 schema: TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA,
145 },
146 hint: {
147 schema: PASSWORD_HINT_SCHEMA,
148 optional: true,
149 },
150 },
151 },
152)]
153/// Change the encryption key's password.
154fn change_passphrase(
155 mut param: Value,
156 rpcenv: &mut dyn RpcEnvironment,
157) -> Result<(), Error> {
158
159 if !tty::stdin_isatty() {
160 bail!("unable to change passphrase - no tty");
161 }
162
163 let password = tty::read_password("Current Tape Encryption Key Password: ")?;
164
165 let new_password = tty::read_and_verify_password("New Tape Encryption Key Password: ")?;
166
167 param["password"] = String::from_utf8(password)?.into();
168 param["new-password"] = String::from_utf8(new_password)?.into();
169
170 let info = &api2::config::tape_encryption_keys::API_METHOD_CHANGE_PASSPHRASE;
171 match info.handler {
172 ApiHandler::Sync(handler) => (handler)(param, info, rpcenv)?,
173 _ => unreachable!(),
174 };
175
176 Ok(())
177}
178
feb1645f
DM
179#[api(
180 input: {
181 properties: {
182 drive: {
183 schema: DRIVE_NAME_SCHEMA,
184 optional: true,
185 },
186 },
187 },
188)]
189/// Restore encryption key from tape (read password from stdin)
190async fn restore_key(
191 mut param: Value,
192 rpcenv: &mut dyn RpcEnvironment,
193) -> Result<(), Error> {
194
1ce8e905 195 let (config, _digest) = pbs_config::drive::config()?;
85cdc4f3 196 param["drive"] = crate::extract_drive_name(&mut param, &config)?.into();
feb1645f
DM
197
198 if !tty::stdin_isatty() {
199 bail!("no password input mechanism available");
200 }
201
202 let password = tty::read_password("Tepe Encryption Key Password: ")?;
203 param["password"] = String::from_utf8(password)?.into();
204
205 let info = &api2::tape::drive::API_METHOD_RESTORE_KEY;
206 match info.handler {
207 ApiHandler::Async(handler) => (handler)(param, info, rpcenv).await?,
208 _ => unreachable!(),
209 };
210
211 Ok(())
212}
213
214#[api(
215 input: {
216 properties: {
e5b6c933
DM
217 kdf: {
218 type: Kdf,
219 optional: true,
220 },
feb1645f
DM
221 hint: {
222 description: "Password restore hint.",
223 type: String,
224 min_length: 1,
225 max_length: 32,
226 },
227 },
228 },
229)]
230/// Create key (read password from stdin)
231fn create_key(
232 mut param: Value,
233 rpcenv: &mut dyn RpcEnvironment,
234) -> Result<(), Error> {
235
236 if !tty::stdin_isatty() {
237 bail!("no password input mechanism available");
238 }
239
240 let password = tty::read_and_verify_password("Tape Encryption Key Password: ")?;
241
242 param["password"] = String::from_utf8(password)?.into();
243
244 let info = &api2::config::tape_encryption_keys::API_METHOD_CREATE_KEY;
245 let fingerprint = match info.handler {
246 ApiHandler::Sync(handler) => (handler)(param, info, rpcenv)?,
247 _ => unreachable!(),
248 };
249
250 println!("{}", fingerprint);
251
252 Ok(())
253}
254
255
d5a48b5c
DM
256#[api(
257 input: {
258 properties: {
259 "output-format": {
260 schema: OUTPUT_FORMAT,
261 optional: true,
262 },
263 },
264 },
265)]
266/// List keys
267fn list_keys(
268 param: Value,
269 rpcenv: &mut dyn RpcEnvironment,
270) -> Result<(), Error> {
271
272 let output_format = get_output_format(&param);
273 let info = &api2::config::tape_encryption_keys::API_METHOD_LIST_KEYS;
274 let mut data = match info.handler {
275 ApiHandler::Sync(handler) => (handler)(param, info, rpcenv)?,
276 _ => unreachable!(),
277 };
278
279 let options = default_table_format_options()
280 .column(ColumnConfig::new("fingerprint"))
281 .column(ColumnConfig::new("hint"))
282 ;
283
284 format_and_print_result_full(&mut data, &info.returns, &output_format, &options);
285
286 Ok(())
287}