actix-net icon indicating copy to clipboard operation
actix-net copied to clipboard

Support hot reloading of SSL credentials

Open scottjmaddox opened this issue 5 years ago • 3 comments

It would be great if there were built-in support for hot reloading of SSL credentials, along with an example for how to do it.

Per @fafhrd91 at https://github.com/actix/actix-web/issues/754:

You just need to replace ssl acceptor. Restart is not required https://github.com/actix/actix-net/blob/master/actix-server/src/ssl/openssl.rs#L62

scottjmaddox avatar Apr 14 '19 18:04 scottjmaddox

Looking at what it was (https://github.com/actix/actix-net/blob/3add90628f3871797794bbd727c5828ff661dc4f/actix-server/src/ssl/openssl.rs#L62 and https://github.com/actix/actix-net/blob/3add90628f3871797794bbd727c5828ff661dc4f/actix-server/src/ssl/rustls.rs#L64), seems to require a lot of set up...

Based on docs, seems that using a wrapped https://docs.rs/rustls/0.16.0/rustls/struct.ResolvesServerCertUsingSNI.html might be useful with interior mutability. Would need to use an rwlock to be able to work with it though, so might require some black magic currently.

ZaneHannanAU avatar Jan 11 '20 22:01 ZaneHannanAU

in our reverse proxy we need to restart the server after adding a new domain or renewing a certificate. I'm really interested in implementing this feature. it's very easy in go as it accept cert resolver function.

rahbari avatar Jan 18 '23 22:01 rahbari

I don't know about openssl, but this is already doable with rustls by implementing a custom CertResolver, as an example we have the following thing :

pub struct CertResolver {
    registered_keys: RwLock<BTreeMap<String, Arc<CertifiedKey>>>,
}

impl ResolvesServerCert for CertResolver {
    fn resolve(&self, client_hello: ClientHello) -> Option<Arc<CertifiedKey>> {
        let server_name = client_hello.server_name()?;

        match self.registered_keys.read() {
            Err(_) => None,
            Ok(registered_keys) => registered_keys.get(server_name).cloned(),
        }
    }
}

Then you can use it when creating the server :

let resolver = Arc::new(CertResolver::default());

let config = ServerConfig::builder()
        .with_safe_defaults()
        .with_no_client_auth()
        .with_cert_resolver(resolver);
        
        
let server = HttpServer::new(move || {
    App::new()
})
.bind_rustls(listen_tls.clone(), config)

Then we have some code that update this cert resolver on some events (cert are not in filesystem), but i guess someone could definitely create a worker that listen to fs events and update this CertResolver

joelwurtz avatar Dec 06 '23 09:12 joelwurtz