From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by lists.proxmox.com (Postfix) with ESMTPS id 8A32F973E5 for ; Tue, 16 Apr 2024 17:37:48 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 71B4330093 for ; Tue, 16 Apr 2024 17:37:48 +0200 (CEST) Received: from proxmox-new.maurer-it.com (proxmox-new.maurer-it.com [94.136.29.106]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by firstgate.proxmox.com (Proxmox) with ESMTPS for ; Tue, 16 Apr 2024 17:37:46 +0200 (CEST) Received: from proxmox-new.maurer-it.com (localhost.localdomain [127.0.0.1]) by proxmox-new.maurer-it.com (Proxmox) with ESMTP id 1C9A645AAC for ; Tue, 16 Apr 2024 17:33:35 +0200 (CEST) From: Aaron Lauterer To: pve-devel@lists.proxmox.com Date: Tue, 16 Apr 2024 17:33:23 +0200 Message-Id: <20240416153325.1154224-35-a.lauterer@proxmox.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20240416153325.1154224-1-a.lauterer@proxmox.com> References: <20240416153325.1154224-1-a.lauterer@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 0 AWL -0.098 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment PROLO_LEO2 0.1 Meta Catches all Leo drug variations so far SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Subject: [pve-devel] [PATCH installer v5 34/36] fetch-answer: use ISO specified configurations X-BeenThere: pve-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox VE development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 16 Apr 2024 15:37:48 -0000 This patch switches the behavior to use the settings that can be specified in the ISO. This means, that it is possible to control how the answer file should be fetched: * auto - as usually, go through the options until one works (partition, http) * included - the answer file is included in the ISO * partition - only check for an answer file in a partition called 'proxmoxinst' in lower or uppercase * http - only fetch the answer file via an HTTP POST request. Additionally it is possible to specify the HTTP URL directly in the ISO. Placing the SSL fingerprint on a partition is not possible anymore. If one wants to provide it right away (besides DHCP or DNS), it must be incluced in the ISO itself. This reduced the need for another USB flash drive. Signed-off-by: Aaron Lauterer --- proxmox-fetch-answer/Cargo.toml | 1 + .../src/fetch_plugins/http.rs | 65 +++++++------------ proxmox-fetch-answer/src/main.rs | 64 ++++++++++++++---- 3 files changed, 77 insertions(+), 53 deletions(-) diff --git a/proxmox-fetch-answer/Cargo.toml b/proxmox-fetch-answer/Cargo.toml index fbcca46..797c185 100644 --- a/proxmox-fetch-answer/Cargo.toml +++ b/proxmox-fetch-answer/Cargo.toml @@ -17,6 +17,7 @@ log = "0.4.20" ureq = { version = "2.6", features = [ "native-certs", "native-tls" ] } rustls = { version = "0.20", features = [ "dangerous_configuration" ] } rustls-native-certs = "0.6" +toml = "0.7" native-tls = "0.2" sha2 = "0.10" hex = "0.4" diff --git a/proxmox-fetch-answer/src/fetch_plugins/http.rs b/proxmox-fetch-answer/src/fetch_plugins/http.rs index 5772c42..b5550fe 100644 --- a/proxmox-fetch-answer/src/fetch_plugins/http.rs +++ b/proxmox-fetch-answer/src/fetch_plugins/http.rs @@ -2,16 +2,12 @@ use anyhow::{bail, Error, Result}; use log::info; use std::{ fs::{self, read_to_string}, - path::Path, process::Command, }; use crate::fetch_plugins::utils::post; -use proxmox_auto_installer::sysinfo; +use proxmox_auto_installer::{sysinfo, utils::AutoInstSettings}; -use super::utils; - -static CERT_FINGERPRINT_FILE: &str = "cert_fingerprint.txt"; static ANSWER_SUBDOMAIN: &str = "proxmoxinst"; static ANSWER_SUBDOMAIN_FP: &str = "proxmoxinst-fp"; @@ -37,30 +33,33 @@ pub struct FetchFromHTTP; impl FetchFromHTTP { /// Will try to fetch the answer.toml by sending a HTTP POST request. The URL can be configured - /// either via DHCP or DNS. - /// DHCP options are checked first. The SSL certificate need to be either trusted by the root - /// certs or a SHA256 fingerprint needs to be provided. The SHA256 SSL fingerprint can either - /// be placed in a `cert_fingerprint.txt` file in the `proxmoxinst` partition, as DHCP option, - /// or as DNS TXT record. If provided, the `cert_fingerprint.txt` file has preference. - pub fn get_answer() -> Result { - info!("Checking for certificate fingerprint in file."); - let mut fingerprint: Option = match Self::get_cert_fingerprint_from_file() { - Ok(fp) => Some(fp), - Err(err) => { - info!("{err}"); - None + /// either via DHCP or DNS or preconfigured in the ISO. + /// If the URL is not defined in the ISO, it will first check DHCP options. The SSL certificate + /// needs to be either trusted by the root certs or a SHA256 fingerprint needs to be provided. + /// The SHA256 SSL fingerprint can either be defined in the ISO, as DHCP option, or as DNS TXT + /// record. If provided, the fingerprint provided in the ISO has preference. + pub fn get_answer(settings: &AutoInstSettings) -> Result { + let mut fingerprint: Option = match settings.ssl_fingerprint.clone() { + Some(fp) => { + info!("SSL fingerprint provided through ISO."); + Some(fp) } + None => None, }; let answer_url: String; - - (answer_url, fingerprint) = match Self::fetch_dhcp(fingerprint.clone()) { - Ok((url, fp)) => (url, fp), - Err(err) => { - info!("{err}"); - Self::fetch_dns(fingerprint.clone())? - } - }; + if let Some(url) = settings.http_url.clone() { + info!("URL specified in ISO"); + answer_url = url; + } else { + (answer_url, fingerprint) = match Self::fetch_dhcp(fingerprint.clone()) { + Ok((url, fp)) => (url, fp), + Err(err) => { + info!("{err}"); + Self::fetch_dns(fingerprint.clone())? + } + }; + } if fingerprint.is_some() { let fp = fingerprint.clone(); @@ -74,22 +73,6 @@ impl FetchFromHTTP { Ok(answer) } - /// Reads certificate fingerprint from file - pub fn get_cert_fingerprint_from_file() -> Result { - let mount_path = utils::mount_proxmoxinst_part()?; - let cert_path = Path::new(mount_path.as_str()).join(CERT_FINGERPRINT_FILE); - match cert_path.try_exists() { - Ok(true) => { - info!("Found certifacte fingerprint file."); - Ok(fs::read_to_string(cert_path)?.trim().into()) - } - _ => Err(Error::msg(format!( - "could not find cert fingerprint file expected at: {}", - cert_path.display() - ))), - } - } - /// Fetches search domain from resolv.conf file fn get_search_domain() -> Result { info!("Retrieving default search domain."); diff --git a/proxmox-fetch-answer/src/main.rs b/proxmox-fetch-answer/src/main.rs index 8c762e9..fe5d599 100644 --- a/proxmox-fetch-answer/src/main.rs +++ b/proxmox-fetch-answer/src/main.rs @@ -1,13 +1,15 @@ use anyhow::{anyhow, Error, Result}; use fetch_plugins::{http::FetchFromHTTP, partition::FetchFromPartition}; use log::{error, info, LevelFilter}; -use proxmox_auto_installer::log::AutoInstLogger; +use proxmox_auto_installer::{log::AutoInstLogger, utils::{AutoInstModes, AutoInstSettings}}; +use std::{fs, path::PathBuf}; use std::io::Write; use std::process::{Command, ExitCode, Stdio}; mod fetch_plugins; static LOGGER: AutoInstLogger = AutoInstLogger; +static AUTOINST_MODE_FILE: &str = "/cdrom/autoinst-mode.toml"; pub fn init_log() -> Result<()> { AutoInstLogger::init("/tmp/fetch_answer.log")?; @@ -16,16 +18,40 @@ pub fn init_log() -> Result<()> { .map_err(|err| anyhow!(err)) } -fn fetch_answer() -> Result { - match FetchFromPartition::get_answer() { - Ok(answer) => return Ok(answer), - Err(err) => info!("Fetching answer file from partition failed: {err}"), - } - match FetchFromHTTP::get_answer() { - Ok(answer) => return Ok(answer), - Err(err) => info!("Fetching answer file via HTTP failed: {err}"), - } +fn fetch_answer(install_settings: &AutoInstSettings) -> Result { + info!("Fetching answer file in mode {:?}:", &install_settings.mode); + match install_settings.mode { + AutoInstModes::Auto => { + match FetchFromPartition::get_answer() { + Ok(answer) => return Ok(answer), + Err(err) => info!("Fetching answer file from partition failed: {err}"), + } + match FetchFromHTTP::get_answer(install_settings) { + Ok(answer) => return Ok(answer), + Err(err) => info!("Fetching answer file via HTTP failed: {err}"), + } + }, + AutoInstModes::Included => { + let answer_path = PathBuf::from("/cdrom/answer.toml"); + match fetch_plugins::utils::get_answer_file(&answer_path) { + Ok(answer) => return Ok(answer), + Err(err) => info!("Fetching answer file from ISO failed: {err}"), + } + }, + AutoInstModes::Partition => { + match FetchFromPartition::get_answer() { + Ok(answer) => return Ok(answer), + Err(err) => info!("Fetching answer file from partition failed: {err}"), + } + }, + AutoInstModes::Http => { + match FetchFromHTTP::get_answer(install_settings) { + Ok(answer) => return Ok(answer), + Err(err) => info!("Fetching answer file via HTTP failed: {err}"), + } + }, + } Err(Error::msg("Could not find any answer file!")) } @@ -34,8 +60,22 @@ fn main() -> ExitCode { panic!("could not initialize logging: {err}"); } - info!("Fetching answer file"); - let answer = match fetch_answer() { + let raw_install_settings = match fs::read_to_string(AUTOINST_MODE_FILE) { + Ok(f) => f, + Err(err) => { + error!("Could not find needed file '{AUTOINST_MODE_FILE}' in live environment: {err}"); + return ExitCode::FAILURE; + }, + }; + let install_settings: AutoInstSettings = match toml::from_str(raw_install_settings.as_str()) { + Ok(content) => content, + Err(err) => { + error!("Failed to parse '{AUTOINST_MODE_FILE}': {err}"); + return ExitCode::FAILURE; + }, + }; + + let answer = match fetch_answer(&install_settings) { Ok(answer) => answer, Err(err) => { error!("Aborting: {}", err); -- 2.39.2