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 48BAE98C61 for ; Tue, 18 Apr 2023 10:59:36 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 2AA93C359 for ; Tue, 18 Apr 2023 10:59:06 +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, 18 Apr 2023 10:59:05 +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 24C7045780 for ; Tue, 18 Apr 2023 10:59:05 +0200 (CEST) From: =?UTF-8?q?Fabian=20Gr=C3=BCnbichler?= To: pve-devel@lists.proxmox.com Date: Tue, 18 Apr 2023 10:58:56 +0200 Message-Id: <20230418085857.2483865-1-f.gruenbichler@proxmox.com> X-Mailer: git-send-email 2.30.2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 0 AWL 0.076 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 SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record T_SCC_BODY_TEXT_LINE -0.01 - Subject: [pve-devel] [PATCH proxmox-offline-mirror 1/2] setup wizard: add subscription keys 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, 18 Apr 2023 08:59:36 -0000 to make it a bit easier to configure access to the enterprise repositories. Signed-off-by: Fabian Grünbichler --- docs/offline-keys.rst | 3 +- src/bin/proxmox-offline-mirror.rs | 102 ++++++++++++++++++ .../subscription.rs | 2 +- 3 files changed, 105 insertions(+), 2 deletions(-) diff --git a/docs/offline-keys.rst b/docs/offline-keys.rst index 2ce6e2c..91971e5 100644 --- a/docs/offline-keys.rst +++ b/docs/offline-keys.rst @@ -57,7 +57,8 @@ Register & Refresh Keys Offline Mirror subscription is configured. Register the hosts with their subscription keys and server IDs using -``proxmox-offline-mirror key add``, for example: +``proxmox-offline-mirror setup`` or ``proxmox-offline-mirror key add``, for +example: .. code-block:: console diff --git a/src/bin/proxmox-offline-mirror.rs b/src/bin/proxmox-offline-mirror.rs index bec366a..93e8dfa 100644 --- a/src/bin/proxmox-offline-mirror.rs +++ b/src/bin/proxmox-offline-mirror.rs @@ -2,6 +2,8 @@ use std::fmt::Display; use std::path::Path; use anyhow::{bail, Error}; +use proxmox_offline_mirror::config::SubscriptionKey; +use proxmox_offline_mirror::subscription::{extract_mirror_key, refresh_mirror_key}; use serde_json::Value; use proxmox_router::cli::{run_cli_command, CliCommand, CliCommandMap, CliEnvironment}; @@ -609,6 +611,94 @@ fn action_add_medium(config: &SectionConfigData) -> Result { }) } +fn action_add_key(config: &SectionConfigData) -> Result { + let (product, mirror_key) = if let Ok(mirror_key) = + extract_mirror_key(&config.convert_to_typed_array("subscription")?) + { + let subscription_products = &[ + (ProductType::Pve, "Proxmox VE"), + (ProductType::Pbs, "Proxmox Backup Server"), + (ProductType::Pmg, "Proxmox Mail Gateway"), + ]; + + let product = read_selection_from_tty( + "Select Proxmox product for which subscription key should be added", + subscription_products, + None, + )?; + + (product, Some(mirror_key)) + } else { + println!("No mirror key configured yet, forcing mirror key setup first.."); + (&ProductType::Pom, None) + }; + + let key = read_string_from_tty("Please enter subscription key", None)?; + if config.sections.get(&key).is_some() { + bail!("Key entry for '{key}' already exists - please use 'key refresh' or 'key update'!"); + } + + let server_id = if product == &ProductType::Pom { + let server_id = proxmox_subscription::get_hardware_address()?; + println!("Server ID of this system is '{server_id}'"); + server_id + } else { + read_string_from_tty( + "Please enter server ID of offline system using this subscription", + None, + )? + }; + + let mut data = SubscriptionKey { + key, + server_id, + description: None, + info: None, + }; + + if data.product() != *product { + bail!( + "Selected product and product in subscription key don't match: {} != {}", + product, + data.product() + ); + } + + if read_bool_from_tty("Attempt to refresh key", Some(true))? { + let info = if let Some(mirror_key) = mirror_key { + if let Err(err) = refresh_mirror_key(mirror_key.clone()) { + eprintln!("Failed to refresh mirror_key '{}' - {err}", mirror_key.key); + } + + let mut refreshed = proxmox_offline_mirror::subscription::refresh_offline_keys( + mirror_key, + vec![data.clone()], + public_key()?, + )?; + + refreshed + .pop() + .ok_or_else(|| format_err!("Server did not return subscription info.."))? + } else { + proxmox_offline_mirror::subscription::refresh_mirror_key(data.clone())? + }; + + println!( + "Refreshed subscription info - status: {}, message: {}", + info.status, + info.message.as_ref().unwrap_or(&"-".to_string()) + ); + + if info.key.as_ref() == Some(&data.key) { + data.info = Some(base64::encode(serde_json::to_vec(&info)?)); + } else { + bail!("Server returned subscription info for wrong key."); + } + } + + Ok(data) +} + #[api( input: { properties: { @@ -639,6 +729,7 @@ async fn setup(config: Option, _param: Value) -> Result<(), Error> { } enum Action { + AddKey, AddMirror, AddMedium, Quit, @@ -662,11 +753,13 @@ async fn setup(config: Option, _param: Value) -> Result<(), Error> { vec![ (Action::AddMirror, "Add new mirror entry"), (Action::AddMedium, "Add new medium entry"), + (Action::AddKey, "Add new subscription key"), (Action::Quit, "Quit"), ] } else { vec![ (Action::AddMirror, "Add new mirror entry"), + (Action::AddKey, "Add new subscription key"), (Action::Quit, "Quit"), ] }; @@ -691,11 +784,20 @@ async fn setup(config: Option, _param: Value) -> Result<(), Error> { println!("Config entry '{id}' added"); println!("Run \"proxmox-offline-mirror medium sync --config '{config_file}' '{id}'\" to sync mirror snapshots to medium."); } + Action::AddKey => { + let key = action_add_key(&config)?; + let id = key.key.clone(); + config.set_data(&id, "subscription", &key)?; + save_config(&config_file, &config)?; + println!("Config entry '{id}' added"); + println!("Run \"proxmox-offline-mirror key refresh\" to refresh subscription information"); + } } } Ok(()) } + fn main() { let rpcenv = CliEnvironment::new(); diff --git a/src/bin/proxmox_offline_mirror_cmds/subscription.rs b/src/bin/proxmox_offline_mirror_cmds/subscription.rs index 911b0af..e58b049 100644 --- a/src/bin/proxmox_offline_mirror_cmds/subscription.rs +++ b/src/bin/proxmox_offline_mirror_cmds/subscription.rs @@ -126,7 +126,7 @@ pub const SHOW_KEY_RETURN_TYPE: ReturnType = ReturnType { optional: true, }; -fn public_key() -> Result, Error> { +pub(crate) fn public_key() -> Result, Error> { openssl::pkey::PKey::public_key_from_pem(&file_get_contents(DEFAULT_SIGNING_KEY)?) .map_err(Error::from) } -- 2.30.2