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