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