nethsm_cli/cli/
config.rs

1use std::{net::Ipv4Addr, path::PathBuf};
2
3use chrono::{DateTime, Utc};
4use clap::{Parser, Subcommand};
5use expression_format::ex_format;
6use nethsm::{BootMode, LogLevel, SystemState, TlsKeyType, UserRole::Administrator};
7use strum::IntoEnumIterator;
8
9use crate::passphrase_file::PassphraseFile;
10
11/// The "nethsm config" command.
12#[derive(Debug, Subcommand)]
13#[command(
14    about = "Manage the configuration of a device",
15    long_about = "Manage the configuration of a device
16
17Allows adding, removing and listing of configuration items"
18)]
19pub enum ConfigCommand {
20    /// The "nethsm config get" command.
21    #[command(subcommand)]
22    Get(ConfigGetCommand),
23
24    /// The "nethsm config set" command.
25    #[command(subcommand)]
26    Set(ConfigSetCommand),
27}
28
29/// The "nethsm config get" command.
30#[derive(Debug, Subcommand)]
31#[command(about = "Get a configuration item for a device")]
32pub enum ConfigGetCommand {
33    /// The "nethsm config get boot-mode" command.
34    BootMode(GetBootModeCommand),
35    /// The "nethsm config get logging" command.
36    Logging(GetLoggingCommand),
37    /// The "nethsm config get network" command.
38    Network(GetNetworkCommand),
39    /// The "nethsm config get time" command.
40    Time(GetTimeCommand),
41    /// The "nethsm config get tls-certificate" command.
42    TlsCertificate(GetTlsCertificateCommand),
43    /// The "nethsm config get tls-csr" command.
44    TlsCsr(GetTlsCsrCommand),
45    /// The "nethsm config get tls-public-key" command.
46    TlsPublicKey(GetTlsPublicKeyCommand),
47}
48
49#[derive(Debug, Parser)]
50#[command(
51    about = "Get the unattended boot configuration",
52    long_about = ex_format!("Get the unattended boot configuration
53
54* \"{BootMode::Attended}\" if the device needs to be unlocked during boot
55* \"{BootMode::Unattended}\" if the device does not need to be unlocked during boot
56
57Requires authentication of a system-wide user in the \"{Administrator}\" role."
58    )
59)]
60pub struct GetBootModeCommand {}
61
62#[derive(Debug, Parser)]
63#[command(
64    about = "Get the logging configuration",
65    long_about = ex_format!("Get the logging configuration
66
67Shows IP address and port number of the host the target device logs to at a given log level.
68
69Requires authentication of a system-wide user in the \"{Administrator}\" role."
70    )
71)]
72pub struct GetLoggingCommand {}
73
74#[derive(Debug, Parser)]
75#[command(
76    about = "Get the network configuration",
77    long_about = ex_format!("Get the network configuration
78
79Shows IP address, netmask and gateway of the target device.
80
81Requires authentication of a system-wide user in the \"{Administrator}\" role."
82    )
83)]
84pub struct GetNetworkCommand {}
85
86#[derive(Debug, Parser)]
87#[command(
88    about = "Get the time",
89    long_about = ex_format!("Get the time
90
91Returns the current time as ISO 8601 formatted timestamp.
92
93Requires authentication of a system-wide user in the \"{Administrator}\" role."
94    )
95)]
96pub struct GetTimeCommand {}
97
98#[derive(Debug, Parser)]
99#[command(
100    about = "Get the certificate for the TLS connection",
101    long_about = ex_format!("Get the certificate for the TLS connection
102
103The X.509 certificate is returned in Privacy-enhanced Electronic Mail (PEM) format.
104Unless a specific output file is chosen, the certificate is returned on stdout.
105
106Requires authentication of a system-wide user in the \"{Administrator}\" role."
107    )
108)]
109pub struct GetTlsCertificateCommand {
110    #[arg(
111        env = "NETHSM_FORCE",
112        help = "Write to output file even if it exists already",
113        long,
114        short
115    )]
116    pub force: bool,
117
118    #[arg(
119        env = "NETHSM_CONFIG_TLS_CERT_OUTPUT_FILE",
120        help = "The optional path to a specific file that the certificate is written to",
121        long,
122        short
123    )]
124    pub output: Option<PathBuf>,
125}
126
127#[derive(Debug, Parser)]
128#[command(
129    about = "Get a Certificate Signing Request for the TLS certificate",
130    long_about = ex_format!("Get a Certificate Signing Request for the TLS certificate
131
132The PKCS#10 Certificate Signing Request (CSR) is returned in Privacy-enhanced Electronic Mail (PEM) format.
133Unless a specific output file is chosen, the certificate is returned on stdout.
134
135At a minimum, the \"Common Name\" (CN) attribute for the CSR has to be provided.
136
137Requires authentication of a system-wide user in the \"{Administrator}\" role."
138    )
139)]
140pub struct GetTlsCsrCommand {
141    #[arg(
142        env = "NETHSM_TLS_CSR_COMMON_NAME",
143        help = "The mandatory \"Common Name\" (CN) attribute for the CSR",
144        long_help = "The mandatory \"Common Name\" (CN) attribute for the CSR
145
146A fully qualified domain name (FQDN) that should be secured using the CSR."
147    )]
148    pub common_name: String,
149
150    #[arg(
151        env = "NETHSM_TLS_CSR_ORG_NAME",
152        help = "The optional \"Organization Name\" (O) attribute for the CSR",
153        long_help = "The optional \"Organization Name\" (O) attribute for the CSR
154
155Usually the legal name of a company or entity and should include any suffixes such as Ltd., Inc., or Corp."
156    )]
157    pub org_name: Option<String>,
158
159    #[arg(
160        env = "NETHSM_TLS_CSR_ORG_UNIT",
161        help = "The optional \"Organizational Unit\" (OU) attribute for the CSR",
162        long_help = "The optional \"Organizational Unit\" (OU) attribute for the CSR
163
164Internal organization department/division name."
165    )]
166    pub org_unit: Option<String>,
167
168    #[arg(
169        env = "NETHSM_TLS_CSR_LOCALITY",
170        help = "The optional \"Locality\" (L) attribute for the CSR",
171        long_help = "The optional \"Locality\" (L) attribute for the CSR
172
173Name of town, city, village, etc."
174    )]
175    pub locality: Option<String>,
176
177    #[arg(
178        env = "NETHSM_TLS_CSR_STATE",
179        help = "The optional \"State\" (ST) attribute for the CSR",
180        long_help = "The optional \"State\" (ST) attribute for the CSR
181
182Province, region, county or state."
183    )]
184    pub state: Option<String>,
185
186    #[arg(
187        env = "NETHSM_TLS_CSR_COUNTRY",
188        help = "The optional \"Country\" (C) attribute for the CSR",
189        long_help = "The optional \"Country\" (C) attribute for the CSR
190
191The two-letter ISO code for the country where the \"Organization\" (O) is located."
192    )]
193    pub country: Option<String>,
194
195    #[arg(
196        env = "NETHSM_TLS_CSR_EMAIL",
197        help = "The optional \"Email Address\" (EMAIL) attribute for the CSR",
198        long_help = "The optional \"Email Address\" (EMAIL) attribute for the CSR
199
200The organization contact, usually of the certificate administrator or IT department."
201    )]
202    pub email: Option<String>,
203
204    #[arg(
205        env = "NETHSM_FORCE",
206        help = "Write to output file even if it exists already",
207        long,
208        short
209    )]
210    pub force: bool,
211
212    #[arg(
213        env = "NETHSM_CONFIG_TLS_CSR_OUTPUT_FILE",
214        help = "The optional path to a specific file that the certificate is written to",
215        long,
216        short
217    )]
218    pub output: Option<PathBuf>,
219}
220
221#[derive(Debug, Parser)]
222#[command(
223    about = "Get the public key for the TLS connection",
224    long_about = ex_format!("Get the public key for the TLS connection
225
226The X.509 public key certificate is returned in Privacy-enhanced Electronic Mail (PEM) format.
227Unless a specific output file is chosen, the certificate is returned on stdout.
228
229Requires authentication of a system-wide user in the \"{Administrator}\" role."
230    )
231)]
232pub struct GetTlsPublicKeyCommand {
233    #[arg(
234        env = "NETHSM_FORCE",
235        help = "Write to output file even if it exists already",
236        long,
237        short
238    )]
239    pub force: bool,
240
241    #[arg(
242        env = "NETHSM_CONFIG_TLS_PUBKEY_OUTPUT_FILE",
243        help = "The optional path to a specific file that the certificate is written to",
244        long,
245        short
246    )]
247    pub output: Option<PathBuf>,
248}
249
250/// The "nethsm config get" command.
251#[derive(Debug, Subcommand)]
252#[command(about = "Set a configuration item for a device")]
253pub enum ConfigSetCommand {
254    /// The "nethsm config set backup-passphrase" command.
255    BackupPassphrase(SetBackupPassphraseCommand),
256    /// The "nethsm config set boot-mode" command.
257    BootMode(SetBootModeCommand),
258    /// The "nethsm config set logging" command.
259    Logging(SetLoggingCommand),
260    /// The "nethsm config set network" command.
261    Network(SetNetworkCommand),
262    /// The "nethsm config set time" command.
263    Time(SetTimeCommand),
264    /// The "nethsm config set tls-certificate" command.
265    TlsCertificate(SetTlsCertificateCommand),
266    /// The "nethsm config set tls-generate" command.
267    TlsGenerate(SetTlsGenerateCommand),
268    /// The "nethsm config set unlock-passphrase" command.
269    UnlockPassphrase(SetUnlockPassphraseCommand),
270}
271
272#[derive(Debug, Parser)]
273#[command(
274    about = "Set the backup passphrase",
275    long_about = ex_format!("Set the backup passphrase
276
277The initial backup passphrase is the empty string.
278
279The new passphrase must be >= 10 and <= 200 characters.
280
281By default the passphrases are prompted for interactively, but they can each be provided using a dedicated passphrase file instead.
282
283Requires authentication of a system-wide user in the \"{Administrator}\" role."
284    )
285)]
286pub struct SetBackupPassphraseCommand {
287    #[arg(
288        env = "NETHSM_NEW_PASSPHRASE_FILE",
289        help = "The path to a file containing the new passphrase",
290        long_help = "The path to a file containing the new passphrase
291
292The passphrase must be >= 10 and <= 200 characters long.",
293        long,
294        short
295    )]
296    pub new_passphrase_file: Option<PassphraseFile>,
297
298    #[arg(
299        env = "NETHSM_OLD_PASSPHRASE_FILE",
300        help = "The path to a file containing the old passphrase",
301        long_help = "The path to a file containing the old passphrase
302
303The passphrase must be >= 10 and <= 200 characters long.",
304        long,
305        short
306    )]
307    pub old_passphrase_file: Option<PassphraseFile>,
308}
309
310#[derive(Debug, Parser)]
311#[command(
312    about = "Set the unattended boot mode",
313    long_about = ex_format!("Set the unattended boot mode
314
315Sets whether the device boots into state \"{SystemState::Locked}\" (using boot mode \"{BootMode::Attended}\") or \"{SystemState::Operational}\" (using boot mode \"{BootMode::Unattended}\").
316
317Requires authentication of a system-wide user in the \"{Administrator}\" role."
318    ),
319)]
320pub struct SetBootModeCommand {
321    #[arg(
322        env = "NETHSM_BOOT_MODE",
323        help = "The boot mode to use",
324        long_help = format!("The boot mode to use
325
326One of {:?} (no default).",
327            BootMode::iter().map(Into::into).collect::<Vec<&'static str>>()
328        )
329    )]
330    pub boot_mode: BootMode,
331}
332
333#[derive(Debug, Parser)]
334#[command(
335    about = "Set the logging configuration",
336    long_about = ex_format!("Set the logging configuration
337
338Provide IP address and port of a host to send syslog to at a specified log level.
339
340Requires authentication of a system-wide user in the \"{Administrator}\" role."
341    )
342)]
343pub struct SetLoggingCommand {
344    #[arg(
345        env = "NETHSM_LOGGING_IP_ADDRESS",
346        help = "The IPv4 address of the host to send syslog to"
347    )]
348    pub ip_address: Ipv4Addr,
349
350    #[arg(
351        env = "NETHSM_LOGGING_PORT",
352        help = "The port of the host to send syslog to"
353    )]
354    pub port: u32,
355
356    #[arg(
357        env = "NETHSM_LOGGING_LOG_LEVEL",
358        help = "The log level at which to log",
359        long_help = format!("The log level at which to log
360
361One of {:?} (defaults to \"{:?}\").",
362            LogLevel::iter().map(Into::into).collect::<Vec<&'static str>>(),
363            LogLevel::default(),
364        )
365    )]
366    pub log_level: Option<LogLevel>,
367}
368
369#[derive(Debug, Parser)]
370#[command(
371    about = "Set the network configuration",
372    long_about = ex_format!("Set the network configuration
373
374Provide IPv4 address, netmask and Ipv4 gateway address for the device to use.
375
376Requires authentication of a system-wide user in the \"{Administrator}\" role."
377    )
378)]
379pub struct SetNetworkCommand {
380    #[arg(
381        env = "NETHSM_NETWORK_IP_ADDRESS",
382        help = "The IPv4 address the device is to use"
383    )]
384    pub ip_address: Ipv4Addr,
385
386    #[arg(
387        env = "NETHSM_NETWORK_NETMASK",
388        help = "The IPv4 netmask the device is to use"
389    )]
390    pub netmask: String,
391
392    #[arg(
393        env = "NETHSM_NETWORK_GATEWAY",
394        help = "The IPv4 gateway the device is to use"
395    )]
396    pub gateway: Ipv4Addr,
397}
398
399#[derive(Debug, Parser)]
400#[command(
401    about = "Set the time",
402    long_about = ex_format!("Set the time
403
404The time must be provided as ISO 8601 formatted UTC timestamp.
405If no timestamp is provided, the caller's current system time is used to construct a UTC timestamp.
406
407Requires authentication of a system-wide user in the \"{Administrator}\" role."
408    )
409)]
410pub struct SetTimeCommand {
411    #[arg(
412        env = "NETHSM_SYSTEM_TIME",
413        help = "An optional ISO 8601 formatted UTC timestamp",
414        long_help = "An optional ISO 8601 formatted UTC timestamp
415
416If no timestamp is provided, the caller's current system time is used."
417    )]
418    pub system_time: Option<DateTime<Utc>>,
419}
420
421#[derive(Debug, Parser)]
422#[command(
423    about = "Set a new TLS certificate",
424    long_about = ex_format!("Set a new TLS certificate
425
426The X.509 certificate must be provided in Privacy-enhanced Electronic Mail (PEM) format.
427
428The certificate is only accepted if it is created using a Certificate Signing Request (CSR) generated by the target device.
429
430Requires authentication of a system-wide user in the \"{Administrator}\" role."
431    )
432)]
433pub struct SetTlsCertificateCommand {
434    #[arg(
435        env = "NETHSM_TLS_CERT",
436        help = "A new TLS certificate file",
437        long_help = "A new TLS certificate file
438
439The X.509 certificate must be provided in Privacy-enhanced Electronic Mail (PEM) format."
440    )]
441    pub tls_cert: PathBuf,
442}
443
444#[derive(Debug, Parser)]
445#[command(
446    about = "Generate a new TLS certificate",
447    long_about = ex_format!("Generate a new TLS certificate
448
449The current TLS certificate is replaced by the newly generated one.
450Optionally, the type of key and its length can be specified.
451
452Requires authentication of a system-wide user in the \"{Administrator}\" role."
453    )
454)]
455pub struct SetTlsGenerateCommand {
456    #[arg(
457        env = "NETHSM_TLS_KEY_TYPE",
458        help = "The optional key type of the TLS certificate to generate",
459        long_help = format!("The optional key type of the TLS certificate to generate
460
461One of {:?} (defaults to \"{}\").",
462            TlsKeyType::iter().map(Into::into).collect::<Vec<&'static str>>(),
463            TlsKeyType::default(),
464        ),
465    )]
466    pub tls_key_type: Option<TlsKeyType>,
467
468    #[arg(
469        env = "NETHSM_TLS_KEY_LENGTH",
470        help = "The bit length of the TLS key to generate",
471        long_help = ex_format!("The optional bit length of the TLS key to generate
472
473The bit length must be compatible with the chosen key type.
474
475Requires authentication of a user in the \"{Administrator}\" role.")
476    )]
477    pub tls_key_length: Option<u32>,
478}
479
480#[derive(Debug, Parser)]
481#[command(
482    about = "Set the unlock passphrase",
483    long_about = ex_format!("Set the unlock passphrase
484
485The initial unlock passphrase is set during provisioning.
486
487The new passphrase must be >= 10 and <= 200 characters.
488
489By default the passphrases are prompted for interactively, but they can each be provided using a dedicated passphrase file instead.
490
491Requires authentication of a system-wide user in the \"{Administrator}\" role."
492    )
493)]
494pub struct SetUnlockPassphraseCommand {
495    #[arg(
496        env = "NETHSM_NEW_PASSPHRASE_FILE",
497        help = "The path to a file containing the new passphrase",
498        long_help = "The path to a file containing the new passphrase
499
500The passphrase must be >= 10 and <= 200 characters long.",
501        long,
502        short
503    )]
504    pub new_passphrase_file: Option<PassphraseFile>,
505
506    #[arg(
507        env = "NETHSM_OLD_PASSPHRASE_FILE",
508        help = "The path to a file containing the old passphrase",
509        long_help = "The path to a file containing the old passphrase
510
511The passphrase must be >= 10 and <= 200 characters long.",
512        long,
513        short
514    )]
515    pub old_passphrase_file: Option<PassphraseFile>,
516}