diff options
Diffstat (limited to 'src/cert_store.rs')
-rw-r--r-- | src/cert_store.rs | 47 |
1 files changed, 41 insertions, 6 deletions
diff --git a/src/cert_store.rs b/src/cert_store.rs index 8d45df4..4cc2fc0 100644 --- a/src/cert_store.rs +++ b/src/cert_store.rs @@ -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 + } + } } } |