summaryrefslogtreecommitdiff
path: root/roles/x509/acmetool/cert/prepare
diff options
context:
space:
mode:
Diffstat (limited to 'roles/x509/acmetool/cert/prepare')
-rw-r--r--roles/x509/acmetool/cert/prepare/defaults/main.yml2
-rw-r--r--roles/x509/acmetool/cert/prepare/filter_plugins/acme_certs.py24
-rw-r--r--roles/x509/acmetool/cert/prepare/handlers/main.yml10
-rw-r--r--roles/x509/acmetool/cert/prepare/tasks/main.yml79
-rw-r--r--roles/x509/acmetool/cert/prepare/templates/reload.sh.j231
5 files changed, 146 insertions, 0 deletions
diff --git a/roles/x509/acmetool/cert/prepare/defaults/main.yml b/roles/x509/acmetool/cert/prepare/defaults/main.yml
new file mode 100644
index 00000000..d4eb7c86
--- /dev/null
+++ b/roles/x509/acmetool/cert/prepare/defaults/main.yml
@@ -0,0 +1,2 @@
+---
+acmetool_cert_hostnames: "{{ x509_certificate_hostnames }}"
diff --git a/roles/x509/acmetool/cert/prepare/filter_plugins/acme_certs.py b/roles/x509/acmetool/cert/prepare/filter_plugins/acme_certs.py
new file mode 100644
index 00000000..179f71e9
--- /dev/null
+++ b/roles/x509/acmetool/cert/prepare/filter_plugins/acme_certs.py
@@ -0,0 +1,24 @@
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+from functools import partial
+
+from ansible import errors
+
+
+def acme_cert_nonexistent(data, hostnames):
+ try:
+ return [hostnames[i] for i, d in enumerate(data) if d['stat']['exists'] == False]
+ except Exception as e:
+ raise errors.AnsibleFilterError("acme_cert_nonexistent(): %s" % str(e))
+
+
+class FilterModule(object):
+
+ ''' acme certificate filters '''
+ filter_map = {
+ 'acme_cert_nonexistent': acme_cert_nonexistent,
+ }
+
+ def filters(self):
+ return self.filter_map
diff --git a/roles/x509/acmetool/cert/prepare/handlers/main.yml b/roles/x509/acmetool/cert/prepare/handlers/main.yml
new file mode 100644
index 00000000..330bcd11
--- /dev/null
+++ b/roles/x509/acmetool/cert/prepare/handlers/main.yml
@@ -0,0 +1,10 @@
+---
+- name: reload systemd
+ systemd:
+ daemon_reload: yes
+
+- name: reload services for x509 certificates
+ loop: "{{ x509_certificate_reload_services | default([]) }}"
+ service:
+ name: "{{ item }}"
+ state: reloaded
diff --git a/roles/x509/acmetool/cert/prepare/tasks/main.yml b/roles/x509/acmetool/cert/prepare/tasks/main.yml
new file mode 100644
index 00000000..2db332b8
--- /dev/null
+++ b/roles/x509/acmetool/cert/prepare/tasks/main.yml
@@ -0,0 +1,79 @@
+---
+- name: check if acme certs already exist
+ loop: "{{ acmetool_cert_hostnames }}"
+ loop_control:
+ loop_var: acme_hostname
+ stat:
+ path: "/var/lib/acme/live/{{ acme_hostname }}"
+ register: acme_cert_stat
+
+- name: set acmecert_missing_hostnames variable
+ set_fact:
+ acmecert_missing_hostnames: "{{ acme_cert_stat.results | acme_cert_nonexistent(acmetool_cert_hostnames) }}"
+
+- name: link nonexistent hostnames to self-signed interim cert
+ when: acmecert_missing_hostnames | length > 0
+ block:
+ - name: get id of existing selfsigned interim certificate
+ command: cat /var/lib/acme/.selfsigned-interim-cert
+ changed_when: false
+ check_mode: false
+ register: selfsigned_interim_cert_id
+
+ - name: set selfsigned_interim_cert_id variable
+ set_fact:
+ selfsigned_interim_cert_id: "{{ selfsigned_interim_cert_id.stdout }}"
+
+ - name: link to snakeoil cert for nonexistent hostnames
+ loop: "{{ acmecert_missing_hostnames }}"
+ loop_control:
+ loop_var: acme_missing_hostname
+ file:
+ src: "../certs/{{ selfsigned_interim_cert_id }}"
+ dest: "/var/lib/acme/live/{{ acme_missing_hostname }}"
+ state: link
+ notify: reload services for x509 certificates
+
+- name: export paths to certificate files
+ set_fact:
+ x509_certificate_path_key: "/var/lib/acme/live/{{ acmetool_cert_hostnames[0] }}/privkey"
+ x509_certificate_path_cert: "/var/lib/acme/live/{{ acmetool_cert_hostnames[0] }}/cert"
+ x509_certificate_path_chain: "/var/lib/acme/live/{{ acmetool_cert_hostnames[0] }}/chain"
+ x509_certificate_path_fullchain: "/var/lib/acme/live/{{ acmetool_cert_hostnames[0] }}/fullchain"
+
+- name: setup custom renewal script
+ when: x509_certificate_renewal is defined
+ block:
+ - name: install custom hook script
+ template:
+ src: reload.sh.j2
+ dest: "/etc/acme/hooks/{{ x509_certificate_name }}"
+ mode: 0755
+
+ - name: install acmetool systemd unit snippet
+ when: "'install' in x509_certificate_renewal"
+ copy:
+ dest: "/etc/systemd/system/acmetool.service.d/{{ x509_certificate_name }}.conf"
+ content: |
+ [Service]
+ {% for path in (x509_certificate_renewal.install | map(attribute='dest') | map('dirname') | unique | list) %}
+ ReadWritePaths={{ path }}
+ {% endfor %}
+ notify: reload systemd
+
+ - name: remove acmetool systemd unit snippet
+ when: "'install' not in x509_certificate_renewal"
+ file:
+ path: "/etc/systemd/system/acmetool.service.d/{{ x509_certificate_name }}.conf"
+ state: absent
+ notify: reload systemd
+
+- name: remove custom renewal script
+ when: x509_certificate_renewal is not defined
+ loop:
+ - "/etc/systemd/system/acmetool.service.d/{{ x509_certificate_name }}.conf"
+ - "/etc/acme/hooks/{{ x509_certificate_name }}"
+ file:
+ path: "{{ item }}"
+ state: absent
+ notify: reload systemd
diff --git a/roles/x509/acmetool/cert/prepare/templates/reload.sh.j2 b/roles/x509/acmetool/cert/prepare/templates/reload.sh.j2
new file mode 100644
index 00000000..f4b8259e
--- /dev/null
+++ b/roles/x509/acmetool/cert/prepare/templates/reload.sh.j2
@@ -0,0 +1,31 @@
+#!/bin/sh
+set -e
+EVENT_NAME="$1"
+[ "$EVENT_NAME" = "live-updated" ] || exit 42
+
+MAIN_HOSTNAME="{{ acmetool_cert_hostnames[0] }}"
+
+while read name; do
+ certdir="$ACME_STATE_DIR/live/$name"
+ if [ -z "$name" -o ! -e "$certdir" ]; then
+ continue
+ fi
+ if [ "$name" != "$MAIN_HOSTNAME" ]; then
+ continue
+ fi
+{% if 'install' in x509_certificate_renewal %}
+
+{% for file in x509_certificate_renewal.install %}
+ install{% if 'mode' in file %} -m {{ file.mode }}{% endif %}{% if 'owner' in file %} -o {{ file.owner }}{% endif %}{% if 'owner' in file %} -g {{ file.group }}{% endif %} /dev/null "{{ file.dest }}.new"
+{% for src in file.src %}
+ cat "{{ hostvars[inventory_hostname]['x509_certificate_path_' + src] }}" >> "{{ file.dest }}.new"
+ mv "{{ file.dest }}.new" "{{ file.dest }}"
+{% endfor %}
+{% endfor %}
+{% endif %}
+{% if 'reload' in x509_certificate_renewal %}
+
+ {{ x509_certificate_renewal.reload | trim | indent(2) }}
+{% endif %}
+ break
+done