Skip to main content

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_TLS_CSR_SUBJECT_ALT_NAME",
206        help = "The optional list of subject alt names (SAN) for the CSR",
207        long_help = "The optional list of subject alt names (SAN) for the CSR
208
209If omitted, it is set to the same value as common_name.
210If it is set to an empty list, no SAN Extension is added.
211All SANs are considered DNS names, unless they start with \"IP:\" to signal IP names."
212    )]
213    pub subject_alt_names: Option<Vec<String>>,
214
215    #[arg(
216        env = "NETHSM_FORCE",
217        help = "Write to output file even if it exists already",
218        long,
219        short
220    )]
221    pub force: bool,
222
223    #[arg(
224        env = "NETHSM_CONFIG_TLS_CSR_OUTPUT_FILE",
225        help = "The optional path to a specific file that the certificate is written to",
226        long,
227        short
228    )]
229    pub output: Option<PathBuf>,
230}
231
232#[derive(Debug, Parser)]
233#[command(
234    about = "Get the public key for the TLS connection",
235    long_about = ex_format!("Get the public key for the TLS connection
236
237The X.509 public key certificate is returned in Privacy-enhanced Electronic Mail (PEM) format.
238Unless a specific output file is chosen, the certificate is returned on stdout.
239
240Requires authentication of a system-wide user in the \"{Administrator}\" role."
241    )
242)]
243pub struct GetTlsPublicKeyCommand {
244    #[arg(
245        env = "NETHSM_FORCE",
246        help = "Write to output file even if it exists already",
247        long,
248        short
249    )]
250    pub force: bool,
251
252    #[arg(
253        env = "NETHSM_CONFIG_TLS_PUBKEY_OUTPUT_FILE",
254        help = "The optional path to a specific file that the certificate is written to",
255        long,
256        short
257    )]
258    pub output: Option<PathBuf>,
259}
260
261/// The "nethsm config get" command.
262#[derive(Debug, Subcommand)]
263#[command(about = "Set a configuration item for a device")]
264pub enum ConfigSetCommand {
265    /// The "nethsm config set backup-passphrase" command.
266    BackupPassphrase(SetBackupPassphraseCommand),
267    /// The "nethsm config set boot-mode" command.
268    BootMode(SetBootModeCommand),
269    /// The "nethsm config set logging" command.
270    Logging(SetLoggingCommand),
271    /// The "nethsm config set network" command.
272    Network(SetNetworkCommand),
273    /// The "nethsm config set time" command.
274    Time(SetTimeCommand),
275    /// The "nethsm config set tls-certificate" command.
276    TlsCertificate(SetTlsCertificateCommand),
277    /// The "nethsm config set tls-generate" command.
278    TlsGenerate(SetTlsGenerateCommand),
279    /// The "nethsm config set unlock-passphrase" command.
280    UnlockPassphrase(SetUnlockPassphraseCommand),
281}
282
283#[derive(Debug, Parser)]
284#[command(
285    about = "Set the backup passphrase",
286    long_about = ex_format!("Set the backup passphrase
287
288The initial backup passphrase is the empty string.
289
290The new passphrase must be >= 10 and <= 200 characters.
291
292By default the passphrases are prompted for interactively, but they can each be provided using a dedicated passphrase file instead.
293
294Requires authentication of a system-wide user in the \"{Administrator}\" role."
295    )
296)]
297pub struct SetBackupPassphraseCommand {
298    #[arg(
299        env = "NETHSM_NEW_PASSPHRASE_FILE",
300        help = "The path to a file containing the new passphrase",
301        long_help = "The path to a file containing the new passphrase
302
303The passphrase must be >= 10 and <= 200 characters long.",
304        long,
305        short
306    )]
307    pub new_passphrase_file: Option<PassphraseFile>,
308
309    #[arg(
310        env = "NETHSM_OLD_PASSPHRASE_FILE",
311        help = "The path to a file containing the old passphrase",
312        long_help = "The path to a file containing the old passphrase
313
314The passphrase must be >= 10 and <= 200 characters long.",
315        long,
316        short
317    )]
318    pub old_passphrase_file: Option<PassphraseFile>,
319}
320
321#[derive(Debug, Parser)]
322#[command(
323    about = "Set the unattended boot mode",
324    long_about = ex_format!("Set the unattended boot mode
325
326Sets whether the device boots into state \"{SystemState::Locked}\" (using boot mode \"{BootMode::Attended}\") or \"{SystemState::Operational}\" (using boot mode \"{BootMode::Unattended}\").
327
328Requires authentication of a system-wide user in the \"{Administrator}\" role."
329    ),
330)]
331pub struct SetBootModeCommand {
332    #[arg(
333        env = "NETHSM_BOOT_MODE",
334        help = "The boot mode to use",
335        long_help = format!("The boot mode to use
336
337One of {:?} (no default).",
338            BootMode::iter().map(Into::into).collect::<Vec<&'static str>>()
339        )
340    )]
341    pub boot_mode: BootMode,
342}
343
344#[derive(Debug, Parser)]
345#[command(
346    about = "Set the logging configuration",
347    long_about = ex_format!("Set the logging configuration
348
349Provide IP address and port of a host to send syslog to at a specified log level.
350
351Requires authentication of a system-wide user in the \"{Administrator}\" role."
352    )
353)]
354pub struct SetLoggingCommand {
355    #[arg(
356        env = "NETHSM_LOGGING_IP_ADDRESS",
357        help = "The IPv4 address of the host to send syslog to"
358    )]
359    pub ip_address: Ipv4Addr,
360
361    #[arg(
362        env = "NETHSM_LOGGING_PORT",
363        help = "The port of the host to send syslog to"
364    )]
365    pub port: u32,
366
367    #[arg(
368        env = "NETHSM_LOGGING_LOG_LEVEL",
369        help = "The log level at which to log",
370        long_help = format!("The log level at which to log
371
372One of {:?} (defaults to \"{:?}\").",
373            LogLevel::iter().map(Into::into).collect::<Vec<&'static str>>(),
374            LogLevel::default(),
375        )
376    )]
377    pub log_level: Option<LogLevel>,
378}
379
380#[derive(Debug, Parser)]
381#[command(
382    about = "Set the network configuration",
383    long_about = ex_format!("Set the network configuration
384
385Provide IPv4 address, netmask and Ipv4 gateway address for the device to use.
386
387Requires authentication of a system-wide user in the \"{Administrator}\" role."
388    )
389)]
390pub struct SetNetworkCommand {
391    #[arg(
392        env = "NETHSM_NETWORK_IP_ADDRESS",
393        help = "The IPv4 address the device is to use"
394    )]
395    pub ip_address: Ipv4Addr,
396
397    #[arg(
398        env = "NETHSM_NETWORK_NETMASK",
399        help = "The IPv4 netmask the device is to use"
400    )]
401    pub netmask: String,
402
403    #[arg(
404        env = "NETHSM_NETWORK_GATEWAY",
405        help = "The IPv4 gateway the device is to use"
406    )]
407    pub gateway: Ipv4Addr,
408}
409
410#[derive(Debug, Parser)]
411#[command(
412    about = "Set the time",
413    long_about = ex_format!("Set the time
414
415The time must be provided as ISO 8601 formatted UTC timestamp.
416If no timestamp is provided, the caller's current system time is used to construct a UTC timestamp.
417
418Requires authentication of a system-wide user in the \"{Administrator}\" role."
419    )
420)]
421pub struct SetTimeCommand {
422    #[arg(
423        env = "NETHSM_SYSTEM_TIME",
424        help = "An optional ISO 8601 formatted UTC timestamp",
425        long_help = "An optional ISO 8601 formatted UTC timestamp
426
427If no timestamp is provided, the caller's current system time is used."
428    )]
429    pub system_time: Option<DateTime<Utc>>,
430}
431
432#[derive(Debug, Parser)]
433#[command(
434    about = "Set a new TLS certificate",
435    long_about = ex_format!("Set a new TLS certificate
436
437The X.509 certificate must be provided in Privacy-enhanced Electronic Mail (PEM) format.
438
439The certificate is only accepted if it is created using a Certificate Signing Request (CSR) generated by the target device.
440
441Requires authentication of a system-wide user in the \"{Administrator}\" role."
442    )
443)]
444pub struct SetTlsCertificateCommand {
445    #[arg(
446        env = "NETHSM_TLS_CERT",
447        help = "A new TLS certificate file",
448        long_help = "A new TLS certificate file
449
450The X.509 certificate must be provided in Privacy-enhanced Electronic Mail (PEM) format."
451    )]
452    pub tls_cert: PathBuf,
453}
454
455#[derive(Debug, Parser)]
456#[command(
457    about = "Generate a new TLS certificate",
458    long_about = ex_format!("Generate a new TLS certificate
459
460The current TLS certificate is replaced by the newly generated one.
461Optionally, the type of key and its length can be specified.
462
463Requires authentication of a system-wide user in the \"{Administrator}\" role."
464    )
465)]
466pub struct SetTlsGenerateCommand {
467    #[arg(
468        env = "NETHSM_TLS_KEY_TYPE",
469        help = "The optional key type of the TLS certificate to generate",
470        long_help = format!("The optional key type of the TLS certificate to generate
471
472One of {:?} (defaults to \"{}\").",
473            TlsKeyType::iter().map(Into::into).collect::<Vec<&'static str>>(),
474            TlsKeyType::default(),
475        ),
476    )]
477    pub tls_key_type: Option<TlsKeyType>,
478
479    #[arg(
480        env = "NETHSM_TLS_KEY_LENGTH",
481        help = "The bit length of the TLS key to generate",
482        long_help = ex_format!("The optional bit length of the TLS key to generate
483
484The bit length must be compatible with the chosen key type.
485
486Requires authentication of a user in the \"{Administrator}\" role.")
487    )]
488    pub tls_key_length: Option<u32>,
489}
490
491#[derive(Debug, Parser)]
492#[command(
493    about = "Set the unlock passphrase",
494    long_about = ex_format!("Set the unlock passphrase
495
496The initial unlock passphrase is set during provisioning.
497
498The new passphrase must be >= 10 and <= 200 characters.
499
500By default the passphrases are prompted for interactively, but they can each be provided using a dedicated passphrase file instead.
501
502Requires authentication of a system-wide user in the \"{Administrator}\" role."
503    )
504)]
505pub struct SetUnlockPassphraseCommand {
506    #[arg(
507        env = "NETHSM_NEW_PASSPHRASE_FILE",
508        help = "The path to a file containing the new passphrase",
509        long_help = "The path to a file containing the new passphrase
510
511The passphrase must be >= 10 and <= 200 characters long.",
512        long,
513        short
514    )]
515    pub new_passphrase_file: Option<PassphraseFile>,
516
517    #[arg(
518        env = "NETHSM_OLD_PASSPHRASE_FILE",
519        help = "The path to a file containing the old passphrase",
520        long_help = "The path to a file containing the old passphrase
521
522The passphrase must be >= 10 and <= 200 characters long.",
523        long,
524        short
525    )]
526    pub old_passphrase_file: Option<PassphraseFile>,
527}