Search code examples
python-3.xpython-asynciotcpserver

Long running Asyncio server, reload certificate


I have a custom TCP server implemented with Python 3.5's asyncio library. I also use Lets Encrypt certificates for SSL encryption of the communication with the server. Lets Encrypt only issues certificates valid for 90 days and there is a good chance my server will not be restarted for a longer period of time than this.

I am generating the SSLContext like this:

ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
ssl_context.load_cert_chain(certfile='path/to/cert', keyfile='path/to/key')

And the server like this:

server = asyncio.streams.start_server(self._accept_client, ip, port, loop=self.loop, ssl=ssl_context)

When the certificate expires, existing connections continue to function but new connections will (correctly) fail. Apparently the SSLContext or the server itself keeps the certificate and key files loaded in memory because updating the files on disk does not solve the problem.

I've read the Python documentation quite a bit and found no solution mentioned. One idea I've had is to try call the ssl_context.load_cert_chain() on a regular interval with the hope that this will update cert and key. I can't look at the source of the load_cert_chain function to determine it's behavior as it is apparently written in C, and the documentation doesn't specify the behavior of calling this function once the context has been passed to the server.

Is there a way to update the certificate and keyfile loaded in the SSLContext at runtime without completely stopping and restarting the server?


Solution

  • I am fairly sure that keeping a copy of the context you use and calling the method to reload the cert chain will work fine. At least at the C openssl API level that's a reasonable thing to do and it doesn't look like python does anything to break that.