diff options
author | Lars Wirzenius <liw@liw.fi> | 2021-03-07 09:01:23 +0200 |
---|---|---|
committer | Lars Wirzenius <liw@liw.fi> | 2021-03-07 12:25:19 +0200 |
commit | 4621b07522564f6a3c1c2ad0484fb88cf0e2ce49 (patch) | |
tree | 8f8c33437771322c2c5c2c40d79151320beb2beb /src/cloudinit.rs | |
parent | a6f802fda57fc7e951c0374a268de2274718cd9d (diff) | |
download | vmadm-4621b07522564f6a3c1c2ad0484fb88cf0e2ce49.tar.gz |
feat: generate SSH key pairs, create host certificates
Diffstat (limited to 'src/cloudinit.rs')
-rw-r--r-- | src/cloudinit.rs | 37 |
1 files changed, 31 insertions, 6 deletions
diff --git a/src/cloudinit.rs b/src/cloudinit.rs index 6e62cc5..842baa7 100644 --- a/src/cloudinit.rs +++ b/src/cloudinit.rs @@ -1,7 +1,9 @@ use crate::spec::{Specification, SpecificationError}; +use crate::sshkeys::{CaKey, KeyError, KeyKind, KeyPair}; use log::debug; use serde::{Deserialize, Serialize}; use shell_words::quote; +use std::default::Default; use std::fs::write; // use std::os::unix::fs::PermissionsExt; use std::path::Path; @@ -92,6 +94,9 @@ logfile.close() #[derive(Debug, thiserror::Error)] pub enum CloudInitError { + #[error("Host certificate requested, but no CA key specified")] + NoCAKey, + #[error("failed to create ISO image with genisoimage: {0}")] IsoFailed(String), @@ -99,6 +104,9 @@ pub enum CloudInitError { SpecificationError(#[from] SpecificationError), #[error(transparent)] + KeyError(#[from] KeyError), + + #[error(transparent)] IoError(#[from] std::io::Error), #[error(transparent)] @@ -148,7 +156,7 @@ impl Userdata { fn from(spec: &Specification) -> Result<Self, CloudInitError> { Ok(Self { ssh_authorized_keys: spec.ssh_keys.clone(), - ssh_keys: Hostkeys::from(spec), + ssh_keys: Hostkeys::from(spec)?, runcmd: vec![ format!("python3 -c {}", quote(SCRIPT)), "systemctl reload ssh".to_string(), @@ -165,7 +173,7 @@ impl Userdata { } } -#[derive(Clone, Debug, Deserialize, Serialize)] +#[derive(Clone, Debug, Deserialize, Serialize, Default)] struct Hostkeys { #[serde(skip_serializing_if = "Option::is_none")] rsa_private: Option<String>, @@ -193,7 +201,7 @@ struct Hostkeys { } impl Hostkeys { - fn from(spec: &Specification) -> Option<Self> { + fn from(spec: &Specification) -> Result<Option<Self>, CloudInitError> { let rsa = spec.rsa_host_key.clone(); let rsa_cert = spec.rsa_host_cert.clone(); @@ -207,7 +215,7 @@ impl Hostkeys { let ed25519_cert = spec.ed25519_host_cert.clone(); if rsa.is_some() || dsa.is_some() || ecdsa.is_some() || ed25519.is_some() { - Some(Self { + Ok(Some(Self { rsa_private: rsa, rsa_certificate: rsa_cert, dsa_private: dsa, @@ -216,9 +224,26 @@ impl Hostkeys { ecdsa_certificate: ecdsa_cert, ed25519_private: ed25519, ed25519_certificate: ed25519_cert, - }) + })) + } else if spec.generate_host_certificate { + if spec.ca_key.is_none() { + return Err(CloudInitError::NoCAKey); + } + if let Some(filename) = &spec.ca_key { + let ca = CaKey::from_file(&filename)?; + let pair = KeyPair::generate(KeyKind::Ed25519)?; + let cert = ca.certify_host(&pair, &spec.name)?; + debug!("generated Ed25519 host certificate {:?}", cert); + Ok(Some(Self { + ed25519_private: Some(pair.public().to_string()), + ed25519_certificate: Some(cert.to_string()), + ..Self::default() + })) + } else { + Ok(None) + } } else { - None + Ok(None) } } } |