From ca15df3e5d3b7a0e8837b188f6327bb46b7a5536 Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Sat, 5 Nov 2022 09:16:31 +0200 Subject: fix: drop unnecessary borrow Sponsored-by: author --- src/cloudinit.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cloudinit.rs b/src/cloudinit.rs index 9d14538..ad32f2a 100644 --- a/src/cloudinit.rs +++ b/src/cloudinit.rs @@ -198,7 +198,7 @@ struct Userdata { impl Userdata { fn from(spec: &Specification) -> Result { let user_ca_pubkey = if let Some(filename) = &spec.user_ca_pubkey { - let data = std::fs::read(&filename) + let data = std::fs::read(filename) .map_err(|err| CloudInitError::ReadError(filename.to_path_buf(), err))?; Some(String::from_utf8(data)?) } else { -- cgit v1.2.1 From b74de5a065c5c73e5592235e013385fadc9b17ed Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Sat, 5 Nov 2022 09:36:11 +0200 Subject: refactor: move the cloud init Python script to a separate file This required adding a build.rs to generate a Rust source from the Python file. Sponsored-by: author --- build.rs | 11 +++++++ cloud-init.py | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/cloudinit.rs | 93 +------------------------------------------------------- 3 files changed, 102 insertions(+), 92 deletions(-) create mode 100644 build.rs create mode 100644 cloud-init.py diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..278a7c6 --- /dev/null +++ b/build.rs @@ -0,0 +1,11 @@ +use std::fs::{read, write}; +use std::path::PathBuf; + +fn main() { + let py = read("cloud-init.py").unwrap(); + let py = String::from_utf8_lossy(&py).to_string(); + + let mut path: PathBuf = std::env::var("OUT_DIR").unwrap().into(); + path.push("cloud-init.rs"); + write(&path, &format!("r#\"{}\"#\n", py)).unwrap(); +} diff --git a/cloud-init.py b/cloud-init.py new file mode 100644 index 0000000..814a5b7 --- /dev/null +++ b/cloud-init.py @@ -0,0 +1,90 @@ +import os +import yaml + + +def log(msg): + logfile.write(msg) + logfile.write("\n") + logfile.flush() + + +logfile = open("/tmp/vmadm.script", "w") +log("vmadm cloud-init script starting") + +if os.environ.get("VMADM_TESTING"): + filename = "smoke/user-data" + etc = "x" +else: + filename = "/var/lib/cloud/instance/user-data.txt" + etc = "/etc/ssh" + +key_types = ("rsa", "dsa", "ecdsa", "ed25519") + +log(f"loading user-data from {filename}") +obj = yaml.safe_load(open(filename)) + +ssh_keys = obj.get("ssh_keys", {}) +user_ca_pubkey = obj.get("user_ca_pubkey", {}) +allow_authorized_keys = obj.get("allow_authorized_keys", True) + +keys = [] +certs = [] + +for key_type in key_types: + filename = os.path.join(etc, f"ssh_host_{key_type}_key.pub") + if os.path.exists(filename): + log(f"removing {filename}") + os.remove(filename) + else: + log(f"file {filename} does not exist") + +for key_type in key_types: + key = ssh_keys.get(f"{key_type}_private") + cert = ssh_keys.get(f"{key_type}_certificate") + log(f"key {key_type} {key}") + log(f"cert {key_type} {cert }") + + if key: + filename = os.path.join(etc, f"ssh_host_{key_type}_key") + log(f"writing key {filename}") + keys.append(filename) + with open(filename, "w") as f: + f.write(key) + + if cert: + filename = os.path.join(etc, f"ssh_host_{key_type}_key-cert.pub") + log(f"writing cert {filename}") + certs.append(filename) + with open(filename, "w") as f: + f.write(cert) + +user_ca_filename = os.path.join(etc, "user-ca-keys") +if user_ca_pubkey: + with open(user_ca_filename, "w") as f: + f.write(user_ca_pubkey) + +config = os.path.join(etc, "sshd_config") +data = "" +if os.path.exists(config): + data = open(config).read() + +log(f"configuring sshd {config}") +log(f"keys {keys}") +log(f"certs {certs}") + +with open(config, "w") as f: + for filename in keys: + log(f"hostkey {filename}") + f.write(f"hostkey {filename}\n") + for filename in certs: + log(f"hostcert {filename}") + f.write(f"hostcertificate {filename}\n") + if user_ca_pubkey: + log(f"trustedusercakeys {user_ca_filename}") + f.write(f"trustedusercakeys {user_ca_filename}\n") + if not allow_authorized_keys: + f.write("authorizedkeysfile none\n") + f.write(data) + +log("vmadm cloud-init script ending") +logfile.close() diff --git a/src/cloudinit.rs b/src/cloudinit.rs index ad32f2a..6057966 100644 --- a/src/cloudinit.rs +++ b/src/cloudinit.rs @@ -17,98 +17,7 @@ use std::path::{Path, PathBuf}; use std::process::Command; use tempfile::tempdir; -const SCRIPT: &str = r#" -import os -import yaml - - -def log(msg): - logfile.write(msg) - logfile.write("\n") - logfile.flush() - - -logfile = open("/tmp/vmadm.script", "w") -log("vmadm cloud-init script starting") - -if os.environ.get("VMADM_TESTING"): - filename = "smoke/user-data" - etc = "x" -else: - filename = "/var/lib/cloud/instance/user-data.txt" - etc = "/etc/ssh" - -key_types = ("rsa", "dsa", "ecdsa", "ed25519") - -log(f"loading user-data from {filename}") -obj = yaml.safe_load(open(filename)) - -ssh_keys = obj.get("ssh_keys", {}) -user_ca_pubkey = obj.get("user_ca_pubkey", {}) -allow_authorized_keys = obj.get("allow_authorized_keys", True) - -keys = [] -certs = [] - -for key_type in key_types: - filename = os.path.join(etc, f"ssh_host_{key_type}_key.pub") - if os.path.exists(filename): - log(f"removing {filename}") - os.remove(filename) - else: - log(f"file {filename} does not exist") - -for key_type in key_types: - key = ssh_keys.get(f"{key_type}_private") - cert = ssh_keys.get(f"{key_type}_certificate") - log(f"key {key_type} {key}") - log(f"cert {key_type} {cert }") - - if key: - filename = os.path.join(etc, f"ssh_host_{key_type}_key") - log(f"writing key {filename}") - keys.append(filename) - with open(filename, "w") as f: - f.write(key) - - if cert: - filename = os.path.join(etc, f"ssh_host_{key_type}_key-cert.pub") - log(f"writing cert {filename}") - certs.append(filename) - with open(filename, "w") as f: - f.write(cert) - -user_ca_filename = os.path.join(etc, "user-ca-keys") -if user_ca_pubkey: - with open(user_ca_filename, "w") as f: - f.write(user_ca_pubkey) - -config = os.path.join(etc, "sshd_config") -data = "" -if os.path.exists(config): - data = open(config).read() - -log(f"configuring sshd {config}") -log(f"keys {keys}") -log(f"certs {certs}") - -with open(config, "w") as f: - for filename in keys: - log(f"hostkey {filename}") - f.write(f"hostkey {filename}\n") - for filename in certs: - log(f"hostcert {filename}") - f.write(f"hostcertificate {filename}\n") - if user_ca_pubkey: - log(f"trustedusercakeys {user_ca_filename}") - f.write(f"trustedusercakeys {user_ca_filename}\n") - if not allow_authorized_keys: - f.write("authorizedkeysfile none\n") - f.write(data) - -log("vmadm cloud-init script ending") -logfile.close() -"#; +const SCRIPT: &str = include!(concat!(env!("OUT_DIR"), "/cloud-init.rs")); /// Errors from this module. #[derive(Debug, thiserror::Error)] -- cgit v1.2.1 From 69986bb3e7baa8eef245d81e85cf03614102ebc2 Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Sat, 5 Nov 2022 09:43:01 +0200 Subject: refactor: use a named constant for name of file with user CA keys Sponsored-by: author --- cloud-init.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cloud-init.py b/cloud-init.py index 814a5b7..52dd895 100644 --- a/cloud-init.py +++ b/cloud-init.py @@ -1,6 +1,8 @@ import os import yaml +USER_CA_KEYS = "user-ca-keys" + def log(msg): logfile.write(msg) @@ -58,7 +60,7 @@ for key_type in key_types: with open(filename, "w") as f: f.write(cert) -user_ca_filename = os.path.join(etc, "user-ca-keys") +user_ca_filename = os.path.join(etc, USER_CA_KEYS) if user_ca_pubkey: with open(user_ca_filename, "w") as f: f.write(user_ca_pubkey) -- cgit v1.2.1 From 12391ce9978cc689c0eda67cb26232ce30ae8865 Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Sat, 5 Nov 2022 11:32:55 +0200 Subject: refactor: extract name of log file into a named constant Sponsored-by: author --- cloud-init.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cloud-init.py b/cloud-init.py index 52dd895..377b770 100644 --- a/cloud-init.py +++ b/cloud-init.py @@ -4,13 +4,16 @@ import yaml USER_CA_KEYS = "user-ca-keys" +LGGFILE = "/tmp/vmadm.script" + + def log(msg): logfile.write(msg) logfile.write("\n") logfile.flush() -logfile = open("/tmp/vmadm.script", "w") +logfile = open(LOGFILE, "w") log("vmadm cloud-init script starting") if os.environ.get("VMADM_TESTING"): -- cgit v1.2.1 From 0915a60346d3bb9d75d9f95958279c0f46337431 Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Sat, 5 Nov 2022 11:43:30 +0200 Subject: refactor: make more named constants Sponsored-by: author --- cloud-init.py | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/cloud-init.py b/cloud-init.py index 377b770..3618ad8 100644 --- a/cloud-init.py +++ b/cloud-init.py @@ -4,7 +4,14 @@ import yaml USER_CA_KEYS = "user-ca-keys" +ETC = "/etc/ssh" +CONFIG = "ssh_config" LGGFILE = "/tmp/vmadm.script" +USER_DATA = "/var/lib/cloud/instance/user-data.txt" + + +def etc_join(*paths): + return os.path.join(etc, *paths) def log(msg): @@ -20,8 +27,8 @@ if os.environ.get("VMADM_TESTING"): filename = "smoke/user-data" etc = "x" else: - filename = "/var/lib/cloud/instance/user-data.txt" - etc = "/etc/ssh" + filename = USER_DATA + etc = ETC key_types = ("rsa", "dsa", "ecdsa", "ed25519") @@ -36,7 +43,7 @@ keys = [] certs = [] for key_type in key_types: - filename = os.path.join(etc, f"ssh_host_{key_type}_key.pub") + filename = etc_join(f"ssh_host_{key_type}_key.pub") if os.path.exists(filename): log(f"removing {filename}") os.remove(filename) @@ -50,25 +57,25 @@ for key_type in key_types: log(f"cert {key_type} {cert }") if key: - filename = os.path.join(etc, f"ssh_host_{key_type}_key") + filename = etc_join(f"ssh_host_{key_type}_key") log(f"writing key {filename}") keys.append(filename) with open(filename, "w") as f: f.write(key) if cert: - filename = os.path.join(etc, f"ssh_host_{key_type}_key-cert.pub") + filename = etc_join(f"ssh_host_{key_type}_key-cert.pub") log(f"writing cert {filename}") certs.append(filename) with open(filename, "w") as f: f.write(cert) -user_ca_filename = os.path.join(etc, USER_CA_KEYS) +user_ca_filename = etc_join(USER_CA_KEYS) if user_ca_pubkey: with open(user_ca_filename, "w") as f: f.write(user_ca_pubkey) -config = os.path.join(etc, "sshd_config") +config = etc_join(CONFIG) data = "" if os.path.exists(config): data = open(config).read() -- cgit v1.2.1 From e3942be72b103f3ca99e836e5bc15abfbb504178 Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Sat, 5 Nov 2022 12:02:13 +0200 Subject: refactor: write a host_id.conf file with keys, certs listed Sponsored-by: author --- cloud-init.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/cloud-init.py b/cloud-init.py index 3618ad8..abbbcb8 100644 --- a/cloud-init.py +++ b/cloud-init.py @@ -1,11 +1,13 @@ import os import yaml +HOST_ID_CONF = "host_id.conf" USER_CA_KEYS = "user-ca-keys" ETC = "/etc/ssh" CONFIG = "ssh_config" +CONFIG_D = "ssh_config" LGGFILE = "/tmp/vmadm.script" USER_DATA = "/var/lib/cloud/instance/user-data.txt" @@ -84,13 +86,23 @@ log(f"configuring sshd {config}") log(f"keys {keys}") log(f"certs {certs}") -with open(config, "w") as f: +config_d = etc_join(CONFIG_D) +if not os.path.exists(config_d): + log(f"mkdir {config_d}") + os.mkdir(config_d) + +host_id_conf = etc.join(CONFIG_D, HOST_ID_CONF) +log(f"write {host_id_conf}") +with open(host_id_conf, "w") as f: for filename in keys: log(f"hostkey {filename}") f.write(f"hostkey {filename}\n") for filename in certs: log(f"hostcert {filename}") f.write(f"hostcertificate {filename}\n") + + +with open(config, "w") as f: if user_ca_pubkey: log(f"trustedusercakeys {user_ca_filename}") f.write(f"trustedusercakeys {user_ca_filename}\n") -- cgit v1.2.1 From b21b24e9681e81fff897c0ac90e51edc204a45d0 Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Sat, 5 Nov 2022 12:12:36 +0200 Subject: feat: create user_ca.conf Sponsored-by: author --- cloud-init.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/cloud-init.py b/cloud-init.py index abbbcb8..42997e7 100644 --- a/cloud-init.py +++ b/cloud-init.py @@ -2,9 +2,9 @@ import os import yaml HOST_ID_CONF = "host_id.conf" +HOST_CA_CONF = "host_id.conf" USER_CA_KEYS = "user-ca-keys" - ETC = "/etc/ssh" CONFIG = "ssh_config" CONFIG_D = "ssh_config" @@ -101,11 +101,14 @@ with open(host_id_conf, "w") as f: log(f"hostcert {filename}") f.write(f"hostcertificate {filename}\n") - -with open(config, "w") as f: - if user_ca_pubkey: +if user_ca_pubkey: + user_ca_conf = etc.join(CONFIG_D, USER_CA_CONF) + log(f"write {user_ca_conf}") + with open(user_ca_conf, "w") as f: log(f"trustedusercakeys {user_ca_filename}") f.write(f"trustedusercakeys {user_ca_filename}\n") + +with open(config, "w") as f: if not allow_authorized_keys: f.write("authorizedkeysfile none\n") f.write(data) -- cgit v1.2.1 From 3c7dbac88da5e428f29b95860fac6b35eaec12cd Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Sat, 5 Nov 2022 12:38:48 +0200 Subject: feat: write authorized_keys.conf Sponsored-by: author --- cloud-init.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/cloud-init.py b/cloud-init.py index 42997e7..6e2a9a0 100644 --- a/cloud-init.py +++ b/cloud-init.py @@ -4,6 +4,7 @@ import yaml HOST_ID_CONF = "host_id.conf" HOST_CA_CONF = "host_id.conf" USER_CA_KEYS = "user-ca-keys" +AUTH_KEYS_CONF = "authorized_keys.conf" ETC = "/etc/ssh" CONFIG = "ssh_config" @@ -82,6 +83,9 @@ data = "" if os.path.exists(config): data = open(config).read() +with open(config, "w") as f: + f.write(data) + log(f"configuring sshd {config}") log(f"keys {keys}") log(f"certs {certs}") @@ -108,10 +112,11 @@ if user_ca_pubkey: log(f"trustedusercakeys {user_ca_filename}") f.write(f"trustedusercakeys {user_ca_filename}\n") -with open(config, "w") as f: - if not allow_authorized_keys: +if not allow_authorized_keys: + authz_keys_conf = etc.join(CONFIG_D, AUTHZ_KEYS_CONF) + log(f"write {authz_keys_conf}") + with open(auth_keys_conf, "w") as f: f.write("authorizedkeysfile none\n") - f.write(data) log("vmadm cloud-init script ending") logfile.close() -- cgit v1.2.1 From 2fa8f7c0e765b4f58d0a27fe4b20a8afa45a59da Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Sat, 5 Nov 2022 12:59:31 +0200 Subject: fix: some file names Sponsored-by: author --- cloud-init.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/cloud-init.py b/cloud-init.py index 6e2a9a0..21d8ff9 100644 --- a/cloud-init.py +++ b/cloud-init.py @@ -2,14 +2,14 @@ import os import yaml HOST_ID_CONF = "host_id.conf" -HOST_CA_CONF = "host_id.conf" +USER_CA_CONF = "user_id.conf" USER_CA_KEYS = "user-ca-keys" AUTH_KEYS_CONF = "authorized_keys.conf" ETC = "/etc/ssh" -CONFIG = "ssh_config" -CONFIG_D = "ssh_config" -LGGFILE = "/tmp/vmadm.script" +CONFIG = "sshd_config" +CONFIG_D = "sshd_config.d" +LOGFILE = "/tmp/vmadm.script" USER_DATA = "/var/lib/cloud/instance/user-data.txt" @@ -91,11 +91,12 @@ log(f"keys {keys}") log(f"certs {certs}") config_d = etc_join(CONFIG_D) +log(f"config.d {CONFIG_D}") if not os.path.exists(config_d): log(f"mkdir {config_d}") os.mkdir(config_d) -host_id_conf = etc.join(CONFIG_D, HOST_ID_CONF) +host_id_conf = etc_join(CONFIG_D, HOST_ID_CONF) log(f"write {host_id_conf}") with open(host_id_conf, "w") as f: for filename in keys: @@ -106,14 +107,14 @@ with open(host_id_conf, "w") as f: f.write(f"hostcertificate {filename}\n") if user_ca_pubkey: - user_ca_conf = etc.join(CONFIG_D, USER_CA_CONF) + user_ca_conf = etc_join(CONFIG_D, USER_CA_CONF) log(f"write {user_ca_conf}") with open(user_ca_conf, "w") as f: log(f"trustedusercakeys {user_ca_filename}") f.write(f"trustedusercakeys {user_ca_filename}\n") if not allow_authorized_keys: - authz_keys_conf = etc.join(CONFIG_D, AUTHZ_KEYS_CONF) + authz_keys_conf = etc_join(CONFIG_D, AUTHZ_KEYS_CONF) log(f"write {authz_keys_conf}") with open(auth_keys_conf, "w") as f: f.write("authorizedkeysfile none\n") -- cgit v1.2.1