Skip to main content

nethsm/cli/command/
config.rs

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