aboutsummaryrefslogtreecommitdiff
path: root/src/cert_store.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/cert_store.rs')
-rw-r--r--src/cert_store.rs47
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
+ }
+ }
}
}