mjl- / mox

modern full-featured open source secure mail server for low-maintenance self-hosted email
https://www.xmox.nl
MIT License
3.71k stars 113 forks source link

Try reloading TLS certs before erroring #77

Closed mattfbacon closed 1 year ago

mattfbacon commented 1 year ago

If there is some external tool renewing the TLS certificates, the mail server may retain the old certificates. As such, if the TLS certificate expires and mox notices this, I would like it to check if there is a new TLS certificate and, if there is, reload it.

This may be problematic with the current "start as root, load certs, drop perms" model of launching, but I would be fine with it just trying to load the certs as its normal unprivileged user; I can handle setting up the permissions properly.

mjl- commented 1 year ago

Ah, I suppose this is the reason for issue #76 as well? Indeed, currently the only approach is to restart mox after getting a new certificate. I can see why that doesn't feel great. Perhaps we could add a command to only reload the statically configured TLS keys/certs from mox.conf. I'll have a look. Or if you would like to try implementing it, that would be good too of course. (:

mattfbacon commented 1 year ago

I guess the question would be, how does mox reload the certs when it handles the letsencrypt renewal internally? In theory that same method should be applicable.

mjl- commented 1 year ago

I guess the question would be, how does mox reload the certs when it handles the letsencrypt renewal internally?

good point. the autocert package does most of that handling, mox wraps it in its package autotls. these packages provide a crypto/tls.Config that has a callback configured that is called for incoming connections. see GetCertificate in https://pkg.go.dev/crypto/tls#Config.

for acme, if a certificate/key isn't already in the cache, it looks for them in the file system. if absent (or expired), it will ask for a new certificate (from let's encrypt by default).

we could have a mode where we do something similar for the statically configured certificates/keys. but it would have to be configurable, because i added the current behaviour (open as root and pass file descriptors to unprivileged process) because users would have the files inaccessible by the mox user. we could do a stat() on the cert/key files (max once every 3 seconds or so), and reload them when changed (after checking they are valid).

i'll try this approach in a few days.

mattfbacon commented 1 year ago

Yeah, similar to that, but my idea was just to check the expiration inside the TLS cert and reload it from the same path once before failing. Not so complicated as continually checking the certs for updates.

Btw, the use case for me was with certbot running separately. In my installation, I just put an ExecStartPost in the certbot systemd unit to reload-or-restart everything that depends on the certs (currently nginx and mox).

mattfbacon commented 1 year ago

Closing this because the restarting approach works fine.

mjl- commented 1 year ago

I wouldn't mind leaving this open. I think mox can be changed to just try to reload the certificate while it is running. When permissions are such that mox can read the key file, and they contain a modified and valid key, the file can be reloaded. When there is no permission (during first attempt to load it after starting), mox can just not try reloading the file. It's not high on the priority list though...

mattfbacon commented 1 year ago

Sure, I'm just saying that I am no longer interested in implementing this.