|
|
|
@ -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
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|