diff --git a/proxy/src/certs.rs b/proxy/src/certs.rs index 528670d964..162e59e7ea 100644 --- a/proxy/src/certs.rs +++ b/proxy/src/certs.rs @@ -206,9 +206,9 @@ impl GlobMap { } } -struct CertResolverEntry { - raw: Arc, - names: Vec, +pub struct CertResolverEntry { + pub raw: Arc, + pub names: Vec, } pub struct CertResolver { @@ -242,16 +242,17 @@ impl CertResolver { storage: builder.build()?, }) } + + pub fn resolve_raw(&self, name: &str) -> Option<&CertResolverEntry> { + let entries = self.storage.query(name); + entries.first().copied() + } } impl ResolvesServerCert for CertResolver { fn resolve(&self, message: ClientHello) -> Option> { let name = message.server_name()?; - let certs = self.storage.query(name); - let first = certs.first()?; - - // TODO: warn if there's more than one match! - Some(first.raw.clone()) + self.resolve_raw(name).map(|entry| entry.raw.clone()) } } diff --git a/proxy/src/config.rs b/proxy/src/config.rs index 42e04bfe93..31b9480703 100644 --- a/proxy/src/config.rs +++ b/proxy/src/config.rs @@ -1,4 +1,4 @@ -use crate::auth; +use crate::{auth, certs}; use anyhow::{bail, Context}; use std::{str::FromStr, sync::Arc, time::Duration}; @@ -25,6 +25,27 @@ impl TlsConfig { } } +impl TlsConfig { + pub fn new(resolver: certs::CertResolver) -> anyhow::Result { + let resolver = Arc::new(resolver); + + let rustls_config = rustls::ServerConfig::builder() + .with_safe_default_cipher_suites() + .with_safe_default_kx_groups() + // allow TLS 1.2 to be compatible with older client libraries + .with_protocol_versions(&[&rustls::version::TLS13, &rustls::version::TLS12])? + .with_no_client_auth() + .with_cert_resolver(resolver.clone()); + + let config = TlsConfig { + config: Arc::new(rustls_config), + common_name: None, + }; + + Ok(config) + } +} + /// Helper for cmdline cache options parsing. pub struct CacheOptions { /// Max number of entries. diff --git a/proxy/src/main.rs b/proxy/src/main.rs index c072e25dd7..7979505892 100644 --- a/proxy/src/main.rs +++ b/proxy/src/main.rs @@ -25,6 +25,7 @@ mod waiters; use anyhow::{bail, Context}; use auth::BackendType; +use certs::config::TlsServers; use clap::{self, Arg}; use config::{MetricCollectionConfig, ProxyConfig, TlsConfig}; use futures::FutureExt; @@ -129,22 +130,24 @@ async fn handle_signals() -> anyhow::Result<()> { } fn build_tls_config(args: &clap::ArgMatches) -> anyhow::Result> { - use certs::config::TlsServers; - let tls_config = args.get_one::("tls-config"); let main = tls_config.map(TlsServers::from_config_file).transpose()?; - certs::CertResolver::new(main.unwrap()); let tls_cert = args.get_one::("tls-cert"); let tls_key = args.get_one::("tls-key"); - let aux = match (tls_cert, tls_key) { + let _aux = match (tls_cert, tls_key) { (Some(_key), Some(_cert)) => todo!("implement legacy TLS setup"), (None, None) => None::<()>, _ => bail!("either both or neither tls-key and tls-cert must be specified"), }; - todo!("TlsConfig") + // TODO: first merge `main` and `_aux` into one. + main.map(|servers| { + let resolver = certs::CertResolver::new(servers)?; + TlsConfig::new(resolver) + }) + .transpose() } fn build_metrics_config(args: &clap::ArgMatches) -> anyhow::Result> { @@ -279,7 +282,7 @@ fn cli() -> clap::Command { .arg( Arg::new("tls-config") .long("tls-config") - .help("path to the TLS config file") + .help("path to the TLS config file (example: config/servers.dhall)") .value_parser(clap::builder::PathBufValueParser::new()), ) .arg(