refactor: remove explict cert file path from backend mods and define abstracted trait for the cert source preparing librarization
This commit is contained in:
parent
6c0fd85ca5
commit
05b2aab8b0
8 changed files with 55 additions and 60 deletions
|
|
@ -19,7 +19,7 @@ use crate::{
|
||||||
};
|
};
|
||||||
use derive_builder::Builder;
|
use derive_builder::Builder;
|
||||||
use rustc_hash::FxHashMap as HashMap;
|
use rustc_hash::FxHashMap as HashMap;
|
||||||
use std::{borrow::Cow, path::PathBuf};
|
use std::borrow::Cow;
|
||||||
|
|
||||||
/// Struct serving information to route incoming connections, like server name to be handled and tls certs/keys settings.
|
/// Struct serving information to route incoming connections, like server name to be handled and tls certs/keys settings.
|
||||||
#[derive(Builder)]
|
#[derive(Builder)]
|
||||||
|
|
@ -36,16 +36,11 @@ where
|
||||||
/// struct of reverse proxy serving incoming request
|
/// struct of reverse proxy serving incoming request
|
||||||
pub reverse_proxy: ReverseProxy,
|
pub reverse_proxy: ReverseProxy,
|
||||||
|
|
||||||
/// tls settings
|
/// tls settings: https redirection with 30x
|
||||||
#[builder(setter(custom), default)]
|
|
||||||
pub tls_cert_path: Option<PathBuf>,
|
|
||||||
#[builder(setter(custom), default)]
|
|
||||||
pub tls_cert_key_path: Option<PathBuf>,
|
|
||||||
#[builder(default)]
|
#[builder(default)]
|
||||||
pub https_redirection: Option<bool>,
|
pub https_redirection: Option<bool>,
|
||||||
#[builder(setter(custom), default)]
|
|
||||||
pub client_ca_cert_path: Option<PathBuf>,
|
|
||||||
|
|
||||||
|
/// TLS settings: source meta for server cert, key, client ca cert
|
||||||
#[builder(default)]
|
#[builder(default)]
|
||||||
pub crypto_source: Option<T>,
|
pub crypto_source: Option<T>,
|
||||||
}
|
}
|
||||||
|
|
@ -57,22 +52,6 @@ where
|
||||||
self.server_name = Some(server_name.into().to_ascii_lowercase());
|
self.server_name = Some(server_name.into().to_ascii_lowercase());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
pub fn tls_cert_path(&mut self, v: &Option<String>) -> &mut Self {
|
|
||||||
self.tls_cert_path = Some(opt_string_to_opt_pathbuf(v));
|
|
||||||
self
|
|
||||||
}
|
|
||||||
pub fn tls_cert_key_path(&mut self, v: &Option<String>) -> &mut Self {
|
|
||||||
self.tls_cert_key_path = Some(opt_string_to_opt_pathbuf(v));
|
|
||||||
self
|
|
||||||
}
|
|
||||||
pub fn client_ca_cert_path(&mut self, v: &Option<String>) -> &mut Self {
|
|
||||||
self.client_ca_cert_path = Some(opt_string_to_opt_pathbuf(v));
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn opt_string_to_opt_pathbuf(input: &Option<String>) -> Option<PathBuf> {
|
|
||||||
input.to_owned().as_ref().map(PathBuf::from)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// HashMap and some meta information for multiple Backend structs.
|
/// HashMap and some meta information for multiple Backend structs.
|
||||||
|
|
|
||||||
|
|
@ -36,8 +36,8 @@ impl CryptoFileSourceBuilder {
|
||||||
self.tls_cert_key_path = Some(PathBuf::from(v));
|
self.tls_cert_key_path = Some(PathBuf::from(v));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
pub fn client_ca_cert_path(&mut self, v: &str) -> &mut Self {
|
pub fn client_ca_cert_path(&mut self, v: &Option<String>) -> &mut Self {
|
||||||
self.client_ca_cert_path = Some(Some(PathBuf::from(v)));
|
self.client_ca_cert_path = Some(v.to_owned().as_ref().map(PathBuf::from));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -45,6 +45,7 @@ impl CryptoFileSourceBuilder {
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl CryptoSource for CryptoFileSource {
|
impl CryptoSource for CryptoFileSource {
|
||||||
type Error = io::Error;
|
type Error = io::Error;
|
||||||
|
/// read crypto materials from source
|
||||||
async fn read(&self) -> Result<CertsAndKeys, Self::Error> {
|
async fn read(&self) -> Result<CertsAndKeys, Self::Error> {
|
||||||
read_certs_and_keys(
|
read_certs_and_keys(
|
||||||
&self.tls_cert_path,
|
&self.tls_cert_path,
|
||||||
|
|
@ -52,10 +53,14 @@ impl CryptoSource for CryptoFileSource {
|
||||||
self.client_ca_cert_path.as_ref(),
|
self.client_ca_cert_path.as_ref(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
/// Returns true when mutual tls is enabled
|
||||||
|
fn is_mutual_tls(&self) -> bool {
|
||||||
|
self.client_ca_cert_path.is_some()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read certificates and private keys from file
|
/// Read certificates and private keys from file
|
||||||
pub(crate) fn read_certs_and_keys(
|
fn read_certs_and_keys(
|
||||||
cert_path: &PathBuf,
|
cert_path: &PathBuf,
|
||||||
cert_key_path: &PathBuf,
|
cert_key_path: &PathBuf,
|
||||||
client_ca_cert_path: Option<&PathBuf>,
|
client_ca_cert_path: Option<&PathBuf>,
|
||||||
|
|
@ -162,11 +167,11 @@ mod tests {
|
||||||
async fn read_server_crt_key_files_with_client_ca_crt() {
|
async fn read_server_crt_key_files_with_client_ca_crt() {
|
||||||
let tls_cert_path = "example-certs/server.crt";
|
let tls_cert_path = "example-certs/server.crt";
|
||||||
let tls_cert_key_path = "example-certs/server.key";
|
let tls_cert_key_path = "example-certs/server.key";
|
||||||
let client_ca_cert_path = "example-certs/client.ca.crt";
|
let client_ca_cert_path = Some("example-certs/client.ca.crt".to_string());
|
||||||
let crypto_file_source = CryptoFileSourceBuilder::default()
|
let crypto_file_source = CryptoFileSourceBuilder::default()
|
||||||
.tls_cert_key_path(tls_cert_key_path)
|
.tls_cert_key_path(tls_cert_key_path)
|
||||||
.tls_cert_path(tls_cert_path)
|
.tls_cert_path(tls_cert_path)
|
||||||
.client_ca_cert_path(client_ca_cert_path)
|
.client_ca_cert_path(&client_ca_cert_path)
|
||||||
.build();
|
.build();
|
||||||
assert!(crypto_file_source.is_ok());
|
assert!(crypto_file_source.is_ok());
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,5 +13,10 @@ pub struct CertsAndKeys {
|
||||||
// Trait to read certs and keys anywhere from KVS, file, sqlite, etc.
|
// Trait to read certs and keys anywhere from KVS, file, sqlite, etc.
|
||||||
pub trait CryptoSource {
|
pub trait CryptoSource {
|
||||||
type Error;
|
type Error;
|
||||||
|
|
||||||
|
/// read crypto materials from source
|
||||||
async fn read(&self) -> Result<CertsAndKeys, Self::Error>;
|
async fn read(&self) -> Result<CertsAndKeys, Self::Error>;
|
||||||
|
|
||||||
|
/// Returns true when mutual tls is enabled
|
||||||
|
fn is_mutual_tls(&self) -> bool;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,16 @@
|
||||||
use super::toml::ConfigToml;
|
use super::toml::ConfigToml;
|
||||||
use crate::{backend::Backends, certs::CryptoSource, error::*, globals::*, log::*, utils::BytesName};
|
use crate::{
|
||||||
|
backend::Backends,
|
||||||
|
cert_file_reader::CryptoFileSource,
|
||||||
|
error::{anyhow, ensure},
|
||||||
|
globals::*,
|
||||||
|
log::*,
|
||||||
|
utils::BytesName,
|
||||||
|
};
|
||||||
use clap::Arg;
|
use clap::Arg;
|
||||||
use tokio::runtime::Handle;
|
use tokio::runtime::Handle;
|
||||||
|
|
||||||
pub fn build_globals<T>(runtime_handle: Handle) -> std::result::Result<Globals<T>, anyhow::Error>
|
pub fn build_globals(runtime_handle: Handle) -> std::result::Result<Globals<CryptoFileSource>, anyhow::Error> {
|
||||||
where
|
|
||||||
T: CryptoSource + Clone,
|
|
||||||
{
|
|
||||||
let _ = include_str!("../../Cargo.toml");
|
let _ = include_str!("../../Cargo.toml");
|
||||||
let options = clap::command!().arg(
|
let options = clap::command!().arg(
|
||||||
Arg::new("config_file")
|
Arg::new("config_file")
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::{Backend, BackendBuilder, ReverseProxy, Upstream, UpstreamGroup, UpstreamGroupBuilder, UpstreamOption},
|
backend::{Backend, BackendBuilder, ReverseProxy, Upstream, UpstreamGroup, UpstreamGroupBuilder, UpstreamOption},
|
||||||
certs::CryptoSource,
|
cert_file_reader::{CryptoFileSource, CryptoFileSourceBuilder},
|
||||||
constants::*,
|
constants::*,
|
||||||
error::*,
|
error::{anyhow, ensure},
|
||||||
globals::ProxyConfig,
|
globals::ProxyConfig,
|
||||||
utils::PathNameBytesExp,
|
utils::PathNameBytesExp,
|
||||||
};
|
};
|
||||||
|
|
@ -164,20 +164,17 @@ impl TryInto<ProxyConfig> for &ConfigToml {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConfigToml {
|
impl ConfigToml {
|
||||||
pub fn new(config_file: &str) -> std::result::Result<Self, RpxyError> {
|
pub fn new(config_file: &str) -> std::result::Result<Self, anyhow::Error> {
|
||||||
let config_str = fs::read_to_string(config_file).map_err(RpxyError::Io)?;
|
let config_str = fs::read_to_string(config_file)?;
|
||||||
|
|
||||||
toml::from_str(&config_str).map_err(RpxyError::TomlDe)
|
toml::from_str(&config_str).map_err(|e| anyhow!(e))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> TryInto<Backend<T>> for &Application
|
impl TryInto<Backend<CryptoFileSource>> for &Application {
|
||||||
where
|
|
||||||
T: CryptoSource + Clone,
|
|
||||||
{
|
|
||||||
type Error = anyhow::Error;
|
type Error = anyhow::Error;
|
||||||
|
|
||||||
fn try_into(self) -> std::result::Result<Backend<T>, Self::Error> {
|
fn try_into(self) -> std::result::Result<Backend<CryptoFileSource>, Self::Error> {
|
||||||
let server_name_string = self.server_name.as_ref().ok_or(anyhow!("Missing server_name"))?;
|
let server_name_string = self.server_name.as_ref().ok_or(anyhow!("Missing server_name"))?;
|
||||||
|
|
||||||
// backend builder
|
// backend builder
|
||||||
|
|
@ -203,11 +200,15 @@ where
|
||||||
tls.https_redirection
|
tls.https_redirection
|
||||||
};
|
};
|
||||||
|
|
||||||
backend_builder
|
let crypto_source = CryptoFileSourceBuilder::default()
|
||||||
.tls_cert_path(&tls.tls_cert_path)
|
.tls_cert_path(tls.tls_cert_path.as_ref().unwrap())
|
||||||
.tls_cert_key_path(&tls.tls_cert_key_path)
|
.tls_cert_key_path(tls.tls_cert_key_path.as_ref().unwrap())
|
||||||
.https_redirection(https_redirection)
|
|
||||||
.client_ca_cert_path(&tls.client_ca_cert_path)
|
.client_ca_cert_path(&tls.client_ca_cert_path)
|
||||||
|
.build()?;
|
||||||
|
|
||||||
|
backend_builder
|
||||||
|
.https_redirection(https_redirection)
|
||||||
|
.crypto_source(Some(crypto_source))
|
||||||
.build()?
|
.build()?
|
||||||
};
|
};
|
||||||
Ok(backend)
|
Ok(backend)
|
||||||
|
|
@ -255,7 +256,7 @@ impl TryInto<ReverseProxy> for &Application {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryInto<Upstream> for &UpstreamParams {
|
impl TryInto<Upstream> for &UpstreamParams {
|
||||||
type Error = RpxyError;
|
type Error = anyhow::Error;
|
||||||
|
|
||||||
fn try_into(self) -> std::result::Result<Upstream, Self::Error> {
|
fn try_into(self) -> std::result::Result<Upstream, Self::Error> {
|
||||||
let scheme = match self.tls {
|
let scheme = match self.tls {
|
||||||
|
|
|
||||||
|
|
@ -29,9 +29,8 @@ pub enum RpxyError {
|
||||||
#[error("I/O Error")]
|
#[error("I/O Error")]
|
||||||
Io(#[from] io::Error),
|
Io(#[from] io::Error),
|
||||||
|
|
||||||
#[error("Toml Deserialization Error")]
|
// #[error("Toml Deserialization Error")]
|
||||||
TomlDe(#[from] toml::de::Error),
|
// TomlDe(#[from] toml::de::Error),
|
||||||
|
|
||||||
#[cfg(feature = "http3")]
|
#[cfg(feature = "http3")]
|
||||||
#[error("Quic Connection Error")]
|
#[error("Quic Connection Error")]
|
||||||
QuicConn(#[from] quinn::ConnectionError),
|
QuicConn(#[from] quinn::ConnectionError),
|
||||||
|
|
|
||||||
|
|
@ -209,7 +209,12 @@ where
|
||||||
#[cfg(feature = "http3")]
|
#[cfg(feature = "http3")]
|
||||||
{
|
{
|
||||||
// TODO: Workaround for avoid h3 for client authentication
|
// TODO: Workaround for avoid h3 for client authentication
|
||||||
if self.globals.proxy_config.http3 && chosen_backend.client_ca_cert_path.is_none() {
|
if self.globals.proxy_config.http3
|
||||||
|
&& chosen_backend
|
||||||
|
.crypto_source
|
||||||
|
.as_ref()
|
||||||
|
.is_some_and(|v| !v.is_mutual_tls())
|
||||||
|
{
|
||||||
if let Some(port) = self.globals.proxy_config.https_port {
|
if let Some(port) = self.globals.proxy_config.https_port {
|
||||||
add_header_entry_overwrite_if_exist(
|
add_header_entry_overwrite_if_exist(
|
||||||
headers,
|
headers,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
cert_file_reader::read_certs_and_keys, // TODO: Trait defining read_certs_and_keys and add struct implementing the trait to backend when build backend
|
|
||||||
certs::{CertsAndKeys, CryptoSource},
|
certs::{CertsAndKeys, CryptoSource},
|
||||||
globals::Globals,
|
globals::Globals,
|
||||||
log::*,
|
log::*,
|
||||||
|
|
@ -55,13 +54,11 @@ where
|
||||||
let mut certs_and_keys_map = ServerCryptoBase::default();
|
let mut certs_and_keys_map = ServerCryptoBase::default();
|
||||||
|
|
||||||
for (server_name_bytes_exp, backend) in self.globals.backends.apps.iter() {
|
for (server_name_bytes_exp, backend) in self.globals.backends.apps.iter() {
|
||||||
if backend.tls_cert_key_path.is_some() && backend.tls_cert_path.is_some() {
|
if let Some(crypto_source) = &backend.crypto_source {
|
||||||
let tls_cert_key_path = backend.tls_cert_key_path.as_ref().unwrap();
|
let certs_and_keys = crypto_source
|
||||||
let tls_cert_path = backend.tls_cert_path.as_ref().unwrap();
|
.read()
|
||||||
let tls_client_ca_cert_path = backend.client_ca_cert_path.as_ref();
|
.await
|
||||||
let certs_and_keys = read_certs_and_keys(tls_cert_path, tls_cert_key_path, tls_client_ca_cert_path)
|
|
||||||
.map_err(|_e| ReloaderError::<ServerCryptoBase>::Reload("Failed to reload cert, key or ca cert"))?;
|
.map_err(|_e| ReloaderError::<ServerCryptoBase>::Reload("Failed to reload cert, key or ca cert"))?;
|
||||||
|
|
||||||
certs_and_keys_map
|
certs_and_keys_map
|
||||||
.inner
|
.inner
|
||||||
.insert(server_name_bytes_exp.to_owned(), certs_and_keys);
|
.insert(server_name_bytes_exp.to_owned(), certs_and_keys);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue