summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dan/sk-testvm.yml59
-rw-r--r--roles/nginx/vhost/templates/generic.conf.j28
-rw-r--r--roles/x509/selfsigned/cert/prepare/tasks/main.yml2
-rw-r--r--roles/x509/uacme/base/defaults/main.yml2
-rw-r--r--roles/x509/uacme/base/tasks/main.yml11
-rw-r--r--roles/x509/uacme/base/tasks/selfsigned.yml47
-rw-r--r--roles/x509/uacme/base/templates/uacme-reconcile.sh.j232
-rw-r--r--roles/x509/uacme/cert/finalize/defaults/main.yml3
-rw-r--r--roles/x509/uacme/cert/finalize/tasks/main.yml5
-rw-r--r--roles/x509/uacme/cert/meta/main.yml4
-rw-r--r--roles/x509/uacme/cert/prepare/defaults/main.yml15
-rw-r--r--roles/x509/uacme/cert/prepare/tasks/main.yml88
12 files changed, 191 insertions, 85 deletions
diff --git a/dan/sk-testvm.yml b/dan/sk-testvm.yml
index de8e66ba..39835fad 100644
--- a/dan/sk-testvm.yml
+++ b/dan/sk-testvm.yml
@@ -11,9 +11,11 @@
- name: Payload Setup
hosts: sk-testvm
vars:
- # cert_provider: acmetool
+ acme_client: uacme
+ # acme_client: acmetool
+ cert_provider: "{{ acme_client }}"
# cert_provider: static
- cert_provider: selfsigned
+ # cert_provider: selfsigned
roles:
- role: "x509/{{ cert_provider }}/base"
- role: nginx/base
@@ -57,20 +59,19 @@
root: /var/www/default
index: index.html
# static_cert_config: "{{ static_cert_config__default }}"
- selfsigned_cert_config:
- cert:
- organization_name: "elev8"
- organizational_unit_name: "ansible"
- key_usage:
- - digitalSignature
- - keyAgreement
- key_usage_critical: yes
- extended_key_usage:
- - serverAuth
- extended_key_usage_critical: yes
- create_subject_key_identifier: yes
- not_after: +1000w
-
+ # selfsigned_cert_config:
+ # cert:
+ # organization_name: "elev8"
+ # organizational_unit_name: "ansible"
+ # key_usage:
+ # - digitalSignature
+ # - keyAgreement
+ # key_usage_critical: yes
+ # extended_key_usage:
+ # - serverAuth
+ # extended_key_usage_critical: yes
+ # create_subject_key_identifier: yes
+ # not_after: +1000w
include_role:
name: nginx/vhost
@@ -108,18 +109,18 @@
root: /var/www/test
index: index.html
# static_cert_config: "{{ static_cert_config__test }}"
- selfsigned_cert_config:
- cert:
- organization_name: "spreadspace"
- organizational_unit_name: "ansible"
- key_usage:
- - digitalSignature
- - keyAgreement
- key_usage_critical: yes
- extended_key_usage:
- - serverAuth
- extended_key_usage_critical: yes
- create_subject_key_identifier: yes
- not_after: +100w
+ # selfsigned_cert_config:
+ # cert:
+ # organization_name: "spreadspace"
+ # organizational_unit_name: "ansible"
+ # key_usage:
+ # - digitalSignature
+ # - keyAgreement
+ # key_usage_critical: yes
+ # extended_key_usage:
+ # - serverAuth
+ # extended_key_usage_critical: yes
+ # create_subject_key_identifier: yes
+ # not_after: +100w
include_role:
name: nginx/vhost
diff --git a/roles/nginx/vhost/templates/generic.conf.j2 b/roles/nginx/vhost/templates/generic.conf.j2
index 64569a5e..dae84a2f 100644
--- a/roles/nginx/vhost/templates/generic.conf.j2
+++ b/roles/nginx/vhost/templates/generic.conf.j2
@@ -13,8 +13,8 @@ server {
{% endif %}
{% if 'tls' in nginx_vhost %}
-{% if nginx_vhost.tls.certificate_provider == 'acmetool' %}
- include snippets/acmetool.conf;
+{% if nginx_vhost.tls.certificate_provider == 'acmetool' or nginx_vhost.tls.certificate_provider == 'uacme' %}
+ include snippets/{{ nginx_vhost.tls.certificate_provider }}.conf;
{% endif %}
location / {
@@ -36,8 +36,8 @@ server {
{% endif %}
{% endif %}
-{% if nginx_vhost.tls.certificate_provider == 'acmetool' %}
- include snippets/acmetool.conf;
+{% if nginx_vhost.tls.certificate_provider == 'acmetool' or nginx_vhost.tls.certificate_provider == 'uacme' %}
+ include snippets/{{ nginx_vhost.tls.certificate_provider }}.conf;
{% endif %}
include snippets/tls{% if 'variant' in nginx_vhost.tls %}-{{ nginx_vhost.tls.variant }}{% endif %}.conf;
ssl_certificate {{ x509_certificate_path_fullchain }};
diff --git a/roles/x509/selfsigned/cert/prepare/tasks/main.yml b/roles/x509/selfsigned/cert/prepare/tasks/main.yml
index c089d420..1af6ef5e 100644
--- a/roles/x509/selfsigned/cert/prepare/tasks/main.yml
+++ b/roles/x509/selfsigned/cert/prepare/tasks/main.yml
@@ -25,7 +25,7 @@
- name: generate csr for selfsigned certificate
community.crypto.openssl_csr:
path: "{{ selfsigned_cert_path }}/{{ selfsigned_cert_name }}-csr.pem"
- mode: "{{ selfsigned_cert_config.cert.mode | default('0600') }}"
+ mode: "{{ selfsigned_cert_config.cert.mode | default('0644') }}"
owner: "{{ selfsigned_cert_config.cert.owner | default(omit) }}"
group: "{{ selfsigned_cert_config.cert.group | default(omit) }}"
privatekey_path: "{{ selfsigned_cert_path }}/{{ selfsigned_cert_name }}-key.pem"
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..9d67e0e7 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,10 @@
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?
+## TODO: add systemd units for automatic refreshing
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.sh.j2 b/roles/x509/uacme/base/templates/uacme-reconcile.sh.j2
new file mode 100644
index 00000000..73a7f4a3
--- /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."
+ awk '{if(length($0) > 0) print} /-----END CERTIFICATE-----/ { exit }' "/var/lib/uacme.d/$id/$id-cert.pem" > "/var/lib/uacme.d/$id/crt.pem"
+ awk '(show==1) {if(length($0) > 0) print} /-----END CERTIFICATE-----/ { show=1 }' "/var/lib/uacme.d/$id/$id-cert.pem" > "/var/lib/uacme.d/$id/chain.pem"
+ ## TODO: reload services
+ ;;
+ 1)
+ echo "$id not updated."
+ ;;
+ *)
+ failed=1
+ ;;
+ esac
+done
+
+exit $failed
diff --git a/roles/x509/uacme/cert/finalize/defaults/main.yml b/roles/x509/uacme/cert/finalize/defaults/main.yml
new file mode 100644
index 00000000..611dc6fc
--- /dev/null
+++ b/roles/x509/uacme/cert/finalize/defaults/main.yml
@@ -0,0 +1,3 @@
+---
+uacme_cert_hostnames: "{{ x509_certificate_hostnames }}"
+uacme_cert_name: "{{ x509_certificate_name | default(uacme_cert_hostnames[0]) }}"
diff --git a/roles/x509/uacme/cert/finalize/tasks/main.yml b/roles/x509/uacme/cert/finalize/tasks/main.yml
new file mode 100644
index 00000000..6578c418
--- /dev/null
+++ b/roles/x509/uacme/cert/finalize/tasks/main.yml
@@ -0,0 +1,5 @@
+---
+- name: running uacme issue command
+ command: "/usr/local/bin/uacme-reconcile.sh '{{ uacme_cert_name }}'"
+ register: uacme_reconcile
+ changed_when: "'not updated.' not in uacme_reconcile.stdout"
diff --git a/roles/x509/uacme/cert/meta/main.yml b/roles/x509/uacme/cert/meta/main.yml
new file mode 100644
index 00000000..5106342c
--- /dev/null
+++ b/roles/x509/uacme/cert/meta/main.yml
@@ -0,0 +1,4 @@
+---
+dependencies:
+ - role: x509/uacme/cert/prepare
+ - role: x509/uacme/cert/finalize
diff --git a/roles/x509/uacme/cert/prepare/defaults/main.yml b/roles/x509/uacme/cert/prepare/defaults/main.yml
new file mode 100644
index 00000000..b15c1e44
--- /dev/null
+++ b/roles/x509/uacme/cert/prepare/defaults/main.yml
@@ -0,0 +1,15 @@
+---
+uacme_cert_hostnames: "{{ x509_certificate_hostnames }}"
+uacme_cert_name: "{{ x509_certificate_name | default(uacme_cert_hostnames[0]) }}"
+
+# uacme_cert_config:
+# key:
+# mode: "0640"
+# owner: root
+# group: www-data
+# type: RSA
+# size: 4096
+# cert:
+# mode: "0644"
+# owner: root
+# group: www-data
diff --git a/roles/x509/uacme/cert/prepare/tasks/main.yml b/roles/x509/uacme/cert/prepare/tasks/main.yml
new file mode 100644
index 00000000..06b9f146
--- /dev/null
+++ b/roles/x509/uacme/cert/prepare/tasks/main.yml
@@ -0,0 +1,88 @@
+---
+- name: create directory for uacme-controlled certificate
+ file:
+ path: "/var/lib/uacme.d/{{ uacme_cert_name }}"
+ state: directory
+
+- name: generate key for uacme-controlled certificate
+ openssl_privatekey:
+ path: "/var/lib/uacme.d/{{ uacme_cert_name }}/key.pem"
+ mode: "{{ uacme_cert_config.key.mode | default('0600') }}"
+ owner: "{{ uacme_cert_config.key.owner | default(omit) }}"
+ group: "{{ uacme_cert_config.key.group | default(omit) }}"
+ type: "{{ uacme_cert_config.key.type | default(omit) }}"
+ size: "{{ uacme_cert_config.key.size | default(omit) }}"
+ notify: "{{ x509_notify_on_change | default(omit) }}"
+
+- name: generate csr for uacme-controlled certificate
+ community.crypto.openssl_csr:
+ path: "/var/lib/uacme.d/{{ uacme_cert_name }}/{{ uacme_cert_name }}.csr"
+ mode: "{{ uacme_cert_config.cert.mode | default('0644') }}"
+ owner: "{{ uacme_cert_config.cert.owner | default(omit) }}"
+ group: "{{ uacme_cert_config.cert.group | default(omit) }}"
+ privatekey_path: "/var/lib/uacme.d/{{ uacme_cert_name }}/key.pem"
+ common_name: "{{ uacme_cert_hostnames[0] }}"
+ subject_alt_name: "{{ ['DNS:'] | product(uacme_cert_hostnames) | map('join') | list }}"
+ subject_alt_name_critical: yes
+ use_common_name_for_san: no
+
+- name: test if uacme-controlled certificate already exists
+ stat:
+ path: "/var/lib/uacme.d/{{ uacme_cert_name }}/{{ uacme_cert_name }}-cert.pem"
+ register: uacme_cert_file
+
+- name: generate selfsigned interim certificate
+ when: not uacme_cert_file.stat.exists
+ block:
+ ### 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/{{ uacme_cert_name }}/{{ uacme_cert_name }}-cert.pem"
+ mode: "{{ uacme_cert_config.cert.mode | default('0644') }}"
+ owner: "{{ uacme_cert_config.cert.owner | default(omit) }}"
+ group: "{{ uacme_cert_config.cert.group | default(omit) }}"
+ privatekey_path: "/var/lib/uacme.d/{{ uacme_cert_name }}/key.pem"
+ csr_path: "/var/lib/uacme.d/{{ uacme_cert_name }}/{{ uacme_cert_name }}.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 }}"
+ return_content: yes
+ register: uacme_cert_selfsigned
+ notify: "{{ x509_notify_on_change | default(omit) }}"
+
+ - name: make sure cert-only file exists
+ copy:
+ content: "{{ uacme_cert_selfsigned.certificate }}"
+ dest: "/var/lib/uacme.d/{{ uacme_cert_name }}/crt.pem"
+ mode: "{{ uacme_cert_config.cert.mode | default('0644') }}"
+ owner: "{{ uacme_cert_config.cert.owner | default(omit) }}"
+ group: "{{ uacme_cert_config.cert.group | default(omit) }}"
+ notify: "{{ x509_notify_on_change | default(omit) }}"
+
+ - name: make sure the chain file exists
+ copy:
+ content: ""
+ dest: "/var/lib/uacme.d/{{ uacme_cert_name }}/chain.pem"
+ mode: "{{ uacme_cert_config.cert.mode | default('0644') }}"
+ owner: "{{ uacme_cert_config.cert.owner | default(omit) }}"
+ group: "{{ uacme_cert_config.cert.group | default(omit) }}"
+ notify: "{{ x509_notify_on_change | default(omit) }}"
+
+- name: export paths to certificate files
+ set_fact:
+ x509_certificate_path_key: "/var/lib/uacme.d/{{ uacme_cert_name }}/key.pem"
+ x509_certificate_path_cert: "/var/lib/uacme.d/{{ uacme_cert_name }}/crt.pem"
+ x509_certificate_path_chain: "/var/lib/uacme.d/{{ uacme_cert_name }}/chain.pem"
+ x509_certificate_path_fullchain: "/var/lib/uacme.d/{{ uacme_cert_name }}/{{ uacme_cert_name }}-cert.pem"