diff --git a/Cargo.lock b/Cargo.lock index a45854e..e98415e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -128,7 +128,6 @@ dependencies = [ "log", "mimalloc", "notify", - "openssl", "pingora", "pingora-core", "pingora-http", @@ -601,9 +600,9 @@ dependencies = [ [[package]] name = "crypto-common" -version = "0.2.0-rc.2" +version = "0.2.0-rc.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "170d71b5b14dec99db7739f6fc7d6ec2db80b78c3acb77db48392ccc3d8a9ea0" +checksum = "8a23fa214dea9efd4dacee5a5614646b30216ae0f05d4bb51bafb50e9da1c5be" dependencies = [ "hybrid-array", ] @@ -684,12 +683,12 @@ dependencies = [ [[package]] name = "digest" -version = "0.11.0-pre.10" +version = "0.11.0-rc.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c478574b20020306f98d61c8ca3322d762e1ff08117422ac6106438605ea516" +checksum = "460dd7f37e4950526b54a5a6b1f41b6c8e763c58eb9a8fc8fc05ba5c2f44ca7b" dependencies = [ "block-buffer 0.11.0-rc.4", - "crypto-common 0.2.0-rc.2", + "crypto-common 0.2.0-rc.3", ] [[package]] @@ -1169,21 +1168,28 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.10" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" +checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb" dependencies = [ + "base64", "bytes", "futures-channel", + "futures-core", "futures-util", "http", "http-body", "hyper", + "ipnet", + "libc", + "percent-encoding", "pin-project-lite", "socket2", + "system-configuration", "tokio", "tower-service", "tracing", + "windows-registry", ] [[package]] @@ -1371,6 +1377,16 @@ version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" +[[package]] +name = "iri-string" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "is_terminal_polyfill" version = "1.70.1" @@ -1469,15 +1485,15 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.169" +version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" [[package]] name = "libmimalloc-sys" -version = "0.1.42" +version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec9d6fac27761dabcd4ee73571cdb06b7022dc99089acbe5435691edffaac0f4" +checksum = "bf88cd67e9de251c1781dbe2f641a1a3ad66eaae831b8a2c38fbdc5ddae16d4d" dependencies = [ "cc", "libc", @@ -1588,9 +1604,9 @@ dependencies = [ [[package]] name = "mimalloc" -version = "0.1.46" +version = "0.1.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "995942f432bbb4822a7e9c3faa87a695185b0d09273ba85f097b54f4e458f2af" +checksum = "b1791cbe101e95af5764f06f20f6760521f7158f69dbf9d6baf941ee1bf6bc40" dependencies = [ "libmimalloc-sys", ] @@ -2403,15 +2419,14 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "reqwest" -version = "0.12.15" +version = "0.12.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb" +checksum = "eabf4c97d9130e2bf606614eb937e86edac8292eaa6f422f995d7e8de1eb1813" dependencies = [ "base64", "bytes", "encoding_rs", "futures-core", - "futures-util", "h2", "http", "http-body", @@ -2420,29 +2435,26 @@ dependencies = [ "hyper-rustls", "hyper-tls", "hyper-util", - "ipnet", "js-sys", "log", "mime", "native-tls", - "once_cell", "percent-encoding", "pin-project-lite", - "rustls-pemfile", + "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", "sync_wrapper", - "system-configuration", "tokio", "tokio-native-tls", "tower", + "tower-http", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "windows-registry", ] [[package]] @@ -2709,13 +2721,13 @@ dependencies = [ [[package]] name = "sha2" -version = "0.11.0-pre.5" +version = "0.11.0-rc.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b4241d1a56954dce82cecda5c8e9c794eef6f53abe5e5216bac0a0ea71ffa7" +checksum = "aa1d2e6b3cc4e43a8258a9a3b17aa5dfd2cc5186c7024bba8a64aa65b2c71a59" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.11.0-pre.10", + "digest 0.11.0-rc.0", ] [[package]] @@ -2762,9 +2774,9 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" -version = "0.5.8" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" dependencies = [ "libc", "windows-sys 0.52.0", @@ -3004,9 +3016,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.45.0" +version = "1.45.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165" +checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" dependencies = [ "backtrace", "bytes", @@ -3101,9 +3113,9 @@ dependencies = [ [[package]] name = "tonic" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85839f0b32fd242bb3209262371d07feda6d780d16ee9d2bc88581b89da1549b" +checksum = "7e581ba15a835f4d9ea06c55ab1bd4dce26fc53752c69a04aac00703bfb49ba9" dependencies = [ "async-trait", "axum", @@ -3147,6 +3159,24 @@ dependencies = [ "tracing", ] +[[package]] +name = "tower-http" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" +dependencies = [ + "bitflags 2.8.0", + "bytes", + "futures-util", + "http", + "http-body", + "iri-string", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", +] + [[package]] name = "tower-layer" version = "0.3.3" @@ -3447,29 +3477,29 @@ checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" [[package]] name = "windows-registry" -version = "0.4.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" +checksum = "b3bab093bdd303a1240bb99b8aba8ea8a69ee19d34c9e2ef9594e708a4878820" dependencies = [ + "windows-link", "windows-result", "windows-strings", - "windows-targets 0.53.0", ] [[package]] name = "windows-result" -version = "0.3.2" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" dependencies = [ "windows-link", ] [[package]] name = "windows-strings" -version = "0.3.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" dependencies = [ "windows-link", ] @@ -3525,29 +3555,13 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", + "windows_i686_gnullvm", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] -[[package]] -name = "windows-targets" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" -dependencies = [ - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", -] - [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -3560,12 +3574,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" - [[package]] name = "windows_aarch64_msvc" version = "0.48.5" @@ -3578,12 +3586,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" - [[package]] name = "windows_i686_gnu" version = "0.48.5" @@ -3596,24 +3598,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" -[[package]] -name = "windows_i686_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" - [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" - [[package]] name = "windows_i686_msvc" version = "0.48.5" @@ -3626,12 +3616,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_i686_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" - [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -3644,12 +3628,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" - [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" @@ -3662,12 +3640,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" - [[package]] name = "windows_x86_64_msvc" version = "0.48.5" @@ -3680,12 +3652,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" - [[package]] name = "wit-bindgen-rt" version = "0.33.0" diff --git a/Cargo.toml b/Cargo.toml index 45f2dbf..b690390 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ panic = "abort" strip = true [dependencies] -tokio = { version = "1.45.0", features = ["full"] } +tokio = { version = "1.45.1", features = ["full"] } #pingora = { version = "0.5.0", features = ["lb", "rustls"] } # openssl, rustls, boringssl pingora = { version = "0.5.0", features = ["lb", "openssl"] } # openssl, rustls, boringssl serde = { version = "1.0.219", features = ["derive"] } @@ -26,7 +26,7 @@ futures = "0.3.31" notify = "8.0.0" axum = { version = "0.8.4" } axum-server = { version = "0.7.2", features = ["tls-openssl"] } -reqwest = { version = "0.12.15", features = ["json", "native-tls-alpn"] } +reqwest = { version = "0.12.20", features = ["json", "native-tls-alpn"] } #reqwest = { version = "0.12.15", features = ["json", "rustls-tls"] } #reqwest = { version = "0.12.15", default-features = false, features = ["rustls-tls", "json"] } @@ -34,18 +34,16 @@ serde_yaml = "0.9.34-deprecated" rand = "0.9.0" base64 = "0.22.1" jsonwebtoken = "9.3.1" -tonic = "0.13.0" -sha2 = { version = "0.11.0-pre.5", default-features = false } +tonic = "0.13.1" +sha2 = { version = "0.11.0-rc.0", default-features = false } base16ct = { version = "0.2.0", features = ["alloc"] } urlencoding = "2.1.3" arc-swap = "1.7.1" #rustls = { version = "0.23.27", features = ["ring"] } -mimalloc = { version = "0.1.46", default-features = false } +mimalloc = { version = "0.1.47", default-features = false } prometheus = "0.14.0" lazy_static = "1.5.0" -openssl = "0.10.72" +#openssl = "0.10.73" x509-parser = "0.17.0" rustls-pemfile = "2.2.0" -#openssl = "0.10.72" - diff --git a/README.md b/README.md index f7bdf43..1ea19bc 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ # Aralez (Արալեզ), Reverse proxy and service mesh built on top of Cloudflare's Pingora -**What Aralez means?** -Aralez = Արալեզ. Named after the legendary Armenian guardian spirit, winged dog-like creature, that descend upon fallen heroes to lick their wounds and resurrect them.. +What Aralez means ? +**Aralez = Արալեզ** .Named after the legendary Armenian guardian spirit, winged dog-like creature, that descend upon fallen heroes to lick their wounds and resurrect them.. Built on Rust, on top of **Cloudflare’s Pingora engine**, **Aralez** delivers world-class performance, security and scalability — right out of the box. diff --git a/src/utils/structs.rs b/src/utils/structs.rs index 82f5408..441e4a0 100644 --- a/src/utils/structs.rs +++ b/src/utils/structs.rs @@ -78,3 +78,9 @@ pub struct AppConfig { pub local_server: Option<(String, u16)>, pub proxy_certificates: Option, } + +// #[derive(Debug)] +// pub struct CertificateMove { +// pub cert_tx: Sender, +// pub cert_rx: Receiver, +// } diff --git a/src/utils/tls.rs b/src/utils/tls.rs index 5a43193..088de6e 100644 --- a/src/utils/tls.rs +++ b/src/utils/tls.rs @@ -1,9 +1,12 @@ -use openssl::ssl::{select_next_proto, AlpnError, NameType, SniError, SslAlert, SslContext, SslFiletype, SslMethod, SslRef}; +use dashmap::DashMap; +use log::error; +use pingora::tls::ssl::{select_next_proto, AlpnError, NameType, SniError, SslAlert, SslContext, SslFiletype, SslMethod, SslRef}; use rustls_pemfile::{read_one, Item}; use serde::Deserialize; use std::collections::HashSet; use std::fs::File; use std::io::BufReader; +// use tokio::time::Instant; use x509_parser::extensions::GeneralName; use x509_parser::nom::Err as NomErr; use x509_parser::prelude::*; @@ -28,43 +31,56 @@ struct CertificateInfo { #[derive(Debug)] pub struct Certificates { configs: Vec, + name_map: DashMap, pub default_cert_path: String, pub default_key_path: String, } impl Certificates { - pub fn new(configs: &Vec) -> Self { - let default_cert = configs.first().expect("atleast one TLS certificate required"); + pub fn new(configs: &Vec) -> Option { + let default_cert = configs.first().expect("At least one TLS certificate required"); let mut cert_infos = Vec::new(); + let name_map: DashMap = DashMap::new(); for config in configs { - cert_infos.push( - load_cert_info(&config.cert_path, &config.key_path) - .unwrap_or_else(|| panic!("unable to load certificate info | public: {}, private: {}", &config.cert_path, &config.key_path)), - ); + let cert_info = load_cert_info(&config.cert_path, &config.key_path); + match cert_info { + Some(cert) => { + for name in &cert.common_names { + name_map.insert(name.clone(), cert.ssl_context.clone()); + } + for name in &cert.alt_names { + name_map.insert(name.clone(), cert.ssl_context.clone()); + } + + cert_infos.push(cert) + } + None => { + error!("Unable to load certificate info | public: {}, private: {}", &config.cert_path, &config.key_path); + return None; + } + } } - Self { + Some(Self { + name_map: name_map, configs: cert_infos, default_cert_path: default_cert.cert_path.clone(), default_key_path: default_cert.key_path.clone(), - } + }) } - fn find_ssl_context(&self, server_name: &str) -> Option<&SslContext> { + fn find_ssl_context(&self, server_name: &str) -> Option { + if let Some(ctx) = self.name_map.get(server_name) { + return Some(ctx.clone()); + } for config in &self.configs { - // Exact name match - if config.common_names.contains(&server_name.to_string()) || config.alt_names.contains(&server_name.to_string()) { - return Some(&config.ssl_context); - } - - // Wildcard match for name in &config.common_names { if name.starts_with("*.") && server_name.ends_with(&name[1..]) { - return Some(&config.ssl_context); + return Some(config.ssl_context.clone()); } } for name in &config.alt_names { if name.starts_with("*.") && server_name.ends_with(&name[1..]) { - return Some(&config.ssl_context); + return Some(config.ssl_context.clone()); } } } @@ -74,16 +90,18 @@ impl Certificates { pub fn server_name_callback(&self, ssl_ref: &mut SslRef, ssl_alert: &mut SslAlert) -> Result<(), SniError> { let server_name = ssl_ref.servername(NameType::HOST_NAME); log::debug!("TLS connect: server_name = {:?}, ssl_ref = {:?}, ssl_alert = {:?}", server_name, ssl_ref, ssl_alert); + // let start_time = Instant::now(); if let Some(name) = server_name { match self.find_ssl_context(name) { Some(ctx) => { - ssl_ref.set_ssl_context(ctx).map_err(|_| SniError::ALERT_FATAL)?; + ssl_ref.set_ssl_context(&*ctx).map_err(|_| SniError::ALERT_FATAL)?; } None => { log::debug!("No matching server name found"); } } } + // println!("Context ==> {:?} <==", start_time.elapsed()); Ok(()) } } @@ -160,7 +178,6 @@ fn load_cert_info(cert_path: &str, key_path: &str) -> Option { fn create_ssl_context(cert_path: &str, key_path: &str) -> Result> { let mut ctx = SslContext::builder(SslMethod::tls())?; - ctx.set_certificate_chain_file(cert_path)?; ctx.set_private_key_file(key_path, SslFiletype::PEM)?; ctx.set_alpn_select_callback(prefer_h2); diff --git a/src/utils/tools.rs b/src/utils/tools.rs index d7fe852..3d06fcb 100644 --- a/src/utils/tools.rs +++ b/src/utils/tools.rs @@ -1,12 +1,17 @@ use crate::utils::structs::{UpstreamsDashMap, UpstreamsIdMap}; use crate::utils::tls; +use crate::utils::tls::CertificateConfig; use dashmap::DashMap; +use log::{error, info}; +use notify::{event::ModifyKind, Config, EventKind, RecommendedWatcher, RecursiveMode, Watcher}; use sha2::{Digest, Sha256}; use std::any::type_name; use std::collections::{HashMap, HashSet}; use std::fmt::Write; use std::fs; use std::sync::atomic::AtomicUsize; +use std::sync::mpsc::{channel, Sender}; +use std::time::{Duration, Instant}; #[allow(dead_code)] pub fn print_upstreams(upstreams: &UpstreamsDashMap) { @@ -162,7 +167,7 @@ pub fn listdir(dir: String) -> Vec { inner.push(name.clone() + ".crt"); inner.push(name.clone() + ".key"); f.insert(domain[domain.len() - 1].to_owned(), inner); - let y = tls::CertificateConfig { + let y = CertificateConfig { cert_path: name.clone() + ".crt", key_path: name.clone() + ".key", }; @@ -170,7 +175,7 @@ pub fn listdir(dir: String) -> Vec { } } for (_, v) in f.iter() { - let y = tls::CertificateConfig { + let y = CertificateConfig { cert_path: v[0].clone(), key_path: v[1].clone(), }; @@ -178,3 +183,30 @@ pub fn listdir(dir: String) -> Vec { } certificate_configs } + +pub fn watch_folder(path: String, sender: Sender>) -> notify::Result<()> { + let (tx, rx) = channel(); + let mut watcher = RecommendedWatcher::new(tx, Config::default())?; + watcher.watch(path.as_ref(), RecursiveMode::Recursive)?; + info!("Watching for certificates in : {}", path); + let certificate_configs = listdir(path.clone()); + sender.send(certificate_configs)?; + let mut start = Instant::now(); + loop { + match rx.recv_timeout(Duration::from_secs(1)) { + Ok(Ok(event)) => match &event.kind { + EventKind::Modify(ModifyKind::Data(_)) | EventKind::Create(_) | EventKind::Remove(_) => { + if start.elapsed() > Duration::from_secs(1) { + start = Instant::now(); + let certificate_configs = listdir(path.clone()); + sender.send(certificate_configs)?; + info!("Certificate changed: {:?}, {:?}", event.kind, event.paths); + } + } + _ => {} + }, + Ok(Err(e)) => error!("Watch error: {:?}", e), + Err(_) => {} + } + } +} diff --git a/src/web/bgservice.rs b/src/web/bgservice.rs index 933b0d2..eb4871e 100644 --- a/src/web/bgservice.rs +++ b/src/web/bgservice.rs @@ -30,6 +30,8 @@ impl BackgroundService for LB { let _ = tokio::spawn(async move { file_load.start(tx_file).await }); let _ = tokio::spawn(async move { consul_load.start(tx_consul).await }); + // let _ = tokio::spawn(tls::watch_certs(self.config.proxy_certificates.clone().unwrap(), self.cert_tx.clone())); + // let _ = tokio::spawn(tls::watch_certs(self.config.proxy_certificates.clone().unwrap(), self.cert_tx.clone())).await; let api_load = APIUpstreamProvider { address: self.config.config_address.clone(), diff --git a/src/web/proxyhttp.rs b/src/web/proxyhttp.rs index 05c0801..4d618d7 100644 --- a/src/web/proxyhttp.rs +++ b/src/web/proxyhttp.rs @@ -15,6 +15,7 @@ use pingora_proxy::{ProxyHttp, Session}; use std::sync::Arc; use tokio::time::Instant; +#[derive(Clone)] pub struct LB { pub ump_upst: Arc, pub ump_full: Arc, diff --git a/src/web/start.rs b/src/web/start.rs index 2b62639..5a56e8d 100644 --- a/src/web/start.rs +++ b/src/web/start.rs @@ -1,17 +1,19 @@ // use rustls::crypto::ring::default_provider; use crate::utils::structs::Extraparams; use crate::utils::tls; -use crate::utils::tools::listdir; +use crate::utils::tls::CertificateConfig; +use crate::utils::tools::*; use crate::web::proxyhttp::LB; use arc_swap::ArcSwap; use dashmap::DashMap; use log::info; -use openssl::ssl::{SslAlert, SslRef}; +use pingora::tls::ssl::{SslAlert, SslRef}; use pingora_core::listeners::tls::TlsSettings; use pingora_core::prelude::{background_service, Opt}; use pingora_core::server::Server; -use std::env; +use std::sync::mpsc::{channel, Receiver, Sender}; use std::sync::Arc; +use std::{env, thread}; pub fn run() { // default_provider().install_default().expect("Failed to install rustls crypto provider"); @@ -42,14 +44,15 @@ pub fn run() { headers: hh_config.clone(), extraparams: ec_config.clone(), }; - let bg = LB { - ump_upst: uf_config.clone(), - ump_full: ff_config.clone(), - ump_byid: im_config.clone(), - config: cfg.clone(), - headers: hh_config.clone(), - extraparams: ec_config.clone(), - }; + // let bg = LB { + // ump_upst: uf_config.clone(), + // ump_full: ff_config.clone(), + // ump_byid: im_config.clone(), + // config: cfg.clone(), + // headers: hh_config.clone(), + // extraparams: ec_config.clone(), + // config_rx: Arc::from(Mutex::new(rx)), + // }; // env_logger::Env::new(); // env_logger::init(); @@ -69,35 +72,49 @@ pub fn run() { } } } - env_logger::builder() - // .format_timestamp(None) - // .format_module_path(false) - // .format_source_path(false) - // .format_target(false) - .init(); + env_logger::builder().init(); - let bg_srvc = background_service("bgsrvc", bg); - let mut proxy = pingora_proxy::http_proxy_service(&server.configuration, lb); + let bg_srvc = background_service("bgsrvc", lb.clone()); + let mut proxy = pingora_proxy::http_proxy_service(&server.configuration, lb.clone()); let bind_address_http = cfg.proxy_address_http.clone(); let bind_address_tls = cfg.proxy_address_tls.clone(); - // let foo = crate::utils::tls::build_ssl_context_builder(); match bind_address_tls { Some(bind_address_tls) => { - info!("Running TLS listener on :{}", bind_address_tls); - // let cert_path = cfg.tls_certificate.clone().unwrap(); - // let key_path = cfg.tls_key_file.clone().unwrap(); - // let mut tls_settings = tls::TlsSettings::intermediate(&cert_path, &key_path).unwrap(); - // tls_settings.enable_h2(); - // proxy.add_tls_with_settings(&bind_address_tls, None, tls_settings); + let (tx, rx): (Sender>, Receiver>) = channel(); + let certs_path = cfg.proxy_certificates.clone().unwrap(); + thread::spawn(move || { + watch_folder(certs_path, tx).unwrap(); + }); + let certificate_configs = rx.recv().unwrap(); + let first_set = tls::Certificates::new(&certificate_configs).unwrap_or_else(|| panic!("Unable to load initial certificate info")); + let certificates = Arc::new(ArcSwap::from_pointee(first_set)); + let certs_for_callback = certificates.clone(); - let certificate_configs = listdir(cfg.proxy_certificates.clone().unwrap()); - let certificates = tls::Certificates::new(&certificate_configs); - let mut tls_settings = TlsSettings::intermediate(&certificates.default_cert_path, &certificates.default_key_path).expect("unable to load or parse cert/key"); - tls_settings.enable_h2(); - tls_settings.set_servername_callback(move |ssl_ref: &mut SslRef, ssl_alert: &mut SslAlert| certificates.server_name_callback(ssl_ref, ssl_alert)); + let certs_for_watcher = certificates.clone(); + let new_certs = tls::Certificates::new(&certificate_configs); + certs_for_watcher.store(Arc::new(new_certs.unwrap())); + + let mut tls_settings = + TlsSettings::intermediate(&certs_for_callback.load().default_cert_path, &certs_for_callback.load().default_key_path).expect("unable to load or parse cert/key"); + + tls_settings.set_servername_callback(move |ssl_ref: &mut SslRef, ssl_alert: &mut SslAlert| certs_for_callback.load().server_name_callback(ssl_ref, ssl_alert)); tls_settings.set_alpn_select_callback(tls::prefer_h2); proxy.add_tls_with_settings(&bind_address_tls, None, tls_settings); + + let certs_for_watcher = certificates.clone(); + thread::spawn(move || { + while let Ok(new_configs) = rx.recv() { + let new_certs = tls::Certificates::new(&new_configs); + match new_certs { + Some(new_certs) => { + certs_for_watcher.store(Arc::new(new_certs)); + info!("Reload TLS certificates from {}", cfg.proxy_certificates.clone().unwrap()) + } + None => {} + }; + } + }); } None => {} }