From b15df3c93f6b92bdb35b8ca3cfded1cc4bfbd63a Mon Sep 17 00:00:00 2001 From: Jean-Gabriel Gill-Couture Date: Tue, 17 Dec 2024 15:15:41 -0500 Subject: [PATCH] feat: OKD Dhcp config works and is actually savec on opnsense firewall, its alive!! First real run on wk cluster --- harmony-rs/harmony/src/domain/hardware/mod.rs | 8 +-- .../harmony/src/domain/topology/network.rs | 1 + harmony-rs/harmony/src/infra/opnsense/mod.rs | 17 ++++- harmony-rs/harmony/src/modules/dhcp.rs | 17 +++-- harmony-rs/harmony/src/modules/mod.rs | 1 + harmony-rs/harmony/src/modules/okd/dhcp.rs | 45 +++++++++++++ harmony-rs/harmony/src/modules/okd/mod.rs | 2 + .../opnsense-config-xml/src/data/opnsense.rs | 65 ++++++++++++------- .../opnsense-config/src/config/manager/ssh.rs | 5 +- .../opnsense-config/src/modules/dhcp.rs | 12 ++-- 10 files changed, 132 insertions(+), 41 deletions(-) create mode 100644 harmony-rs/harmony/src/modules/okd/dhcp.rs create mode 100644 harmony-rs/harmony/src/modules/okd/mod.rs diff --git a/harmony-rs/harmony/src/domain/hardware/mod.rs b/harmony-rs/harmony/src/domain/hardware/mod.rs index 8ec4f81..2b2c02a 100644 --- a/harmony-rs/harmony/src/domain/hardware/mod.rs +++ b/harmony-rs/harmony/src/domain/hardware/mod.rs @@ -96,10 +96,10 @@ pub enum StorageKind { } #[derive(Debug, new, Clone)] pub struct Storage { - connection: StorageConnectionType, - kind: StorageKind, - size: u64, - serial: String, + pub connection: StorageConnectionType, + pub kind: StorageKind, + pub size: u64, + pub serial: String, } #[derive(Debug, Clone)] diff --git a/harmony-rs/harmony/src/domain/topology/network.rs b/harmony-rs/harmony/src/domain/topology/network.rs index be55f37..536370c 100644 --- a/harmony-rs/harmony/src/domain/topology/network.rs +++ b/harmony-rs/harmony/src/domain/topology/network.rs @@ -47,6 +47,7 @@ pub trait DhcpServer: Send + Sync { async fn list_static_mappings(&self) -> Vec<(MacAddress, IpAddress)>; fn get_ip(&self) -> IpAddress; fn get_host(&self) -> LogicalHost; + async fn commit_config(&self) -> Result<(), ExecutorError>; } impl std::fmt::Debug for dyn DhcpServer { diff --git a/harmony-rs/harmony/src/infra/opnsense/mod.rs b/harmony-rs/harmony/src/infra/opnsense/mod.rs index deca92a..8bc27d6 100644 --- a/harmony-rs/harmony/src/infra/opnsense/mod.rs +++ b/harmony-rs/harmony/src/infra/opnsense/mod.rs @@ -1,9 +1,10 @@ mod management; -use std::sync::{Arc, RwLock }; +use std::sync::Arc; use async_trait::async_trait; use log::debug; pub use management::*; +use tokio::sync::RwLock; use crate::{ executors::ExecutorError, @@ -97,14 +98,24 @@ impl LoadBalancer for OPNSenseFirewall { #[async_trait] impl DhcpServer for OPNSenseFirewall { + async fn commit_config(&self) -> Result<(), ExecutorError> { + self.opnsense_config + .read() + .await + .apply() + .await + .map_err(|e| ExecutorError::UnexpectedError(e.to_string())) + } + async fn add_static_mapping(&self, entry: &DHCPStaticEntry) -> Result<(), ExecutorError> { let mac: String = String::from(&entry.mac); { - let mut writable_opnsense = self.opnsense_config.write().unwrap(); + let mut writable_opnsense = self.opnsense_config.write().await; writable_opnsense .dhcp() - .add_static_mapping(&mac, entry.ip, &entry.name).unwrap(); + .add_static_mapping(&mac, entry.ip, &entry.name) + .unwrap(); } debug!("Registered {:?}", entry); diff --git a/harmony-rs/harmony/src/modules/dhcp.rs b/harmony-rs/harmony/src/modules/dhcp.rs index fb3470e..73e6d65 100644 --- a/harmony-rs/harmony/src/modules/dhcp.rs +++ b/harmony-rs/harmony/src/modules/dhcp.rs @@ -87,7 +87,9 @@ impl Interpret for DhcpInterpret { .map(|binding| { let ip = match binding.logical_host.ip { std::net::IpAddr::V4(ipv4) => ipv4, - std::net::IpAddr::V6(_) => unimplemented!("DHCPStaticEntry only supports ipv4 at the moment"), + std::net::IpAddr::V6(_) => { + unimplemented!("DHCPStaticEntry only supports ipv4 at the moment") + } }; DHCPStaticEntry { @@ -99,20 +101,23 @@ impl Interpret for DhcpInterpret { .collect(); info!("DHCPStaticEntry : {:?}", dhcp_entries); - let dhcp = Arc::new(Box::new(topology.dhcp_server.clone())); - info!("DHCP server : {:?}", dhcp); + let dhcp_server = Arc::new(Box::new(topology.dhcp_server.clone())); + info!("DHCP server : {:?}", dhcp_server); + + let number_new_entries = dhcp_entries.len(); + for entry in dhcp_entries.into_iter() { - match dhcp.add_static_mapping(&entry).await { + match dhcp_server.add_static_mapping(&entry).await { Ok(_) => info!("Successfully registered DHCPStaticEntry {}", entry), Err(_) => todo!(), } } - todo!("Configure DHCPServer"); + dhcp_server.commit_config().await; Ok(Outcome::new( InterpretStatus::SUCCESS, - "Connection test successful".to_string(), + format!("Dhcp Interpret registered {} entries", number_new_entries), )) } } diff --git a/harmony-rs/harmony/src/modules/mod.rs b/harmony-rs/harmony/src/modules/mod.rs index 5833493..84aeb83 100644 --- a/harmony-rs/harmony/src/modules/mod.rs +++ b/harmony-rs/harmony/src/modules/mod.rs @@ -1 +1,2 @@ pub mod dhcp; +pub mod okd; diff --git a/harmony-rs/harmony/src/modules/okd/dhcp.rs b/harmony-rs/harmony/src/modules/okd/dhcp.rs new file mode 100644 index 0000000..3603696 --- /dev/null +++ b/harmony-rs/harmony/src/modules/okd/dhcp.rs @@ -0,0 +1,45 @@ +use crate::{ + inventory::Inventory, + modules::dhcp::DhcpScore, + score::Score, + topology::{HAClusterTopology, HostBinding}, +}; + +#[derive(Debug)] +pub struct OKDBootstrapDhcpScore { + dhcp_score: DhcpScore, +} + +impl OKDBootstrapDhcpScore { + pub fn new(topology: &HAClusterTopology, inventory: &Inventory) -> Self { + Self { + dhcp_score: DhcpScore::new( + topology + .control_plane + .iter() + .enumerate() + .map(|(index, topology_entry)| { + HostBinding { + logical_host: topology_entry.clone(), + physical_host: inventory + .control_plane_host + .get(index) + .expect( + "Iventory should contain at least as many physical hosts as topology", + ) + .clone(), + } + }) + .collect(), + ), + } + } +} + +impl Score for OKDBootstrapDhcpScore { + type InterpretType = ::InterpretType; + + fn create_interpret(self) -> Self::InterpretType { + self.dhcp_score.create_interpret() + } +} diff --git a/harmony-rs/harmony/src/modules/okd/mod.rs b/harmony-rs/harmony/src/modules/okd/mod.rs new file mode 100644 index 0000000..8c32480 --- /dev/null +++ b/harmony-rs/harmony/src/modules/okd/mod.rs @@ -0,0 +1,2 @@ +pub mod dhcp; + diff --git a/harmony-rs/opnsense-config-xml/src/data/opnsense.rs b/harmony-rs/opnsense-config-xml/src/data/opnsense.rs index 48ff582..04c4977 100644 --- a/harmony-rs/opnsense-config-xml/src/data/opnsense.rs +++ b/harmony-rs/opnsense-config-xml/src/data/opnsense.rs @@ -27,7 +27,7 @@ pub struct OPNsense { pub opnsense: OPNsenseXmlSection, pub staticroutes: StaticRoutes, pub ca: MaybeString, - pub gateways: Option, + pub gateways: Option, pub cert: Vec, pub dhcpdv6: DhcpDv6, pub virtualip: VirtualIp, @@ -60,7 +60,6 @@ impl OPNsense { } } - #[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)] pub struct LoadBalancer { pub monitor_type: Vec, @@ -415,6 +414,8 @@ pub struct OPNsenseXmlSection { pub ipsec: Option, #[yaserde(rename = "Interfaces")] pub interfaces: Option, + #[yaserde(rename = "NodeExporter")] + pub node_exporter: Option, #[yaserde(rename = "Kea")] pub kea: Option, pub monit: Option, @@ -428,6 +429,7 @@ pub struct OPNsenseXmlSection { pub unboundplus: Option, #[yaserde(rename = "DHCRelay")] pub dhcrelay: Option, + pub trust: Option, pub wireguard: Option, #[yaserde(rename = "Swanctl")] pub swanctl: Swanctl, @@ -479,6 +481,8 @@ pub struct IDSGeneral { #[yaserde(rename = "LogPayload")] log_payload: Option, verbosity: MaybeString, + #[yaserde(rename = "eveLog")] + eve_log: Option, } #[derive(Debug, YaSerialize, YaDeserialize, PartialEq)] @@ -498,11 +502,15 @@ pub struct IPsec { key_pairs: MaybeString, #[yaserde(rename = "preSharedKeys")] pre_shared_keys: MaybeString, + charon: Option, } #[derive(Debug, YaSerialize, YaDeserialize, PartialEq)] pub struct GeneralIpsec { enabled: MaybeString, + preferred_oldsa: MaybeString, + disablevpnrules: MaybeString, + passthrough_networks: MaybeString, } #[derive(Debug, YaSerialize, YaDeserialize, PartialEq)] @@ -1214,6 +1222,8 @@ pub struct WireguardServerItem { pub gateway: MaybeString, pub carp_depend_on: MaybeString, pub peers: String, + pub endpoint: MaybeString, + pub peer_dns: MaybeString, } #[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)] @@ -1320,7 +1330,6 @@ pub struct ConfigOpenVPN { pub StaticKeys: MaybeString, } - #[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)] #[yaserde(rename = "HAProxy")] pub struct HAProxy { @@ -1411,6 +1420,8 @@ pub struct Tuning { #[yaserde(rename = "maxConnections")] pub max_connections: MaybeString, pub nbthread: i32, + #[yaserde(rename = "resolversPrefer")] + pub resolvers_prefer: String, #[yaserde(rename = "sslServerVerify")] pub ssl_server_verify: String, #[yaserde(rename = "maxDHSize")] @@ -1425,6 +1436,12 @@ pub struct Tuning { pub lua_max_mem: i32, #[yaserde(rename = "customOptions")] pub custom_options: MaybeString, + #[yaserde(rename = "ocspUpdateEnabled")] + pub ocs_update_enabled: MaybeString, + #[yaserde(rename = "ocspUpdateMinDelay")] + pub ocs_update_min_delay: MaybeString, + #[yaserde(rename = "ocspUpdateMaxDelay")] + pub ocs_update_max_delay: MaybeString, #[yaserde(rename = "ssl_defaultsEnabled")] pub ssl_defaults_enabled: i32, #[yaserde(rename = "ssl_bindOptions")] @@ -1437,6 +1454,19 @@ pub struct Tuning { pub ssl_cipher_list: String, #[yaserde(rename = "ssl_cipherSuites")] pub ssl_cipher_suites: String, + #[yaserde(rename = "h2_initialWindowSize")] + pub h2_initial_window_size: Option, + #[yaserde(rename = "h2_initialWindowSizeOutgoing")] + pub h2_initial_window_size_outgoing: Option, + #[yaserde(rename = "h2_initialWindowSizeIncoming")] + pub h2_initial_window_size_incoming: Option, + #[yaserde(rename = "h2_maxConcurrentStreams")] + pub h2_max_concurrent_streams: Option, + #[yaserde(rename = "h2_maxConcurrentStreamsOutgoing")] + pub h2_max_concurrent_streams_outgoing: Option, + #[yaserde(rename = "h2_maxConcurrentStreamsIncoming")] + pub h2_max_concurrent_streams_incoming: Option, + } #[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)] @@ -1684,25 +1714,22 @@ pub struct Backend { pub http2_enabled_nontls: u8, #[yaserde(rename = "ba_advertised_protocols")] pub ba_advertised_protocols: String, - #[yaserde(rename = "persistence")] - pub persistence: String, - #[yaserde(rename = "persistence_cookiemode")] + #[yaserde(rename = "forwardFor")] + pub forward_for: Option, + #[yaserde(rename = "forwardedHeader")] + pub forwarded_header: Option, + #[yaserde(rename = "forwardedHeaderParameters")] + pub forwarded_header_parameters: Option, + pub persistence: MaybeString, pub persistence_cookiemode: String, - #[yaserde(rename = "persistence_cookiename")] pub persistence_cookiename: MaybeString, - #[yaserde(rename = "persistence_stripquotes")] pub persistence_stripquotes: u8, - #[yaserde(rename = "stickiness_pattern")] - pub stickiness_pattern: String, + pub stickiness_pattern: MaybeString, #[yaserde(rename = "stickiness_dataTypes")] pub stickiness_data_types: MaybeString, - #[yaserde(rename = "stickiness_expire")] pub stickiness_expire: String, - #[yaserde(rename = "stickiness_size")] pub stickiness_size: String, - #[yaserde(rename = "stickiness_cookiename")] pub stickiness_cookiename: MaybeString, - #[yaserde(rename = "stickiness_cookielength")] pub stickiness_cookielength: MaybeString, #[yaserde(rename = "stickiness_connRatePeriod")] pub stickiness_conn_rate_period: String, @@ -1863,12 +1890,6 @@ pub struct StaticRoutes { #[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)] pub struct Ca {} -#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)] -pub struct Gateways { - #[yaserde(rename = "gateway_item")] - pub gateway_item: RawXml -} - #[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)] pub struct Cert { #[yaserde(attribute)] @@ -1975,14 +1996,14 @@ pub struct Bridges { pub struct Gifs { #[yaserde(attribute)] pub version: Option, - pub gif: MaybeString, + pub gif: Option, } #[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)] pub struct Gres { #[yaserde(attribute)] pub version: Option, - pub gre: MaybeString, + pub gre: Option, } #[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)] diff --git a/harmony-rs/opnsense-config/src/config/manager/ssh.rs b/harmony-rs/opnsense-config/src/config/manager/ssh.rs index a32298b..fdd8d03 100644 --- a/harmony-rs/opnsense-config/src/config/manager/ssh.rs +++ b/harmony-rs/opnsense-config/src/config/manager/ssh.rs @@ -24,9 +24,10 @@ impl SshConfigManager { impl SshConfigManager { async fn backup_config_remote(&self) -> Result { - let backup_filename = format!("config_{}.xml", chrono::Local::now().format("%Y%m%d%H%M%S")); + let ts = chrono::Utc::now(); + let backup_filename = format!("config-{}-harmony.xml", ts.format("%s%.3f")); - self.opnsense_shell.exec(&format!("cp /conf/config.xml /tmp/{}", backup_filename)) + self.opnsense_shell.exec(&format!("cp /conf/config.xml /conf/backup/{}", backup_filename)) .await } diff --git a/harmony-rs/opnsense-config/src/modules/dhcp.rs b/harmony-rs/opnsense-config/src/modules/dhcp.rs index a337cac..537c3c4 100644 --- a/harmony-rs/opnsense-config/src/modules/dhcp.rs +++ b/harmony-rs/opnsense-config/src/modules/dhcp.rs @@ -84,9 +84,13 @@ impl<'a> DhcpConfig<'a> { return Err(DhcpError::InvalidMacAddress(mac)); } - if !Self::is_ip_in_range(&ipaddr, range) { - return Err(DhcpError::IpAddressOutOfRange(ipaddr.to_string())); - } + // TODO verify if address is in subnet range + // This check here does not do what we want to do, as we want to assign static leases + // outside of the dynamic DHCP pool + // + // if !Self::is_ip_in_range(&ipaddr, range) { + // return Err(DhcpError::IpAddressOutOfRange(ipaddr.to_string())); + // } if existing_mappings.iter().any(|m| { m.ipaddr @@ -123,7 +127,7 @@ impl<'a> DhcpConfig<'a> { parts .iter() - .all(|part| part.len() == 2 && part.chars().all(|c| c.is_ascii_hexdigit())) + .all(|part| part.len() <= 2 && part.chars().all(|c| c.is_ascii_hexdigit())) } fn is_ip_in_range(ip: &Ipv4Addr, range: &Range) -> bool {