|
|
|
@ -19,6 +19,7 @@ use crate::proxy_config::*; |
|
|
|
|
pub struct CertStore { |
|
|
|
|
consul: Consul, |
|
|
|
|
certs: RwLock<HashMap<String, Arc<Cert>>>, |
|
|
|
|
self_signed_certs: RwLock<HashMap<String, Arc<Cert>>>, |
|
|
|
|
rx_proxy_config: watch::Receiver<Arc<ProxyConfig>>, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -27,6 +28,7 @@ impl CertStore { |
|
|
|
|
Arc::new(Self { |
|
|
|
|
consul, |
|
|
|
|
certs: RwLock::new(HashMap::new()), |
|
|
|
|
self_signed_certs: RwLock::new(HashMap::new()), |
|
|
|
|
rx_proxy_config, |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
@ -66,16 +68,23 @@ impl CertStore { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Check in local memory if it exists
|
|
|
|
|
let certs = self.certs.read().unwrap(); |
|
|
|
|
if let Some(cert) = certs.get(domain) { |
|
|
|
|
if let Some(cert) = self.certs.read().unwrap().get(domain) { |
|
|
|
|
if !cert.is_old() { |
|
|
|
|
return Ok(cert.clone()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Not found in local memory
|
|
|
|
|
// Not found in local memory, try to get it in background
|
|
|
|
|
tokio::spawn(self.clone().get_cert_task(domain.to_string())); |
|
|
|
|
bail!("Certificate not found (will try to get it in background)"); |
|
|
|
|
|
|
|
|
|
// In the meantime, use a self-signed certificate
|
|
|
|
|
if let Some(cert) = self.self_signed_certs.read().unwrap().get(domain) { |
|
|
|
|
if !cert.is_old() { |
|
|
|
|
return Ok(cert.clone()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
self.gen_self_signed_certificate(domain) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub async fn get_cert_task(self: Arc<Self>, domain: String) -> Result<Arc<Cert>> { |
|
|
|
@ -221,6 +230,27 @@ impl CertStore { |
|
|
|
|
info!("Cert successfully renewed: {}", domain); |
|
|
|
|
Ok(cert) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn gen_self_signed_certificate(&self, domain: &str) -> Result<Arc<Cert>> { |
|
|
|
|
let subject_alt_names = vec![domain.to_string(), "localhost".to_string()]; |
|
|
|
|
let cert = rcgen::generate_simple_self_signed(subject_alt_names)?; |
|
|
|
|
|
|
|
|
|
let certser = CertSer { |
|
|
|
|
hostname: domain.to_string(), |
|
|
|
|
date: Utc::today().naive_utc(), |
|
|
|
|
valid_days: 1024, |
|
|
|
|
key_pem: cert.serialize_private_key_pem(), |
|
|
|
|
cert_pem: cert.serialize_pem()?, |
|
|
|
|
}; |
|
|
|
|
let cert = Arc::new(Cert::new(certser)?); |
|
|
|
|
self.self_signed_certs |
|
|
|
|
.write() |
|
|
|
|
.unwrap() |
|
|
|
|
.insert(domain.to_string(), cert.clone()); |
|
|
|
|
info!("Added self-signed certificate for {}", domain); |
|
|
|
|
|
|
|
|
|
Ok(cert) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub struct StoreResolver(pub Arc<CertStore>); |
|
|
|
@ -228,7 +258,12 @@ pub struct StoreResolver(pub Arc<CertStore>); |
|
|
|
|
impl rustls::server::ResolvesServerCert for StoreResolver { |
|
|
|
|
fn resolve(&self, client_hello: rustls::server::ClientHello<'_>) -> Option<Arc<CertifiedKey>> { |
|
|
|
|
let domain = client_hello.server_name()?; |
|
|
|
|
let cert = self.0.get_cert_for_https(domain).ok()?; |
|
|
|
|
Some(cert.certkey.clone()) |
|
|
|
|
match self.0.get_cert_for_https(domain) { |
|
|
|
|
Ok(cert) => Some(cert.certkey.clone()), |
|
|
|
|
Err(e) => { |
|
|
|
|
warn!("Could not get certificate for {}: {}", domain, e); |
|
|
|
|
None |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|