summaryrefslogtreecommitdiff
path: root/roles/x509/uacme/base
diff options
context:
space:
mode:
authorChristian Pointner <equinox@spreadspace.org>2023-08-22 19:53:49 +0200
committerChristian Pointner <equinox@spreadspace.org>2023-08-22 19:53:49 +0200
commitfc5d0657bfcba53ace230ff2ada64b7fcf9b97a3 (patch)
tree350a8d401e0113bff7d78aee4d8547cddf06b8f7 /roles/x509/uacme/base
parentfix docker for debian bookworm+ (diff)
parentsome more cleanup for acme specific variables (diff)
Merge branch 'topic/uacme'
Diffstat (limited to 'roles/x509/uacme/base')
-rw-r--r--roles/x509/uacme/base/defaults/main.yml2
-rw-r--r--roles/x509/uacme/base/tasks/main.yml29
-rw-r--r--roles/x509/uacme/base/tasks/selfsigned.yml47
-rw-r--r--roles/x509/uacme/base/templates/uacme-reconcile.service.j218
-rw-r--r--roles/x509/uacme/base/templates/uacme-reconcile.sh.j232
-rw-r--r--roles/x509/uacme/base/templates/uacme-reconcile.timer.j210
6 files changed, 87 insertions, 51 deletions
diff --git a/roles/x509/uacme/base/defaults/main.yml b/roles/x509/uacme/base/defaults/main.yml
index 50ac8019..264bc2d9 100644
--- a/roles/x509/uacme/base/defaults/main.yml
+++ b/roles/x509/uacme/base/defaults/main.yml
@@ -4,3 +4,5 @@ uacme_directory_server: "{{ acme_directory_server }}"
### this defaults to '/var/run/acme/acme-challenge'
# uacme_challenge_webroot_path: "/path/to/acme-challenge"
+
+# uacme_eab: <keyid>:base64(<key>)
diff --git a/roles/x509/uacme/base/tasks/main.yml b/roles/x509/uacme/base/tasks/main.yml
index 3d1c8404..3473d541 100644
--- a/roles/x509/uacme/base/tasks/main.yml
+++ b/roles/x509/uacme/base/tasks/main.yml
@@ -7,7 +7,7 @@
state: present
- name: create acme account key
- command: "uacme -c /var/lib/uacme.d -a '{{ uacme_directory_server }}' -y new '{{ uacme_account_email }}'"
+ command: "uacme -c /var/lib/uacme.d -a '{{ uacme_directory_server }}' -y{% if uacme_eab is defined %} -e {{ uacme_eab }}{% endif %} new '{{ uacme_account_email }}'"
args:
creates: /var/lib/uacme.d/private/key.pem
@@ -44,7 +44,28 @@
alias {{ uacme_challenge_webroot_path | default('/var/run/acme/acme-challenge') }}/;
}
-- name: generate selfsigned interim certificate
- include_tasks: selfsigned.yml
+- name: install reconcile script
+ template:
+ src: uacme-reconcile.sh.j2
+ dest: /usr/local/bin/uacme-reconcile.sh
+ mode: 0755
-## TODO: add global automatic refresher?
+- name: install systemd unit for automatic refresh
+ loop:
+ - service
+ - timer
+ template:
+ src: "uacme-reconcile.{{ item }}.j2"
+ dest: "/etc/systemd/system/uacme-reconcile.{{ item }}"
+
+- name: create system unit snippet directory
+ file:
+ path: /etc/systemd/system/uacme-reconcile.service.d/
+ state: directory
+
+- name: make sure systemd timer for automatic refresh is enabled and started
+ systemd:
+ daemon_reload: yes
+ name: uacme-reconcile.timer
+ state: started
+ enabled: yes
diff --git a/roles/x509/uacme/base/tasks/selfsigned.yml b/roles/x509/uacme/base/tasks/selfsigned.yml
deleted file mode 100644
index fff77d42..00000000
--- a/roles/x509/uacme/base/tasks/selfsigned.yml
+++ /dev/null
@@ -1,47 +0,0 @@
----
-- name: create directories for selfsigned interim certificate
- loop:
- - path: private/.self-signed
- mode: "0700"
- - path: .self-signed
- mode: "0755"
- loop_control:
- label: "{{ item.path }}"
- file:
- path: "/var/lib/uacme.d/{{ item.path }}"
- state: directory
- mode: "{{ item.mode }}"
-
-- name: generate private key for selfsigned interim certificate
- openssl_privatekey:
- path: /var/lib/uacme.d/private/.self-signed/key.pem
- mode: 0600
-
-- name: generate csr for selfsigned interim certificate
- community.crypto.openssl_csr_pipe:
- privatekey_path: /var/lib/uacme.d/private/.self-signed/key.pem
- common_name: "{{ ansible_fqdn }}"
- register: selfsigned_interim_cert_req
- changed_when: false
-
-### this is needed because strftime filter in ansible is exceptionally stupid
-### see: https://github.com/ansible/ansible/issues/39835
-- name: get remote date-time 10s ago
- command: date -d '10 seconds ago' -u '+%Y%m%d%H%M%SZ'
- register: remote_datetime_10sago
- changed_when: false
-
-- name: get remote date-time now
- command: date -u '+%Y%m%d%H%M%SZ'
- register: remote_datetime_now
- changed_when: false
-
-- name: generate selfsigned interim certificate
- community.crypto.x509_certificate:
- path: /var/lib/uacme.d/.self-signed/cert.pem
- privatekey_path: /var/lib/uacme.d/private/.self-signed/key.pem
- csr_content: "{{ selfsigned_interim_cert_req.csr }}"
- provider: selfsigned
- ## make sure the certificate is not valid anymore to force uacme to create a new cert
- selfsigned_not_before: "{{ remote_datetime_10sago.stdout }}"
- selfsigned_not_after: "{{ remote_datetime_now.stdout }}"
diff --git a/roles/x509/uacme/base/templates/uacme-reconcile.service.j2 b/roles/x509/uacme/base/templates/uacme-reconcile.service.j2
new file mode 100644
index 00000000..c2fe917a
--- /dev/null
+++ b/roles/x509/uacme/base/templates/uacme-reconcile.service.j2
@@ -0,0 +1,18 @@
+[Unit]
+Description=Reconcile Let's Encrypt certificates using uacme
+
+[Service]
+Type=oneshot
+ExecStart=/usr/local/bin/uacme-reconcile.sh
+TimeoutStartSec=5min
+CapabilityBoundingSet=CAP_CHOWN CAP_NET_BIND_SERVICE
+NoNewPrivileges=yes
+PrivateTmp=yes
+PrivateDevices=yes
+ProtectSystem=strict
+ReadWritePaths=/var/lib/uacme.d {{ uacme_challenge_webroot_path | default('/var/run/acme/acme-challenge') }}
+ProtectHome=yes
+ProtectKernelTunables=yes
+ProtectControlGroups=yes
+RestrictRealtime=yes
+RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
diff --git a/roles/x509/uacme/base/templates/uacme-reconcile.sh.j2 b/roles/x509/uacme/base/templates/uacme-reconcile.sh.j2
new file mode 100644
index 00000000..ea02841d
--- /dev/null
+++ b/roles/x509/uacme/base/templates/uacme-reconcile.sh.j2
@@ -0,0 +1,32 @@
+#!/bin/bash
+
+declare -a csr_files
+if [ -n "$1" ]; then
+ csr_files+=("/var/lib/uacme.d/$1/$1.csr")
+else
+ readarray -d '' csr_files < <(find /var/lib/uacme.d -name "*.csr" -print0)
+fi
+
+export UACME_CHALLENGE_PATH="{{ uacme_challenge_webroot_path | default('/var/run/acme/acme-challenge') }}"
+
+failed=0
+for csr_file in "${csr_files[@]}"; do
+ id=$(basename -s .csr "$csr_file")
+ uacme -c /var/lib/uacme.d -a "{{ uacme_directory_server }}" -h /usr/share/uacme/uacme.sh -n issue "$csr_file"
+ case $? in
+ 0)
+ echo "$id successfully (re)issued."
+ if [ -x "/var/lib/uacme.d/$id/updated.sh" ]; then
+ /var/lib/uacme.d/$id/updated.sh
+ fi
+ ;;
+ 1)
+ echo "$id not updated."
+ ;;
+ *)
+ failed=1
+ ;;
+ esac
+done
+
+exit $failed
diff --git a/roles/x509/uacme/base/templates/uacme-reconcile.timer.j2 b/roles/x509/uacme/base/templates/uacme-reconcile.timer.j2
new file mode 100644
index 00000000..6d37a162
--- /dev/null
+++ b/roles/x509/uacme/base/templates/uacme-reconcile.timer.j2
@@ -0,0 +1,10 @@
+[Unit]
+Description=Reconcile Let's Encrypt certificates using uacme
+
+[Timer]
+OnCalendar=*-*-* 00,12:00:00
+RandomizedDelaySec=1h
+Persistent=yes
+
+[Install]
+WantedBy=timers.target