Skip to content

letsencrypt: Simplify renewal hooks implementation

Currently, we have a mechanism for renewing certificates that copies certificates and restarts daemons properly when a certificate is renewed. But this mechanism has user configuration and is complex. Simplify it.

New Approach

Here is new plan for implementing Let's Encrypt hooks:

Single hook for all apps

Instead of each application writing an individual hook into the Let's Encryption hook configuration (this is currently done by appending application parameters to hook command), only a single hook will be added such that FreedomBox Service receives hook notification. The service will then look at each application that is interested in renewal notification and perform the processing. D-Bus notification section below describes how this is possible.

Single hook for all domains

Let's Encrypt now allows a single hook for all the domains that it deals with. These hooks are placed in /etc/letsencrypt/renewal-hooks/{pre,post,deploy}. FreedomBox Service should just drop a file in there. On-the-fly adding and removing of hooks will no longer be needed and quite a bit of code can be removed.

When the notification arrives at a application, the application, by looking at its domain configuration, will decide whether it is interested in the notification for that domain or not. If it is not interested, it will simply ignore. If it is interested, then it will perform renewal operations for that domain.

Internal Signals

When FreedomBox Service receives the notification from D-Bus it will emit a signal. The emitted signal will be caught by interested apps. This allows for loose coupling. Let's Encrypt module need not have code for each app that needs renewal handling.

D-Bus notification

We have implemented a mechanism for getting package updates notifications using D-Bus. We should implement a similar mechanism for getting Let's Encrypt renewal notification. This has the following advantages:

  • The notification is sent to the main FreedomBox Service process instead of an action script. This allows us to do quite a few things like check if we are interested in the domain (as we have list of all domains). Send further notifications each interested application and they can then check if they are interested in the notification, etc.
  • This is secure. Not only a root process but also a configurable user will be able to run this notification. The current implementation assumes that the Let's Encrypt will run it's as root user only. Otherwise, the handling fails.

Implementation Plan

This new plan is not a lot of change from where we are already.

  • Implement a D-Bus service for listening to renew notification. This should allow only a root process to send the notification. See dbus.py/PackageHandler for similar implementation.
  • On arrival of the D-Bus notification, emit a signal. Signal must contain the following parameters: 'operation' (pre/post/deploy), 'domains' (a map of domain names to dict with further information, it should contain 'private_key' and 'certificate' keys with full paths). Note the multiple domains may have their certificate renewed in a single operation if the certificate contains a list of domains. The signal must be emitted in a separate thread and not in the D-Bus thread.
  • Subscribe to the signal for each of the interested application. When the signal is emitted, the application will check its configuration if it is interested in domain. Ignore actions such as 'pre' which are not relevant for the app. If the domain and action are interesting it will call its own action action/<app> letsencrypt --domain <domain>. These actions are already implemented.
    • Apache (simply restart apache when signal is received)
    • Ejabberd
    • Matrix Synapse
  • Drop script files into /etc/letsencrypt/renewal-hooks/{pre,post,deploy}. These scripts use gdbus command line tool to call notify FreedomBox Service via D-Bus.
  • Remove UI for renewal configuration. Remove all associated code.
  • Make the functions in actions/letsencrypt run_*_hooks do nothing. But keep the actions for maximum compatibility during upgrade process.
  • Write a migration script to remove all existing hooks in /etc/letsencrypt/{domain}/*.conf.
Edited by Joseph Nuthalapati