wip: implemented reloader service with trait object for future support of acme
This commit is contained in:
parent
377096c14e
commit
e18fafe4e6
5 changed files with 100 additions and 6 deletions
|
|
@ -18,7 +18,7 @@ tracing = { version = "0.1.40" }
|
||||||
# anyhow = "1.0.86"
|
# anyhow = "1.0.86"
|
||||||
derive_builder = { version = "0.20.0" }
|
derive_builder = { version = "0.20.0" }
|
||||||
thiserror = { version = "1.0.61" }
|
thiserror = { version = "1.0.61" }
|
||||||
# hot_reload = {version = "0.1.5"}
|
hot_reload = { version = "0.1.5" }
|
||||||
async-trait = { version = "0.1.80" }
|
async-trait = { version = "0.1.80" }
|
||||||
# tokio-rustls = { version = "0.26.0", features = ["early-data"] }
|
# tokio-rustls = { version = "0.26.0", features = ["early-data"] }
|
||||||
rustls = { version = "0.23.8", default-features = false, features = [
|
rustls = { version = "0.23.8", default-features = false, features = [
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
mod certs;
|
mod certs;
|
||||||
|
mod crypto_source;
|
||||||
mod error;
|
mod error;
|
||||||
mod service;
|
mod reloader_service;
|
||||||
mod source;
|
mod server_crypto;
|
||||||
|
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
mod log {
|
mod log {
|
||||||
|
|
@ -10,6 +11,6 @@ mod log {
|
||||||
|
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
certs::SingleServerCertsKeys,
|
certs::SingleServerCertsKeys,
|
||||||
service::{ServerCrypto, ServerNameBytes, ServerNameCryptoMap},
|
crypto_source::{CryptoFileSource, CryptoFileSourceBuilder, CryptoFileSourceBuilderError, CryptoSource},
|
||||||
source::{CryptoFileSource, CryptoFileSourceBuilder, CryptoFileSourceBuilderError, CryptoSource},
|
server_crypto::{ServerCrypto, ServerNameBytes, ServerNameCryptoMap},
|
||||||
};
|
};
|
||||||
|
|
|
||||||
83
rpxy-certs/src/reloader_service.rs
Normal file
83
rpxy-certs/src/reloader_service.rs
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
use crate::{
|
||||||
|
crypto_source::CryptoSource,
|
||||||
|
error::*,
|
||||||
|
log::*,
|
||||||
|
server_crypto::{ServerCryptoBase, ServerNameBytes},
|
||||||
|
};
|
||||||
|
use async_trait::async_trait;
|
||||||
|
use hot_reload::{Reload, ReloaderError};
|
||||||
|
use rustc_hash::FxHashMap as HashMap;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
/* ------------------------------------------------ */
|
||||||
|
/// Boxed CryptoSource trait object with Send and Sync
|
||||||
|
/// TODO: support for not only `CryptoFileSource` but also other type of sources
|
||||||
|
type DynCryptoSource = dyn CryptoSource<Error = RpxyCertError> + Send + Sync + 'static;
|
||||||
|
|
||||||
|
/// Reloader service for certificates and keys for TLS
|
||||||
|
pub struct CryptoReloader {
|
||||||
|
inner: HashMap<ServerNameBytes, Arc<Box<DynCryptoSource>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Extend<(ServerNameBytes, T)> for CryptoReloader
|
||||||
|
where
|
||||||
|
T: CryptoSource<Error = RpxyCertError> + Send + Sync + 'static,
|
||||||
|
{
|
||||||
|
fn extend<I: IntoIterator<Item = (ServerNameBytes, T)>>(&mut self, iter: I) {
|
||||||
|
let iter = iter
|
||||||
|
.into_iter()
|
||||||
|
.map(|(k, v)| (k, Arc::new(Box::new(v) as Box<DynCryptoSource>)));
|
||||||
|
self.inner.extend(iter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl Reload<ServerCryptoBase> for CryptoReloader {
|
||||||
|
type Source = HashMap<ServerNameBytes, Arc<Box<DynCryptoSource>>>;
|
||||||
|
|
||||||
|
async fn new(source: &Self::Source) -> Result<Self, ReloaderError<ServerCryptoBase>> {
|
||||||
|
let mut inner = HashMap::default();
|
||||||
|
inner.extend(source.clone());
|
||||||
|
Ok(Self { inner })
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn reload(&self) -> Result<Option<ServerCryptoBase>, ReloaderError<ServerCryptoBase>> {
|
||||||
|
let mut server_crypto_base = ServerCryptoBase::default();
|
||||||
|
|
||||||
|
for (server_name_bytes, crypto_source) in self.inner.iter() {
|
||||||
|
let certs_keys = crypto_source.read().await.map_err(|e| {
|
||||||
|
error!("Failed to reload cert, key or ca cert: {e}");
|
||||||
|
ReloaderError::<ServerCryptoBase>::Reload("Failed to reload cert, key or ca cert")
|
||||||
|
})?;
|
||||||
|
server_crypto_base.inner.insert(server_name_bytes.clone(), certs_keys);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Some(server_crypto_base))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* ------------------------------------------------ */
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::crypto_source::CryptoFileSourceBuilder;
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_crypto_reloader() {
|
||||||
|
let tls_cert_path = "../example-certs/server.crt";
|
||||||
|
let tls_cert_key_path = "../example-certs/server.key";
|
||||||
|
let client_ca_cert_path = Some("../example-certs/client.ca.crt");
|
||||||
|
|
||||||
|
let mut crypto_reloader = CryptoReloader::new(&HashMap::default()).await.unwrap();
|
||||||
|
let crypto_source = CryptoFileSourceBuilder::default()
|
||||||
|
.tls_cert_path(tls_cert_path)
|
||||||
|
.tls_cert_key_path(tls_cert_key_path)
|
||||||
|
.client_ca_cert_path(client_ca_cert_path)
|
||||||
|
.build()
|
||||||
|
.unwrap();
|
||||||
|
crypto_reloader.extend(vec![(b"localhost".to_vec(), crypto_source)]);
|
||||||
|
|
||||||
|
let server_crypto_base = crypto_reloader.reload().await.unwrap().unwrap();
|
||||||
|
assert_eq!(server_crypto_base.inner.len(), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
|
use crate::SingleServerCertsKeys;
|
||||||
use rustc_hash::FxHashMap as HashMap;
|
use rustc_hash::FxHashMap as HashMap;
|
||||||
use rustls::ServerConfig;
|
use rustls::ServerConfig;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// ServerName in bytes type
|
/* ------------------------------------------------ */
|
||||||
|
/// ServerName in bytes type (TODO: this may be changed to define `common` layer defining types of names. or should be independent?)
|
||||||
pub type ServerNameBytes = Vec<u8>;
|
pub type ServerNameBytes = Vec<u8>;
|
||||||
/// ServerName (SNI) to ServerConfig map type
|
/// ServerName (SNI) to ServerConfig map type
|
||||||
pub type ServerNameCryptoMap = HashMap<ServerNameBytes, Arc<ServerConfig>>;
|
pub type ServerNameCryptoMap = HashMap<ServerNameBytes, Arc<ServerConfig>>;
|
||||||
|
|
@ -13,3 +15,11 @@ pub struct ServerCrypto {
|
||||||
// // For TLS over TCP/HTTP2 and 1.1, map of SNI to server_crypto for all given servers
|
// // For TLS over TCP/HTTP2 and 1.1, map of SNI to server_crypto for all given servers
|
||||||
pub inner_local_map: Arc<ServerNameCryptoMap>,
|
pub inner_local_map: Arc<ServerNameCryptoMap>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------ */
|
||||||
|
/// Reloader target for the certificate reloader service
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone, Default)]
|
||||||
|
pub struct ServerCryptoBase {
|
||||||
|
/// Map of server name to certs and keys
|
||||||
|
pub(super) inner: HashMap<ServerNameBytes, SingleServerCertsKeys>,
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue