Generate SSH key on startup if it does not already exist; add API endpoint to get SSH public key
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
pub mod node;
|
||||
pub mod carrier;
|
||||
pub mod volume;
|
||||
pub mod system;
|
||||
|
||||
42
src/api/cluster/system.rs
Normal file
42
src/api/cluster/system.rs
Normal file
@@ -0,0 +1,42 @@
|
||||
use std::env;
|
||||
use std::fs::{File, Permissions};
|
||||
use std::io::Write;
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
use std::path::Path;
|
||||
use log::info;
|
||||
use rand::rngs::OsRng;
|
||||
use ssh_key::{PrivateKey, Algorithm, LineEnding};
|
||||
|
||||
|
||||
/** Check if the SSH pubkey/privkey exist at the configured paths. If not, generate them. */
|
||||
pub fn ensure_ssh_keypair() -> Result<(), ssh_key::Error> {
|
||||
let pubkey_path = env::var("P5X_SSH_PUBKEY_PATH").expect("Missing env: P5X_SSH_PUBKEY_PATH");
|
||||
let privkey_path = env::var("P5X_SSH_PRIVKEY_PATH").expect("Missing env: P5X_SSH_PRIVKEY_PATH");
|
||||
|
||||
// If both exist, then p5x will boot correctly when it reads from the files.
|
||||
// If only one of the two files exists, p5x will error on boot. This is safer
|
||||
// than accidentally overwriting someone's key.
|
||||
if Path::new(&pubkey_path).exists() || Path::new(&privkey_path).exists() {
|
||||
info!(target: "p5x", "Found existing SSH keypair on filesystem");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Generate an ed25519 keypair
|
||||
info!(target: "p5x", "Generating a new SSH keypair");
|
||||
let mut csprng = OsRng;
|
||||
let privkey = PrivateKey::random(&mut csprng, Algorithm::Ed25519)?;
|
||||
|
||||
// Write the privkey to a file
|
||||
let privkey_pem = privkey.to_openssh(LineEnding::LF)?;
|
||||
let mut privkey_file = File::create(privkey_path)?;
|
||||
privkey_file.write_all(privkey_pem.as_bytes())?;
|
||||
privkey_file.set_permissions(Permissions::from_mode(0o600))?;
|
||||
|
||||
// Write the pubkey to a file
|
||||
let pubkey = privkey.public_key();
|
||||
let pubkey_ssh = pubkey.to_openssh()?;
|
||||
let mut pubkey_file = File::create(pubkey_path)?;
|
||||
pubkey_file.write_all(pubkey_ssh.as_bytes())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -3,7 +3,7 @@ use rocket::fairing::AdHoc;
|
||||
mod db;
|
||||
mod route;
|
||||
pub mod util;
|
||||
mod cluster;
|
||||
pub mod cluster;
|
||||
pub mod entity;
|
||||
pub use db::Db;
|
||||
pub mod services;
|
||||
|
||||
@@ -2,10 +2,12 @@ use rocket::fairing::AdHoc;
|
||||
|
||||
mod volume;
|
||||
mod node;
|
||||
mod system;
|
||||
|
||||
pub(super) fn init() -> AdHoc {
|
||||
AdHoc::on_ignite("Registering routes", |rocket| async {
|
||||
rocket.attach(volume::init())
|
||||
.attach(node::init())
|
||||
.attach(system::init())
|
||||
})
|
||||
}
|
||||
|
||||
15
src/api/route/system.rs
Normal file
15
src/api/route/system.rs
Normal file
@@ -0,0 +1,15 @@
|
||||
use rocket::fairing::AdHoc;
|
||||
use rocket::response::status;
|
||||
use crate::api::util::read_p5x_config;
|
||||
|
||||
#[get("/pubkey")]
|
||||
fn get_pubkey() -> Result<String, status::Custom<String>> {
|
||||
let config = read_p5x_config();
|
||||
Ok(config.ssh_pubkey)
|
||||
}
|
||||
|
||||
pub(super) fn init() -> AdHoc {
|
||||
AdHoc::on_ignite("Routes: /system", |rocket| async {
|
||||
rocket.mount("/system", routes![get_pubkey])
|
||||
})
|
||||
}
|
||||
@@ -4,6 +4,7 @@ use dotenv::dotenv;
|
||||
use rocket::{Build, Rocket};
|
||||
use log::{error, info};
|
||||
use std::{env, process};
|
||||
use crate::api::cluster::system::ensure_ssh_keypair;
|
||||
use crate::api::util::read_p5x_config;
|
||||
|
||||
fn configure_rocket() -> Rocket<Build> {
|
||||
@@ -23,6 +24,8 @@ async fn main() {
|
||||
process::exit(1);
|
||||
}
|
||||
|
||||
ensure_ssh_keypair().expect("Could not ensure SSH keypair exists.");
|
||||
|
||||
let config = read_p5x_config(); // Do this so we early-fail if there are missing env vars
|
||||
info!(target: "p5x", "Successfully read config from environment.");
|
||||
info!(target: "p5x", "Cluster host: {} ({})", config.pve_host_name, config.pve_api_host);
|
||||
|
||||
Reference in New Issue
Block a user