From 584128f372f44892fcdfebc9cc3bbb8a00f715fc Mon Sep 17 00:00:00 2001 From: Tom Whitwell Date: Tue, 9 Aug 2022 12:37:40 +0100 Subject: [PATCH] Implement a post-renewal hook script Sometimes, after a certificate is renewed, you may want to do something with the new certificate. For example, you may want to restart a web server or reload a configuration file. This change allows for a renewal script to be created by specifying commands in the `step_acme_cert_post_renewal_commands` variable. An example of this is for provisioning a certificate for UniFi's Controller. The following configuration will update unifi's jks and restart the service after the certificate is renewed: ```yaml step_acme_cert_post_renewal_commands: - openssl pkcs12 -export -in "${CERT_FILE}" -inkey "${KEY_FILE}" -out /etc/ssl/cert.p12 -name unifi -password pass:aircontrolenterprise - keytool -importkeystore -deststorepass aircontrolenterprise -destkeypass aircontrolenterprise -destkeystore /usr/lib/unifi/data/keystore -srckeystore /etc/ssl/cert.p12 -srcstoretype PKCS12 -srcstorepass aircontrolenterprise -alias unifi - systemctl restart unifi ``` `systemctl try-reload-or-restart {{step_acme_cert_renewal_reload_services}}` has been removed from the `ExecStart` command in the systemd unit file, and is appended to the end of this post-renewal hook script. In the example above, I am using `systemctl restart unifi` as the last command, because I have experienced issues with `systemctl try-reload-or-restart` for this specific service. For a 'more normal' service, the following should work: ```yaml step_acme_cert_post_renewal_commands: - do_something ${CERT_FILE} ${KEY_FILE} step_acme_cert_renewal_reload_services: - some_service ``` The variables ${STEP_CLI}, ${CERT_FILE}, and ${KEY_FILE} are all exported in the script by default, and are available for use in the commands. This change is backwards compatible, and will not break existing configurations. Signed-off-by: Tom Whitwell --- roles/step_acme_cert/defaults/main.yml | 2 ++ roles/step_acme_cert/tasks/renewal.yml | 8 ++++++++ .../templates/step-post-renew-hook.sh.j2 | 12 ++++++++++++ roles/step_acme_cert/templates/step-renew.service.j2 | 2 +- 4 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 roles/step_acme_cert/templates/step-post-renew-hook.sh.j2 diff --git a/roles/step_acme_cert/defaults/main.yml b/roles/step_acme_cert/defaults/main.yml index c440f106..cd81489d 100644 --- a/roles/step_acme_cert/defaults/main.yml +++ b/roles/step_acme_cert/defaults/main.yml @@ -25,4 +25,6 @@ step_acme_cert_keyfile_defaults: step_acme_cert_renewal_service: step-renew #step_acme_cert_renewal_when: 8h +step_acme_cert_post_renewal_shell: "/bin/sh" +step_acme_cert_post_renewal_commands: [] step_acme_cert_renewal_reload_services: [] diff --git a/roles/step_acme_cert/tasks/renewal.yml b/roles/step_acme_cert/tasks/renewal.yml index a0cf31c4..fcaf8009 100644 --- a/roles/step_acme_cert/tasks/renewal.yml +++ b/roles/step_acme_cert/tasks/renewal.yml @@ -6,6 +6,14 @@ changed_when: no check_mode: no +- name: Post renewal hook script is present + template: + src: step-post-renew-hook.sh.j2 + dest: "{{step_cli_steppath}}/{{ step_acme_cert_renewal_service }}_post.sh" + owner: root + group: root + mode: 0744 + - name: Renewal service is installed template: src: step-renew.service.j2 diff --git a/roles/step_acme_cert/templates/step-post-renew-hook.sh.j2 b/roles/step_acme_cert/templates/step-post-renew-hook.sh.j2 new file mode 100644 index 00000000..c371430e --- /dev/null +++ b/roles/step_acme_cert/templates/step-post-renew-hook.sh.j2 @@ -0,0 +1,12 @@ +#!{{ step_acme_cert_post_renewal_shell }} +####### added by ansible: maxhoesel.smallstep.step_acme_cert - changes will be overwritten ####### +set -eu +export STEP_CLI="{{ step_cli_executable_absolute.stdout }}" +export CERT_FILE="{{ step_acme_cert_certfile_full.path }}" +export KEY_FILE="{{ step_acme_cert_keyfile_full.path }}" +{% for command in step_acme_cert_post_renewal_commands -%} +{{ command }} +{% endfor -%} +{% if step_acme_cert_renewal_reload_services -%} +systemctl try-reload-or-restart {{ step_acme_cert_renewal_reload_services | join(' ') }} +{% endif -%} diff --git a/roles/step_acme_cert/templates/step-renew.service.j2 b/roles/step_acme_cert/templates/step-renew.service.j2 index f8030ee9..8c9082f9 100644 --- a/roles/step_acme_cert/templates/step-renew.service.j2 +++ b/roles/step_acme_cert/templates/step-renew.service.j2 @@ -9,7 +9,7 @@ Type=simple Restart=always RestartSec=1 Environment=STEPPATH={{ step_cli_steppath }} -ExecStart={{ step_cli_executable_absolute.stdout }} ca renew {{ step_acme_cert_certfile_full.path }} {{ step_acme_cert_keyfile_full.path }} --daemon --force{% if step_acme_cert_renewal_when is defined %} --expires-in {{ step_acme_cert_renewal_when }}{% endif %}{% if step_acme_cert_renewal_reload_services %} --exec "systemctl try-reload-or-restart {{ step_acme_cert_renewal_reload_services | join(' ') }}"{% endif %} +ExecStart={{ step_cli_executable_absolute.stdout }} ca renew {{ step_acme_cert_certfile_full.path }} {{ step_acme_cert_keyfile_full.path }} --daemon --force{% if step_acme_cert_renewal_when is defined %} --expires-in {{ step_acme_cert_renewal_when }}{% endif %}{% if step_acme_cert_post_renewal_commands or step_acme_cert_renewal_reload_services %} --exec "{{ step_acme_cert_post_renewal_shell }} {{ step_cli_steppath }}/{{ step_acme_cert_renewal_service }}_post.sh"{% endif %} [Install] WantedBy=multi-user.target