feat: add initial acme support (ugly!)
This commit is contained in:
parent
d6136f9ffa
commit
7b0ca08e1e
11 changed files with 277 additions and 89 deletions
|
|
@ -29,7 +29,7 @@ sticky-cookie = ["base64", "sha2", "chrono"]
|
|||
native-tls-backend = ["hyper-tls"]
|
||||
rustls-backend = ["hyper-rustls"]
|
||||
webpki-roots = ["rustls-backend", "hyper-rustls/webpki-tokio"]
|
||||
acme = []
|
||||
acme = ["dep:rpxy-acme"]
|
||||
|
||||
[dependencies]
|
||||
rand = "0.8.5"
|
||||
|
|
@ -80,6 +80,9 @@ hot_reload = "0.1.6"
|
|||
rustls = { version = "0.23.11", default-features = false }
|
||||
tokio-rustls = { version = "0.26.0", features = ["early-data"] }
|
||||
|
||||
# acme
|
||||
rpxy-acme = { path = "../rpxy-acme/", default-features = false, optional = true }
|
||||
|
||||
# logging
|
||||
tracing = { version = "0.1.40" }
|
||||
|
||||
|
|
|
|||
|
|
@ -105,4 +105,9 @@ pub enum RpxyError {
|
|||
// Others
|
||||
#[error("Infallible")]
|
||||
Infallible(#[from] std::convert::Infallible),
|
||||
|
||||
/// No Acme server config for Acme challenge
|
||||
#[cfg(feature = "acme")]
|
||||
#[error("No Acme server config")]
|
||||
NoAcmeServerConfig,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,10 @@ pub struct Globals {
|
|||
pub term_notify: Option<Arc<tokio::sync::Notify>>,
|
||||
/// Shared context - Certificate reloader service receiver // TODO: newer one
|
||||
pub cert_reloader_rx: Option<ReloaderReceiver<ServerCryptoBase>>,
|
||||
|
||||
#[cfg(feature = "acme")]
|
||||
/// ServerConfig used for only ACME challenge for ACME domains
|
||||
pub server_configs_acme_challenge: Arc<rustc_hash::FxHashMap<String, Arc<rustls::ServerConfig>>>,
|
||||
}
|
||||
|
||||
/// Configuration parameters for proxy transport and request handlers
|
||||
|
|
|
|||
|
|
@ -30,13 +30,36 @@ pub mod reexports {
|
|||
pub use hyper::Uri;
|
||||
}
|
||||
|
||||
#[derive(derive_builder::Builder)]
|
||||
/// rpxy entrypoint args
|
||||
pub struct RpxyOptions {
|
||||
/// Configuration parameters for proxy transport and request handlers
|
||||
pub proxy_config: ProxyConfig,
|
||||
/// List of application configurations
|
||||
pub app_config_list: AppConfigList,
|
||||
/// Certificate reloader service receiver
|
||||
pub cert_rx: Option<ReloaderReceiver<ServerCryptoBase>>, // TODO:
|
||||
/// Async task runtime handler
|
||||
pub runtime_handle: tokio::runtime::Handle,
|
||||
/// Notify object to stop async tasks
|
||||
pub term_notify: Option<Arc<tokio::sync::Notify>>,
|
||||
|
||||
#[cfg(feature = "acme")]
|
||||
/// ServerConfig used for only ACME challenge for ACME domains
|
||||
pub server_configs_acme_challenge: Arc<rustc_hash::FxHashMap<String, Arc<rustls::ServerConfig>>>,
|
||||
}
|
||||
|
||||
/// Entrypoint that creates and spawns tasks of reverse proxy services
|
||||
pub async fn entrypoint(
|
||||
proxy_config: &ProxyConfig,
|
||||
app_config_list: &AppConfigList,
|
||||
cert_rx: Option<&ReloaderReceiver<ServerCryptoBase>>, // TODO:
|
||||
runtime_handle: &tokio::runtime::Handle,
|
||||
term_notify: Option<Arc<tokio::sync::Notify>>,
|
||||
RpxyOptions {
|
||||
proxy_config,
|
||||
app_config_list,
|
||||
cert_rx, // TODO:
|
||||
runtime_handle,
|
||||
term_notify,
|
||||
#[cfg(feature = "acme")]
|
||||
server_configs_acme_challenge,
|
||||
}: &RpxyOptions,
|
||||
) -> RpxyResult<()> {
|
||||
#[cfg(all(feature = "http3-quinn", feature = "http3-s2n"))]
|
||||
warn!("Both \"http3-quinn\" and \"http3-s2n\" features are enabled. \"http3-quinn\" will be used");
|
||||
|
|
@ -85,7 +108,10 @@ pub async fn entrypoint(
|
|||
request_count: Default::default(),
|
||||
runtime_handle: runtime_handle.clone(),
|
||||
term_notify: term_notify.clone(),
|
||||
cert_reloader_rx: cert_rx.cloned(),
|
||||
cert_reloader_rx: cert_rx.clone(),
|
||||
|
||||
#[cfg(feature = "acme")]
|
||||
server_configs_acme_challenge: server_configs_acme_challenge.clone(),
|
||||
});
|
||||
|
||||
// 3. build message handler containing Arc-ed http_client and backends, and make it contained in Arc as well
|
||||
|
|
|
|||
|
|
@ -167,6 +167,9 @@ where
|
|||
|
||||
let mut server_crypto_map: Option<Arc<super::SniServerCryptoMap>> = None;
|
||||
loop {
|
||||
#[cfg(feature = "acme")]
|
||||
let server_configs_acme_challenge = self.globals.server_configs_acme_challenge.clone();
|
||||
|
||||
select! {
|
||||
tcp_cnx = tcp_listener.accept().fuse() => {
|
||||
if tcp_cnx.is_err() || server_crypto_map.is_none() {
|
||||
|
|
@ -190,11 +193,35 @@ where
|
|||
if server_name.is_none(){
|
||||
return Err(RpxyError::NoServerNameInClientHello);
|
||||
}
|
||||
let server_crypto = sc_map_inner.as_ref().unwrap().get(server_name.as_ref().unwrap());
|
||||
if server_crypto.is_none() {
|
||||
return Err(RpxyError::NoTlsServingApp(server_name.as_ref().unwrap().try_into().unwrap_or_default()));
|
||||
}
|
||||
let stream = match start.into_stream(server_crypto.unwrap().clone()).await {
|
||||
/* ------------------ */
|
||||
// Check for ACME TLS ALPN challenge
|
||||
#[cfg(feature = "acme")]
|
||||
let server_crypto = {
|
||||
if rpxy_acme::reexports::is_tls_alpn_challenge(&client_hello) {
|
||||
info!("ACME TLS ALPN challenge received");
|
||||
let Some(server_crypto_acme) = server_configs_acme_challenge.get(&sni.unwrap().to_ascii_lowercase()) else {
|
||||
return Err(RpxyError::NoAcmeServerConfig);
|
||||
};
|
||||
server_crypto_acme
|
||||
} else {
|
||||
let server_crypto = sc_map_inner.as_ref().unwrap().get(server_name.as_ref().unwrap());
|
||||
let Some(server_crypto) = server_crypto else {
|
||||
return Err(RpxyError::NoTlsServingApp(server_name.as_ref().unwrap().try_into().unwrap_or_default()));
|
||||
};
|
||||
server_crypto
|
||||
}
|
||||
};
|
||||
/* ------------------ */
|
||||
#[cfg(not(feature = "acme"))]
|
||||
let server_crypto = {
|
||||
let server_crypto = sc_map_inner.as_ref().unwrap().get(server_name.as_ref().unwrap());
|
||||
let Some(server_crypto) = server_crypto else {
|
||||
return Err(RpxyError::NoTlsServingApp(server_name.as_ref().unwrap().try_into().unwrap_or_default()));
|
||||
};
|
||||
server_crypto
|
||||
};
|
||||
/* ------------------ */
|
||||
let stream = match start.into_stream(server_crypto.clone()).await {
|
||||
Ok(s) => TokioIo::new(s),
|
||||
Err(e) => {
|
||||
return Err(RpxyError::FailedToTlsHandshake(e.to_string()));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue