From 5b08c3fb96e54e0ae8ae1d650658b27dcdfd78de Mon Sep 17 00:00:00 2001 From: Christian Pointner Date: Tue, 8 Aug 2023 00:42:56 +0200 Subject: make acmetool cert role more generic (WIP - needs more testing) --- roles/x509/acmetool/cert/defaults/main.yml | 2 -- .../acmetool/cert/filter_plugins/acme_certs.py | 24 ------------- .../x509/acmetool/cert/finalize/defaults/main.yml | 2 ++ .../x509/acmetool/cert/finalize/handlers/main.yml | 6 ++++ roles/x509/acmetool/cert/finalize/tasks/main.yml | 10 ++++++ roles/x509/acmetool/cert/handlers/main.yml | 6 ---- roles/x509/acmetool/cert/meta/main.yml | 3 ++ .../cert/prepare/filter_plugins/acme_certs.py | 24 +++++++++++++ roles/x509/acmetool/cert/prepare/tasks/main.yml | 41 ++++++++++++++++++++++ roles/x509/acmetool/cert/tasks/main.yml | 10 ------ 10 files changed, 86 insertions(+), 42 deletions(-) delete mode 100644 roles/x509/acmetool/cert/defaults/main.yml delete mode 100644 roles/x509/acmetool/cert/filter_plugins/acme_certs.py create mode 100644 roles/x509/acmetool/cert/finalize/defaults/main.yml create mode 100644 roles/x509/acmetool/cert/finalize/handlers/main.yml create mode 100644 roles/x509/acmetool/cert/finalize/tasks/main.yml delete mode 100644 roles/x509/acmetool/cert/handlers/main.yml create mode 100644 roles/x509/acmetool/cert/meta/main.yml create mode 100644 roles/x509/acmetool/cert/prepare/filter_plugins/acme_certs.py create mode 100644 roles/x509/acmetool/cert/prepare/tasks/main.yml delete mode 100644 roles/x509/acmetool/cert/tasks/main.yml (limited to 'roles/x509') diff --git a/roles/x509/acmetool/cert/defaults/main.yml b/roles/x509/acmetool/cert/defaults/main.yml deleted file mode 100644 index ab0afaa3..00000000 --- a/roles/x509/acmetool/cert/defaults/main.yml +++ /dev/null @@ -1,2 +0,0 @@ ---- -acmetool_reconcile_disabled: false diff --git a/roles/x509/acmetool/cert/filter_plugins/acme_certs.py b/roles/x509/acmetool/cert/filter_plugins/acme_certs.py deleted file mode 100644 index 179f71e9..00000000 --- a/roles/x509/acmetool/cert/filter_plugins/acme_certs.py +++ /dev/null @@ -1,24 +0,0 @@ -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/finalize/defaults/main.yml b/roles/x509/acmetool/cert/finalize/defaults/main.yml new file mode 100644 index 00000000..ab0afaa3 --- /dev/null +++ b/roles/x509/acmetool/cert/finalize/defaults/main.yml @@ -0,0 +1,2 @@ +--- +acmetool_reconcile_disabled: false diff --git a/roles/x509/acmetool/cert/finalize/handlers/main.yml b/roles/x509/acmetool/cert/finalize/handlers/main.yml new file mode 100644 index 00000000..a7fc43ed --- /dev/null +++ b/roles/x509/acmetool/cert/finalize/handlers/main.yml @@ -0,0 +1,6 @@ +--- +- name: reconcile acmetool + when: not acmetool_reconcile_disabled + systemd: + name: acmetool.service + state: started diff --git a/roles/x509/acmetool/cert/finalize/tasks/main.yml b/roles/x509/acmetool/cert/finalize/tasks/main.yml new file mode 100644 index 00000000..91bf5157 --- /dev/null +++ b/roles/x509/acmetool/cert/finalize/tasks/main.yml @@ -0,0 +1,10 @@ +--- +- name: add acmetool desired file + vars: + acmetool_cert_satisfy: + satisfy: + names: "{{ acmetool_cert_hostnames }}" + copy: + content: "{{ acmetool_cert_config | default({}) | combine(acmetool_cert_satisfy) | to_nice_yaml }}" + dest: "/var/lib/acme/desired/{{ acmetool_cert_name | default(acmetool_cert_hostnames[0]) }}" + notify: reconcile acmetool diff --git a/roles/x509/acmetool/cert/handlers/main.yml b/roles/x509/acmetool/cert/handlers/main.yml deleted file mode 100644 index a7fc43ed..00000000 --- a/roles/x509/acmetool/cert/handlers/main.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -- name: reconcile acmetool - when: not acmetool_reconcile_disabled - systemd: - name: acmetool.service - state: started diff --git a/roles/x509/acmetool/cert/meta/main.yml b/roles/x509/acmetool/cert/meta/main.yml new file mode 100644 index 00000000..8e6ac88d --- /dev/null +++ b/roles/x509/acmetool/cert/meta/main.yml @@ -0,0 +1,3 @@ +dependencies: + - role: x509/acmetool/cert/prepare + - role: x509/acmetool/cert/finalize 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/tasks/main.yml b/roles/x509/acmetool/cert/prepare/tasks/main.yml new file mode 100644 index 00000000..1f7dc724 --- /dev/null +++ b/roles/x509/acmetool/cert/prepare/tasks/main.yml @@ -0,0 +1,41 @@ +--- +- 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 + +- name: export paths to certificate files + set_fact: + x509_certificate_path_key: "/var/lib/acme/live/{{ acmetool_cert_hostnames[0] }}/privkey" + x509_certificate_path_fullchain: "/var/lib/acme/live/{{ acmetool_cert_hostnames[0] }}/fullchain" + 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" diff --git a/roles/x509/acmetool/cert/tasks/main.yml b/roles/x509/acmetool/cert/tasks/main.yml deleted file mode 100644 index 09980dad..00000000 --- a/roles/x509/acmetool/cert/tasks/main.yml +++ /dev/null @@ -1,10 +0,0 @@ ---- -- name: add acmetool desired file - vars: - acmetool_cert_satisfy: - satisfy: - names: "{{ acmetool_cert_hostnames | default([acmetool_cert_name]) }}" - copy: - content: "{{ acmetool_cert_config | default({}) | combine(acmetool_cert_satisfy) | to_nice_yaml }}" - dest: "/var/lib/acme/desired/{{ acmetool_cert_name }}" - notify: reconcile acmetool -- cgit v1.2.3 From bc98352d3e331003db625be96139b3c1f95f63b2 Mon Sep 17 00:00:00 2001 From: Christian Pointner Date: Wed, 9 Aug 2023 14:38:23 +0200 Subject: nginx/vhost: major change in certifcate/tls handling (WIP) --- chaos-at-home/ch-http-proxy.yml | 13 ++++++++----- chaos-at-home/ch-mimas.yml | 3 ++- chaos-at-home/ch-pan.yml | 3 ++- chaos-at-home/r3-0x10.yml | 3 ++- dan/sk-testvm.yml | 13 +++++++++---- inventory/group_vars/all/vars.yml | 2 ++ roles/apps/bluespice/tasks/main.yml | 3 ++- roles/apps/collabora/code/tasks/main.yml | 3 ++- .../collabora/code/templates/nginx-vhost.conf.j2 | 4 ++-- roles/apps/coturn/tasks/main.yml | 9 ++++++++- roles/apps/etherpad-lite/tasks/main.yml | 3 ++- .../etherpad-lite/templates/nginx-vhost.conf.j2 | 4 ++-- roles/apps/jitsi/meet/tasks/main.yml | 3 ++- roles/apps/keycloak/tasks/main.yml | 3 ++- roles/apps/mumble/tasks/main.yml | 6 ++++++ roles/apps/nextcloud/tasks/main.yml | 3 ++- roles/apps/onlyoffice/tasks/main.yml | 3 ++- roles/apps/pigallery2/tasks/main.yml | 3 ++- roles/apps/wikijs/tasks/main.yml | 3 ++- roles/elevate/liquidtruth/tasks/main.yml | 3 ++- roles/elevate/media/tasks/nextcloud-app.yml | 3 ++- roles/gitolite/http/tasks/main.yml | 3 ++- roles/gitolite/http/templates/nginx-vhost.conf.j2 | 4 ++-- roles/monitoring/landingpage/defaults/main.yml | 3 ++- roles/monitoring/landingpage/tasks/main.yml | 3 ++- .../prometheus/exporter/base/tasks/main.yml | 10 +++++++--- roles/nginx/vhost/defaults/main.yml | 8 ++++++-- roles/nginx/vhost/tasks/main.yml | 21 +++++++++++---------- roles/nginx/vhost/templates/generic.conf.j2 | 10 ++++++++-- roles/x509/acmetool/cert/finalize/defaults/main.yml | 3 +++ roles/x509/acmetool/cert/finalize/tasks/main.yml | 2 +- roles/x509/acmetool/cert/prepare/defaults/main.yml | 2 ++ spreadspace/glt-stream.yml | 3 ++- spreadspace/sgg-icecast.yml | 6 ++++-- 34 files changed, 117 insertions(+), 54 deletions(-) create mode 100644 roles/x509/acmetool/cert/prepare/defaults/main.yml (limited to 'roles/x509') diff --git a/chaos-at-home/ch-http-proxy.yml b/chaos-at-home/ch-http-proxy.yml index 67e3521a..24fd6f92 100644 --- a/chaos-at-home/ch-http-proxy.yml +++ b/chaos-at-home/ch-http-proxy.yml @@ -47,7 +47,8 @@ default: yes name: web template: generic - acme: yes + tls: + certificate_provider: acmetool hostnames: - web.chaos-at-home.org locations: @@ -112,7 +113,8 @@ nginx_vhost: name: passwd template: generic - acme: yes + tls: + certificate_provider: acmetool hostnames: - passwd.chaos-at-home.org locations: @@ -179,7 +181,8 @@ nginx_vhost: name: webmail template: generic - acme: yes + tls: + certificate_provider: acmetool hostnames: - webmail.chaos-at-home.org locations: @@ -204,7 +207,8 @@ nginx_vhost: name: webdav template: generic - acme: yes + tls: + certificate_provider: acmetool hostnames: - webdav.chaos-at-home.org locations: @@ -228,7 +232,6 @@ vars: nginx_vhost: name: imap - acme: no content: | server { listen 80; diff --git a/chaos-at-home/ch-mimas.yml b/chaos-at-home/ch-mimas.yml index 2743644c..d486023b 100644 --- a/chaos-at-home/ch-mimas.yml +++ b/chaos-at-home/ch-mimas.yml @@ -44,7 +44,8 @@ nginx_vhost: name: pub template: generic - acme: yes + tls: + certificate_provider: "{{ acme_client }}" hostnames: - pub.chaos-at-home.org locations: diff --git a/chaos-at-home/ch-pan.yml b/chaos-at-home/ch-pan.yml index 56a4f30a..eea3f287 100644 --- a/chaos-at-home/ch-pan.yml +++ b/chaos-at-home/ch-pan.yml @@ -43,7 +43,8 @@ template: generic hostnames: - dyn.schaaas.at - acme: yes + tls: + certificate_provider: "{{ acme_client }}" extra_directives: | access_log /var/log/nginx/dyn-schaaas_access.log; error_log /var/log/nginx/dyn-schaaas_error.log; diff --git a/chaos-at-home/r3-0x10.yml b/chaos-at-home/r3-0x10.yml index c613f373..5e30abec 100644 --- a/chaos-at-home/r3-0x10.yml +++ b/chaos-at-home/r3-0x10.yml @@ -33,7 +33,8 @@ default: yes name: 0x10 template: generic - acme: yes + tls: + certificate_provider: "{{ acme_client }}" hostnames: - 0x10.r3.at - 0x10.realraum.at diff --git a/dan/sk-testvm.yml b/dan/sk-testvm.yml index 658b5ac4..c7aaf754 100644 --- a/dan/sk-testvm.yml +++ b/dan/sk-testvm.yml @@ -10,9 +10,10 @@ - name: Payload Setup hosts: sk-testvm + vars: + acme_client: acmetool roles: - #- role: x509/acmetool/base - #- role: x509/uacme/base + - role: "x509/{{ acme_client }}/base" - role: nginx/base post_tasks: - name: make sure document root directories exist @@ -44,7 +45,9 @@ default: yes name: nosuchsite template: generic - #acme: yes + tls: + certificate_provider: "{{ acme_client }}" + hsts: no hostnames: - testvm.elev8.at locations: @@ -75,7 +78,9 @@ nginx_vhost: name: test template: generic - #acme: yes + tls: + certificate_provider: "{{ acme_client }}" + hsts: no hostnames: - test.spreadspace.org - test.spreadspace.com diff --git a/inventory/group_vars/all/vars.yml b/inventory/group_vars/all/vars.yml index f72f71ef..09eba1cf 100644 --- a/inventory/group_vars/all/vars.yml +++ b/inventory/group_vars/all/vars.yml @@ -129,3 +129,5 @@ acme_directory_server: "{{ acme_directory_server_le_staging_v2 }}" ## at least acmetool can't be used to change this after the account has been created (aka after the first run) ## and it's not recommended to keep this empty so we don't define it here to force the user to define it # acme_account_email: + +acme_client: acmetool diff --git a/roles/apps/bluespice/tasks/main.yml b/roles/apps/bluespice/tasks/main.yml index 899d1e1d..49ef2418 100644 --- a/roles/apps/bluespice/tasks/main.yml +++ b/roles/apps/bluespice/tasks/main.yml @@ -49,7 +49,8 @@ nginx_vhost: name: "bluespice-{{ item.key }}" template: generic - acme: true + tls: + certificate_provider: "{{ acme_client }}" hostnames: - "{{ item.value.hostname }}" locations: diff --git a/roles/apps/collabora/code/tasks/main.yml b/roles/apps/collabora/code/tasks/main.yml index db28bb65..8f4acc76 100644 --- a/roles/apps/collabora/code/tasks/main.yml +++ b/roles/apps/collabora/code/tasks/main.yml @@ -53,7 +53,8 @@ nginx_vhost: name: "collabora-code-{{ item.key }}" content: "{{ lookup('template', 'nginx-vhost.conf.j2') }}" - acme: true + tls: + certificate_provider: "{{ acme_client }}" hostnames: - "{{ item.value.hostname }}" include_role: diff --git a/roles/apps/collabora/code/templates/nginx-vhost.conf.j2 b/roles/apps/collabora/code/templates/nginx-vhost.conf.j2 index 04358976..8dd67fb7 100644 --- a/roles/apps/collabora/code/templates/nginx-vhost.conf.j2 +++ b/roles/apps/collabora/code/templates/nginx-vhost.conf.j2 @@ -3,7 +3,7 @@ server { listen [::]:80; server_name {{ item.value.hostname }}; - include snippets/acmetool.conf; + include snippets/{{ acme_client }}.conf; location / { return 301 https://$host$request_uri; @@ -15,7 +15,7 @@ server { listen [::]:443 ssl http2; server_name {{ item.value.hostname }}; - include snippets/acmetool.conf; + include snippets/{{ acme_client }}.conf; include snippets/tls.conf; ssl_certificate {{ x509_certificate_path_fullchain }}; ssl_certificate_key {{ x509_certificate_path_key }}; diff --git a/roles/apps/coturn/tasks/main.yml b/roles/apps/coturn/tasks/main.yml index 42ccd2b3..bab53d99 100644 --- a/roles/apps/coturn/tasks/main.yml +++ b/roles/apps/coturn/tasks/main.yml @@ -1,4 +1,10 @@ --- +- name: check if acme_client is set to acmetool + assert: + msg: "this role currently only works with acmetool" + that: + - acme_client == "acmetool" + - name: add group for coturn group: name: coturn @@ -64,7 +70,8 @@ nginx_vhost: name: "coturn-{{ coturn_realm }}" content: "{{ lookup('template', 'nginx-vhost.conf.j2') }}" - acme: true + tls: + certificate_provider: acmetool hostnames: "{{ coturn_hostnames }}" include_role: name: nginx/vhost diff --git a/roles/apps/etherpad-lite/tasks/main.yml b/roles/apps/etherpad-lite/tasks/main.yml index 072a6c09..495a0387 100644 --- a/roles/apps/etherpad-lite/tasks/main.yml +++ b/roles/apps/etherpad-lite/tasks/main.yml @@ -114,7 +114,8 @@ nginx_vhost: name: "etherpad-lite-{{ item.key }}" content: "{{ lookup('template', 'nginx-vhost.conf.j2') }}" - acme: true + tls: + certificate_provider: "{{ acme_client }}" hostnames: "{{ item.value.hostnames }}" include_role: name: nginx/vhost diff --git a/roles/apps/etherpad-lite/templates/nginx-vhost.conf.j2 b/roles/apps/etherpad-lite/templates/nginx-vhost.conf.j2 index 0ac9d0f0..c572a7eb 100644 --- a/roles/apps/etherpad-lite/templates/nginx-vhost.conf.j2 +++ b/roles/apps/etherpad-lite/templates/nginx-vhost.conf.j2 @@ -3,7 +3,7 @@ server { listen [::]:80; server_name {{ item.value.hostnames | join(' ') }}; - include snippets/acmetool.conf; + include snippets/{{ acme_client }}.conf; location / { return 301 https://$host$request_uri; @@ -15,7 +15,7 @@ server { listen [::]:443 ssl http2; server_name {{ item.value.hostnames | join(' ') }}; - include snippets/acmetool.conf; + include snippets/{{ acme_client }}.conf; include snippets/tls.conf; ssl_certificate {{ x509_certificate_path_fullchain }}; ssl_certificate_key {{ x509_certificate_path_key }}; diff --git a/roles/apps/jitsi/meet/tasks/main.yml b/roles/apps/jitsi/meet/tasks/main.yml index eff8232b..1d55fc78 100644 --- a/roles/apps/jitsi/meet/tasks/main.yml +++ b/roles/apps/jitsi/meet/tasks/main.yml @@ -151,7 +151,8 @@ nginx_vhost: name: "jitsi-meet-{{ jitsi_meet_inst_name }}" template: generic - acme: true + tls: + certificate_provider: "{{ acme_client }}" hostnames: - "{{ jitsi_meet_hostname }}" locations: "{{ nginx_vhost_locations_base | combine(nginx_vhost_locations_streamui) }}" diff --git a/roles/apps/keycloak/tasks/main.yml b/roles/apps/keycloak/tasks/main.yml index 68806458..c3e93666 100644 --- a/roles/apps/keycloak/tasks/main.yml +++ b/roles/apps/keycloak/tasks/main.yml @@ -96,7 +96,8 @@ nginx_vhost: name: "keycloak-{{ item.key }}" template: generic - acme: true + tls: + certificate_provider: "{{ acme_client }}" hostnames: - "{{ item.value.hostname }}" locations: diff --git a/roles/apps/mumble/tasks/main.yml b/roles/apps/mumble/tasks/main.yml index 33331dca..92659b66 100644 --- a/roles/apps/mumble/tasks/main.yml +++ b/roles/apps/mumble/tasks/main.yml @@ -1,4 +1,10 @@ --- +- name: check if acme_client is set to acmetool + assert: + msg: "this role currently only works with acmetool" + that: + - acme_client == "acmetool" + - name: add group for mumble group: name: mumble diff --git a/roles/apps/nextcloud/tasks/main.yml b/roles/apps/nextcloud/tasks/main.yml index 29ab9c39..c9a9061c 100644 --- a/roles/apps/nextcloud/tasks/main.yml +++ b/roles/apps/nextcloud/tasks/main.yml @@ -160,7 +160,8 @@ nginx_vhost: name: "nextcloud-{{ item.key }}" template: generic - acme: true + tls: + certificate_provider: "{{ acme_client }}" hostnames: "{{ item.value.hostnames }}" locations: '/': diff --git a/roles/apps/onlyoffice/tasks/main.yml b/roles/apps/onlyoffice/tasks/main.yml index 957d8afe..960e811b 100644 --- a/roles/apps/onlyoffice/tasks/main.yml +++ b/roles/apps/onlyoffice/tasks/main.yml @@ -140,7 +140,8 @@ nginx_vhost: name: "onlyoffice-{{ item.key }}" template: generic - acme: true + tls: + certificate_provider: "{{ acme_client }}" hostnames: - "{{ item.value.hostname }}" locations: diff --git a/roles/apps/pigallery2/tasks/main.yml b/roles/apps/pigallery2/tasks/main.yml index b8b0166d..2a758da1 100644 --- a/roles/apps/pigallery2/tasks/main.yml +++ b/roles/apps/pigallery2/tasks/main.yml @@ -67,7 +67,8 @@ nginx_vhost: name: "pigallery2-{{ item.key }}" template: generic - acme: true + tls: + certificate_provider: "{{ acme_client }}" hostnames: - "{{ item.value.hostname }}" locations: diff --git a/roles/apps/wikijs/tasks/main.yml b/roles/apps/wikijs/tasks/main.yml index e2b03d24..10b0aa54 100644 --- a/roles/apps/wikijs/tasks/main.yml +++ b/roles/apps/wikijs/tasks/main.yml @@ -73,7 +73,8 @@ nginx_vhost: name: "wikijs-{{ item.key }}" template: generic - acme: true + tls: + certificate_provider: "{{ acme_client }}" hostnames: - "{{ item.value.hostname }}" locations: diff --git a/roles/elevate/liquidtruth/tasks/main.yml b/roles/elevate/liquidtruth/tasks/main.yml index 837d2fd0..aa73adb5 100644 --- a/roles/elevate/liquidtruth/tasks/main.yml +++ b/roles/elevate/liquidtruth/tasks/main.yml @@ -18,7 +18,8 @@ nginx_vhost: name: liquidtruth template: generic - acme: true + tls: + certificate_provider: "{{ acme_client }}" hostnames: "{{ liquidtruth_hostnames }}" locations: '/': diff --git a/roles/elevate/media/tasks/nextcloud-app.yml b/roles/elevate/media/tasks/nextcloud-app.yml index 2e533ec6..42a351e4 100644 --- a/roles/elevate/media/tasks/nextcloud-app.yml +++ b/roles/elevate/media/tasks/nextcloud-app.yml @@ -102,7 +102,8 @@ nginx_vhost: name: "nextcloud-{{ elevate_media_nextcloud_instance_name }}" template: generic - acme: true + tls: + certificate_provider: "{{ acme_client }}" hostnames: "{{ elevate_media_nextcloud_instance.hostnames }}" locations: '/': diff --git a/roles/gitolite/http/tasks/main.yml b/roles/gitolite/http/tasks/main.yml index a3055902..1006283a 100644 --- a/roles/gitolite/http/tasks/main.yml +++ b/roles/gitolite/http/tasks/main.yml @@ -54,7 +54,8 @@ vars: nginx_vhost: name: "gitolite-{{ gitolite_instance }}" - acme: true + tls: + certificate_provider: "{{ acme_client }}" hostnames: "{{ gitolite_instances[gitolite_instance].http.hostnames }}" content: "{{ lookup('template', 'nginx-vhost.conf.j2') }}" include_role: diff --git a/roles/gitolite/http/templates/nginx-vhost.conf.j2 b/roles/gitolite/http/templates/nginx-vhost.conf.j2 index 3386d956..f656d48f 100644 --- a/roles/gitolite/http/templates/nginx-vhost.conf.j2 +++ b/roles/gitolite/http/templates/nginx-vhost.conf.j2 @@ -6,7 +6,7 @@ access_log /var/log/nginx/git-{{ gitolite_instance }}_access.log; error_log /var/log/nginx/git-{{ gitolite_instance }}_error.log; - include snippets/acmetool.conf; + include snippets/{{ acme_client }}.conf; location / { return 301 https://$host$request_uri; @@ -21,7 +21,7 @@ server { access_log /var/log/nginx/git-{{ gitolite_instance }}_access.log; error_log /var/log/nginx/git-{{ gitolite_instance }}_error.log; - include snippets/acmetool.conf; + include snippets/{{ acme_client }}.conf; include snippets/tls.conf; ssl_certificate {{ x509_certificate_path_fullchain }}; ssl_certificate_key {{ x509_certificate_path_key }}; diff --git a/roles/monitoring/landingpage/defaults/main.yml b/roles/monitoring/landingpage/defaults/main.yml index ad2a3895..88e1b133 100644 --- a/roles/monitoring/landingpage/defaults/main.yml +++ b/roles/monitoring/landingpage/defaults/main.yml @@ -2,6 +2,7 @@ # monitoring_landingpage_hostnames: # - "mon.example.com" -monitoring_landingpage_acme: no +# monitoring_landingpage_tls: +# certificate_provider: "{{ acme_client }}" #monitoring_landingpage_title: "Example Monitoring Host" diff --git a/roles/monitoring/landingpage/tasks/main.yml b/roles/monitoring/landingpage/tasks/main.yml index 3158770b..225cab10 100644 --- a/roles/monitoring/landingpage/tasks/main.yml +++ b/roles/monitoring/landingpage/tasks/main.yml @@ -15,7 +15,8 @@ name: landingpage template: generic hostnames: "{{ monitoring_landingpage_hostnames }}" - acme: "{{ monitoring_landingpage_acme }}" + ### make tls settings optional? + #tls: "{{ monitoring_landingpage_tls }}" locations: '/': root: /var/www/landingpage diff --git a/roles/monitoring/prometheus/exporter/base/tasks/main.yml b/roles/monitoring/prometheus/exporter/base/tasks/main.yml index c69c6e05..3cedc042 100644 --- a/roles/monitoring/prometheus/exporter/base/tasks/main.yml +++ b/roles/monitoring/prometheus/exporter/base/tasks/main.yml @@ -21,10 +21,14 @@ - name: create TLS certificate and key import_tasks: tls.yml +- name: render nginx-vhost config template + set_fact: + prometheus_exporter_nginx_vhost_content: "{{ lookup('template', 'nginx-vhost.j2') }}" + - name: configure nginx vhost - import_role: - name: nginx/vhost vars: nginx_vhost: name: prometheus-exporter - content: "{{ lookup('template', 'nginx-vhost.j2') }}" + content: "{{ prometheus_exporter_nginx_vhost_content }}" + import_role: + name: nginx/vhost diff --git a/roles/nginx/vhost/defaults/main.yml b/roles/nginx/vhost/defaults/main.yml index b80a5442..5984e623 100644 --- a/roles/nginx/vhost/defaults/main.yml +++ b/roles/nginx/vhost/defaults/main.yml @@ -3,7 +3,8 @@ # default: yes # name: example # template: generic -# acme: yes +# tls: +# certificate_provider: acmetool # hostnames: # - example.com # - www.example.com @@ -26,7 +27,10 @@ # nginx_vhost: # name: mixed-static-and-proxy # template: generic -# acme: yes +# tls: +# variant: legacy +# hsts: false +# certificate_provider: acmetool # hostnames: # - static.example.com # extra_directives: |- diff --git a/roles/nginx/vhost/tasks/main.yml b/roles/nginx/vhost/tasks/main.yml index 424c86a0..c5e68732 100644 --- a/roles/nginx/vhost/tasks/main.yml +++ b/roles/nginx/vhost/tasks/main.yml @@ -1,11 +1,12 @@ --- - name: ensure certificate exists (fake it, until you make it) - when: "'acme' in nginx_vhost and nginx_vhost.acme" - import_role: - name: x509/acmetool/cert/prepare + when: "'tls' in nginx_vhost" + include_role: + name: "x509/{{ nginx_vhost.tls.certificate_provider }}/cert/prepare" + public: true vars: - acmetool_cert_name: "{{ nginx_vhost.name }}" - acmetool_cert_hostnames: "{{ nginx_vhost.hostnames }}" + x509_certificate_name: "{{ nginx_vhost.name }}" + x509_certificate_hostnames: "{{ nginx_vhost.hostnames }}" - name: install nginx configs from template when: "'template' in nginx_vhost" @@ -31,14 +32,14 @@ notify: reload nginx - name: generate acme certificate - when: "'acme' in nginx_vhost and nginx_vhost.acme" + when: "'tls' in nginx_vhost" block: - name: make sure nginx config has been (re)loaded meta: flush_handlers - name: actually request the certificate - import_role: - name: x509/acmetool/cert/finalize + include_role: + name: "x509/{{ nginx_vhost.tls.certificate_provider }}/cert/finalize" vars: - acmetool_cert_name: "{{ nginx_vhost.name }}" - acmetool_cert_hostnames: "{{ nginx_vhost.hostnames }}" + x509_certificate_name: "{{ nginx_vhost.name }}" + x509_certificate_hostnames: "{{ nginx_vhost.hostnames }}" diff --git a/roles/nginx/vhost/templates/generic.conf.j2 b/roles/nginx/vhost/templates/generic.conf.j2 index 5c7576e7..434fa679 100644 --- a/roles/nginx/vhost/templates/generic.conf.j2 +++ b/roles/nginx/vhost/templates/generic.conf.j2 @@ -3,9 +3,11 @@ server { listen [::]:80{% if 'default' in nginx_vhost and nginx_vhost.default %} default_server{% endif %}; server_name {{ nginx_vhost.hostnames | join(' ') }}; -{% if 'acme' in nginx_vhost and nginx_vhost.acme %} +{% if 'tls' in nginx_vhost %} +{% if nginx_vhost.tls.certificate_provider == 'acmetool' %} include snippets/acmetool.conf; +{% endif %} location / { return 301 https://$host$request_uri; } @@ -16,11 +18,15 @@ server { listen [::]:443 ssl http2{% if 'default' in nginx_vhost and nginx_vhost.default %} default_server{% endif %}; server_name {{ nginx_vhost.hostnames | join(' ') }}; +{% if nginx_vhost.tls.certificate_provider == 'acmetool' %} include snippets/acmetool.conf; - include snippets/tls{% if 'tls_variant' in nginx_vhost %}-{{ nginx_vhost.tls_variant }}{% endif %}.conf; +{% endif %} + include snippets/tls{% if 'variant' in nginx_vhost.tls %}-{{ nginx_vhost.tls.variant }}{% endif %}.conf; ssl_certificate {{ x509_certificate_path_fullchain }}; ssl_certificate_key {{ x509_certificate_path_key }}; +{% if 'hsts' not in nginx_vhost.tls or nginx_vhost.tls.hsts %} include snippets/hsts.conf; +{% endif %} {% endif %} {% if 'extra_directives' in nginx_vhost %} diff --git a/roles/x509/acmetool/cert/finalize/defaults/main.yml b/roles/x509/acmetool/cert/finalize/defaults/main.yml index ab0afaa3..b9a80136 100644 --- a/roles/x509/acmetool/cert/finalize/defaults/main.yml +++ b/roles/x509/acmetool/cert/finalize/defaults/main.yml @@ -1,2 +1,5 @@ --- +acmetool_cert_hostnames: "{{ x509_certificate_hostnames }}" +acmetool_cert_name: "{{ x509_certificate_name | default(acmetool_cert_hostnames[0]) }}" + acmetool_reconcile_disabled: false diff --git a/roles/x509/acmetool/cert/finalize/tasks/main.yml b/roles/x509/acmetool/cert/finalize/tasks/main.yml index 91bf5157..abb2d4cb 100644 --- a/roles/x509/acmetool/cert/finalize/tasks/main.yml +++ b/roles/x509/acmetool/cert/finalize/tasks/main.yml @@ -6,5 +6,5 @@ names: "{{ acmetool_cert_hostnames }}" copy: content: "{{ acmetool_cert_config | default({}) | combine(acmetool_cert_satisfy) | to_nice_yaml }}" - dest: "/var/lib/acme/desired/{{ acmetool_cert_name | default(acmetool_cert_hostnames[0]) }}" + dest: "/var/lib/acme/desired/{{ acmetool_cert_name }}" notify: reconcile acmetool 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/spreadspace/glt-stream.yml b/spreadspace/glt-stream.yml index 145f8671..063baba8 100644 --- a/spreadspace/glt-stream.yml +++ b/spreadspace/glt-stream.yml @@ -29,7 +29,8 @@ default: yes name: stream template: generic - acme: yes + tls: + certificate_provider: "{{ acme_client }}" hostnames: - stream.linuxtage.at extra_directives: |- diff --git a/spreadspace/sgg-icecast.yml b/spreadspace/sgg-icecast.yml index bfe67bde..69dbc883 100644 --- a/spreadspace/sgg-icecast.yml +++ b/spreadspace/sgg-icecast.yml @@ -32,7 +32,8 @@ default: yes name: radio template: generic - acme: yes + tls: + certificate_provider: "{{ acme_client }}" hostnames: - radiogloria.at - www.radiogloria.at @@ -48,7 +49,8 @@ nginx_vhost: name: radio-stream template: generic - acme: yes + tls: + certificate_provider: "{{ acme_client }}" hostnames: - live.radiogloria.at locations: -- cgit v1.2.3 From 91441c684bff2f8807199e4696d39683af02a953 Mon Sep 17 00:00:00 2001 From: Christian Pointner Date: Wed, 16 Aug 2023 01:04:37 +0200 Subject: add role: x509/static --- dan/sk-testvm.yml | 10 +- inventory/host_vars/sk-testvm.yml | 316 +++++++++++++++++++++++ roles/nginx/vhost/tasks/main.yml | 2 + roles/x509/acmetool/cert/meta/main.yml | 1 + roles/x509/static/base/tasks/main.yml | 2 + roles/x509/static/cert/finalize/tasks/main.yml | 2 + roles/x509/static/cert/meta/main.yml | 4 + roles/x509/static/cert/prepare/defaults/main.yml | 35 +++ roles/x509/static/cert/prepare/tasks/main.yml | 81 ++++++ 9 files changed, 449 insertions(+), 4 deletions(-) create mode 100644 roles/x509/static/base/tasks/main.yml create mode 100644 roles/x509/static/cert/finalize/tasks/main.yml create mode 100644 roles/x509/static/cert/meta/main.yml create mode 100644 roles/x509/static/cert/prepare/defaults/main.yml create mode 100644 roles/x509/static/cert/prepare/tasks/main.yml (limited to 'roles/x509') diff --git a/dan/sk-testvm.yml b/dan/sk-testvm.yml index c7aaf754..c66601cb 100644 --- a/dan/sk-testvm.yml +++ b/dan/sk-testvm.yml @@ -11,9 +11,9 @@ - name: Payload Setup hosts: sk-testvm vars: - acme_client: acmetool + cert_provider: static roles: - - role: "x509/{{ acme_client }}/base" + - role: "x509/{{ cert_provider }}/base" - role: nginx/base post_tasks: - name: make sure document root directories exist @@ -46,7 +46,7 @@ name: nosuchsite template: generic tls: - certificate_provider: "{{ acme_client }}" + certificate_provider: "{{ cert_provider }}" hsts: no hostnames: - testvm.elev8.at @@ -54,6 +54,7 @@ '/': root: /var/www/default index: index.html + static_cert_config: "{{ static_cert_config__default }}" include_role: name: nginx/vhost @@ -79,7 +80,7 @@ name: test template: generic tls: - certificate_provider: "{{ acme_client }}" + certificate_provider: "{{ cert_provider }}" hsts: no hostnames: - test.spreadspace.org @@ -90,5 +91,6 @@ '/': root: /var/www/test index: index.html + static_cert_config: "{{ static_cert_config__test }}" include_role: name: nginx/vhost diff --git a/inventory/host_vars/sk-testvm.yml b/inventory/host_vars/sk-testvm.yml index 3eaf94c4..a6eed52d 100644 --- a/inventory/host_vars/sk-testvm.yml +++ b/inventory/host_vars/sk-testvm.yml @@ -38,3 +38,319 @@ external_ip: "{{ network.primary.overlay }}" # https://owncloud.org/news/upgrading-owncloud-on-debian-stable-to-official-packages/ # nginx_server_names_hash_bucket_size: 64 + + +static_cert_config__default: + key: + content: | + -----BEGIN RSA PRIVATE KEY----- + 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 + -----END RSA PRIVATE KEY----- + cert: + content: | + -----BEGIN CERTIFICATE----- + MIIGGzCCBQOgAwIBAgITAPqTv2Ggom9ksX9aLTLweB6M0DANBgkqhkiG9w0BAQsF + ADBZMQswCQYDVQQGEwJVUzEgMB4GA1UEChMXKFNUQUdJTkcpIExldCdzIEVuY3J5 + cHQxKDAmBgNVBAMTHyhTVEFHSU5HKSBBcnRpZmljaWFsIEFwcmljb3QgUjMwHhcN + MjMwODA5MTA1MzAwWhcNMjMxMTA3MTA1MjU5WjAaMRgwFgYDVQQDEw90ZXN0dm0u + ZWxldjguYXQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQChRMRfIFJm + FhZCzTDHp8s7plb7gMGnz5Qk4bOcmfG5TrweFJyY+gMdcT0M/i4+rzqzZ4PeMJli + hQ7690RM5omurq8gDdYQB601Ca/oj0J+FaGvJv1AYNQU+2NOKUbYYMD6PmhLt30d + gt+kO4n71vLUj2tIimzzn3nx3VNu6+m3AvlEUHgEE52Gw1owpOxyxVR3dKjNnHjD + AMymMuM2KDtUqWeoxV6yc0O5CO0UxlkGN5eDUN/dPRFealJE0gJH8tPe8OfMWR/S + EU5pRI+gRfA3G/id6kivzZ3Uh2p51PFzhE9hy6LmUxtifAKKD82CUfoDAEkHEYWM + gZ8ZwG56agawqe7tmlNuzFDio23e+CwMMaxwnqh3VESnbthJ18AK0ybxLCflkB7H + Xw7ByJt4VWrrp9tWmrSIH6w2d7Oh/p6XTrBMXUx7HYFjsiQqkl4K4cLBP330qrrn + bVSSDU52DEu602GVsnAtbwt/pdgZoLJ3L9AzxaI9JRMu9GCPfX/dFA5UD/DvP6ag + DIk7X/9MFHmxbIoT+Bk1RbgCb74vX4vupDqRNWmFbx/z0UiAMctTaE52/swo38Zf + u4cJXF6xMqBT8MunvD2I2NR5RoPjqwt58oH4yzgqm+8ZuvEtHbWsPG4yq5ntUsbv + /QI1WewL96uCAeJRM+N11E/ZzPftxNZsnQIDAQABo4ICGTCCAhUwDgYDVR0PAQH/ + BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8E + AjAAMB0GA1UdDgQWBBQ+nXoERS+3lz/+LksWdhlIRdBRZzAfBgNVHSMEGDAWgBTe + cnpI3zHDplDfn4Uj31c3S10uZTBdBggrBgEFBQcBAQRRME8wJQYIKwYBBQUHMAGG + GWh0dHA6Ly9zdGctcjMuby5sZW5jci5vcmcwJgYIKwYBBQUHMAKGGmh0dHA6Ly9z + dGctcjMuaS5sZW5jci5vcmcvMBoGA1UdEQQTMBGCD3Rlc3R2bS5lbGV2OC5hdDAT + BgNVHSAEDDAKMAgGBmeBDAECATCCAQQGCisGAQQB1nkCBAIEgfUEgfIA8AB1ALDM + g+Wl+X1rr3wJzChJBIcqx+iLEyxjULfG/SbhbGx3AAABidoknl8AAAQDAEYwRAIg + WtCJ8ld4R1f2KNpuMFrOjvjp08Tz4OFvZ0+HPHxcPfECIFoVZ4ZYsgg7Z+gUsP+N + auCUo3gnonymPzdyl8Mlg2WgAHcA7audHd2Dc5Wf9SqI5Gu0vMPEzE12imDM/042 + LX+41mgAAAGJ2iSgVwAABAMASDBGAiEA6vwwJZROjqHlG6PAI3PBTgQvsPf1XDVn + HdTRg3lVfxQCIQDiyPNyJVAQJcjDYxRJZchP2GIs3pHbmY2qC8TrzpTA/DANBgkq + hkiG9w0BAQsFAAOCAQEArmQ+hx5+72piX+y27K+pFzWvYAJ9VjYULj+Un3N+Ta2U + y7nL89b0Hpy9/FlZz2joG10/1TQGC11M6Nq0fWmK5BTf0MPEkVLG3ChkhPZeHsWa + ok18WiHjy5jjgF4uPbAnSorYmR77ANnuKM1RNpF/xkPb1wQDvF7TmtEdfeMbLGM0 + 2Pa7cnrwEiq5dC2oyC+D2Qkfvr4Z1t28WepDHGG66VPes7puuL3XMZnor+8SGtCp + WfMrrIShXDSQcssxoD9XG6SM15lSCPHjKDT9lhellwvrbGOwKcX+PVJNZW9jGU7D + f/PRJpM9pJiz8KqUoVA0o3Sri6DPS6OEH7JPYXszqw== + -----END CERTIFICATE----- + chain: + content: | + -----BEGIN CERTIFICATE----- + MIIFWzCCA0OgAwIBAgIQTfQrldHumzpMLrM7jRBd1jANBgkqhkiG9w0BAQsFADBm + MQswCQYDVQQGEwJVUzEzMDEGA1UEChMqKFNUQUdJTkcpIEludGVybmV0IFNlY3Vy + aXR5IFJlc2VhcmNoIEdyb3VwMSIwIAYDVQQDExkoU1RBR0lORykgUHJldGVuZCBQ + ZWFyIFgxMB4XDTIwMDkwNDAwMDAwMFoXDTI1MDkxNTE2MDAwMFowWTELMAkGA1UE + BhMCVVMxIDAeBgNVBAoTFyhTVEFHSU5HKSBMZXQncyBFbmNyeXB0MSgwJgYDVQQD + Ex8oU1RBR0lORykgQXJ0aWZpY2lhbCBBcHJpY290IFIzMIIBIjANBgkqhkiG9w0B + AQEFAAOCAQ8AMIIBCgKCAQEAu6TR8+74b46mOE1FUwBrvxzEYLck3iasmKrcQkb+ + gy/z9Jy7QNIAl0B9pVKp4YU76JwxF5DOZZhi7vK7SbCkK6FbHlyU5BiDYIxbbfvO + L/jVGqdsSjNaJQTg3C3XrJja/HA4WCFEMVoT2wDZm8ABC1N+IQe7Q6FEqc8NwmTS + nmmRQm4TQvr06DP+zgFK/MNubxWWDSbSKKTH5im5j2fZfg+j/tM1bGaczFWw8/lS + nukyn5J2L+NJYnclzkXoh9nMFnyPmVbfyDPOc4Y25aTzVoeBKXa/cZ5MM+WddjdL + biWvm19f1sYn1aRaAIrkppv7kkn83vcth8XCG39qC2ZvaQIDAQABo4IBEDCCAQww + DgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAS + BgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBTecnpI3zHDplDfn4Uj31c3S10u + ZTAfBgNVHSMEGDAWgBS182Xy/rAKkh/7PH3zRKCsYyXDFDA2BggrBgEFBQcBAQQq + MCgwJgYIKwYBBQUHMAKGGmh0dHA6Ly9zdGcteDEuaS5sZW5jci5vcmcvMCsGA1Ud + HwQkMCIwIKAeoByGGmh0dHA6Ly9zdGcteDEuYy5sZW5jci5vcmcvMCIGA1UdIAQb + MBkwCAYGZ4EMAQIBMA0GCysGAQQBgt8TAQEBMA0GCSqGSIb3DQEBCwUAA4ICAQCN + DLam9yN0EFxxn/3p+ruWO6n/9goCAM5PT6cC6fkjMs4uas6UGXJjr5j7PoTQf3C1 + vuxiIGRJC6qxV7yc6U0X+w0Mj85sHI5DnQVWN5+D1er7mp13JJA0xbAbHa3Rlczn + y2Q82XKui8WHuWra0gb2KLpfboYj1Ghgkhr3gau83pC/WQ8HfkwcvSwhIYqTqxoZ + Uq8HIf3M82qS9aKOZE0CEmSyR1zZqQxJUT7emOUapkUN9poJ9zGc+FgRZvdro0XB + yphWXDaqMYph0DxW/10ig5j4xmmNDjCRmqIKsKoWA52wBTKKXK1na2ty/lW5dhtA + xkz5rVZFd4sgS4J0O+zm6d5GRkWsNJ4knotGXl8vtS3X40KXeb3A5+/3p0qaD215 + Xq8oSNORfB2oI1kQuyEAJ5xvPTdfwRlyRG3lFYodrRg6poUBD/8fNTXMtzydpRgy + zUQZh/18F6B/iW6cbiRN9r2Hkh05Om+q0/6w0DdZe+8YrNpfhSObr/1eVZbKGMIY + qKmyZbBNu5ysENIK5MPc14mUeKmFjpN840VR5zunoU52lqpLDua/qIM8idk86xGW + xx2ml43DO/Ya/tVZVok0mO0TUjzJIfPqyvr455IsIut4RlCR9Iq0EDTve2/ZwCuG + hSjpTUFGSiQrR2JK2Evp+o6AETUkBCO1aw0PpQBPDQ== + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIIFVDCCBDygAwIBAgIRAO1dW8lt+99NPs1qSY3Rs8cwDQYJKoZIhvcNAQELBQAw + cTELMAkGA1UEBhMCVVMxMzAxBgNVBAoTKihTVEFHSU5HKSBJbnRlcm5ldCBTZWN1 + cml0eSBSZXNlYXJjaCBHcm91cDEtMCsGA1UEAxMkKFNUQUdJTkcpIERvY3RvcmVk + IER1cmlhbiBSb290IENBIFgzMB4XDTIxMDEyMDE5MTQwM1oXDTI0MDkzMDE4MTQw + M1owZjELMAkGA1UEBhMCVVMxMzAxBgNVBAoTKihTVEFHSU5HKSBJbnRlcm5ldCBT + ZWN1cml0eSBSZXNlYXJjaCBHcm91cDEiMCAGA1UEAxMZKFNUQUdJTkcpIFByZXRl + bmQgUGVhciBYMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALbagEdD + Ta1QgGBWSYkyMhscZXENOBaVRTMX1hceJENgsL0Ma49D3MilI4KS38mtkmdF6cPW + nL++fgehT0FbRHZgjOEr8UAN4jH6omjrbTD++VZneTsMVaGamQmDdFl5g1gYaigk + kmx8OiCO68a4QXg4wSyn6iDipKP8utsE+x1E28SA75HOYqpdrk4HGxuULvlr03wZ + GTIf/oRt2/c+dYmDoaJhge+GOrLAEQByO7+8+vzOwpNAPEx6LW+crEEZ7eBXih6V + P19sTGy3yfqK5tPtTdXXCOQMKAp+gCj/VByhmIr+0iNDC540gtvV303WpcbwnkkL + YC0Ft2cYUyHtkstOfRcRO+K2cZozoSwVPyB8/J9RpcRK3jgnX9lujfwA/pAbP0J2 + UPQFxmWFRQnFjaq6rkqbNEBgLy+kFL1NEsRbvFbKrRi5bYy2lNms2NJPZvdNQbT/ + 2dBZKmJqxHkxCuOQFjhJQNeO+Njm1Z1iATS/3rts2yZlqXKsxQUzN6vNbD8KnXRM + EeOXUYvbV4lqfCf8mS14WEbSiMy87GB5S9ucSV1XUrlTG5UGcMSZOBcEUpisRPEm + QWUOTWIoDQ5FOia/GI+Ki523r2ruEmbmG37EBSBXdxIdndqrjy+QVAmCebyDx9eV + EGOIpn26bW5LKerumJxa/CFBaKi4bRvmdJRLAgMBAAGjgfEwge4wDgYDVR0PAQH/ + BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFLXzZfL+sAqSH/s8ffNE + oKxjJcMUMB8GA1UdIwQYMBaAFAhX2onHolN5DE/d4JCPdLriJ3NEMDgGCCsGAQUF + BwEBBCwwKjAoBggrBgEFBQcwAoYcaHR0cDovL3N0Zy1kc3QzLmkubGVuY3Iub3Jn + LzAtBgNVHR8EJjAkMCKgIKAehhxodHRwOi8vc3RnLWRzdDMuYy5sZW5jci5vcmcv + MCIGA1UdIAQbMBkwCAYGZ4EMAQIBMA0GCysGAQQBgt8TAQEBMA0GCSqGSIb3DQEB + CwUAA4IBAQB7tR8B0eIQSS6MhP5kuvGth+dN02DsIhr0yJtk2ehIcPIqSxRRmHGl + 4u2c3QlvEpeRDp2w7eQdRTlI/WnNhY4JOofpMf2zwABgBWtAu0VooQcZZTpQruig + F/z6xYkBk3UHkjeqxzMN3d1EqGusxJoqgdTouZ5X5QTTIee9nQ3LEhWnRSXDx7Y0 + ttR1BGfcdqHopO4IBqAhbkKRjF5zj7OD8cG35omywUbZtOJnftiI0nFcRaxbXo0v + oDfLD0S6+AC2R3tKpqjkNX6/91hrRFglUakyMcZU/xleqbv6+Lr3YD8PsBTub6lI + oZ2lS38fL18Aon458fbc0BPHtenfhKj5 + -----END CERTIFICATE----- + + +static_cert_config__test: + key: + content: | + -----BEGIN RSA PRIVATE KEY----- + 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 + -----END RSA PRIVATE KEY----- + cert: + content: | + -----BEGIN CERTIFICATE----- + MIIGaTCCBVGgAwIBAgITAPqbPyeH5GyeBBoPgHbVWlDC3TANBgkqhkiG9w0BAQsF + ADBZMQswCQYDVQQGEwJVUzEgMB4GA1UEChMXKFNUQUdJTkcpIExldCdzIEVuY3J5 + cHQxKDAmBgNVBAMTHyhTVEFHSU5HKSBBcnRpZmljaWFsIEFwcmljb3QgUjMwHhcN + MjMwODA5MTA1MzI3WhcNMjMxMTA3MTA1MzI2WjAfMR0wGwYDVQQDExR0ZXN0LnNw + cmVhZHNwYWNlLm9yZzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL9h + y+Pe0DFWDV+/9P/nfvhfb6rQUUvBOab8nzoi9q/ShoKrdS9uSqT2DZC38L9YmzIj + KJS0Q/Pe1McjXfN0x3O4OAQ8BFX+RCmHhL6RdUV1IdgUEcivD7xenBvrabHxOd53 + y0fpjA0JMcmuQhpbRBUWOnguiXzxOdeKGUc5weoImzr9LProYFZe4pYrGSQLUpUE + VrhAwarKdLhqFXq2JAHFyHQKUj0KKOw4Cr0fxLMW83wZWjqSkL3vTiF53Q1olNeP + 7sbeSaLiE7s8ZGUW3xmkZzZ6f6SNdPB6XZ2FBiuQmCB6HlEwv2JtrNDKTQX94fUp + 5snVD7x00lI1ubnlLDGNkaEZTv6D+1cOmNwsGoPKJige9DQeO8rxlttppeqOxS1m + LPY6YyagacH6mx5O8o9j/ZHtF5saFYEC+QPj2aLAlAd9ikOzlFgU+Yep580sF55G + MmVCs/HDAi2Lx2+TFsliwY9Hwcp/VzSAcwIvyMGfbXaiiithVlvybFV9nKx2qpCP + Ons/g8Yuoq3ElGrcudCXiLVd6PdhaMTIlXJJ0fcmeHk0tT9EbyiZ4ALmee4wb5nN + FRrA1nS/KaI6VTaWdTX161bZryicRxDDtAfHVZCp1L+56WlM5OhWw05wWclD307d + 8qLIs3UHssjmlzhnfCBXSDdS89bYj0MBS4uHjMzHAgMBAAGjggJiMIICXjAOBgNV + HQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwGA1Ud + EwEB/wQCMAAwHQYDVR0OBBYEFDy0lODy9HEp1M4FdG/YUjBBnQ0IMB8GA1UdIwQY + MBaAFN5yekjfMcOmUN+fhSPfVzdLXS5lMF0GCCsGAQUFBwEBBFEwTzAlBggrBgEF + BQcwAYYZaHR0cDovL3N0Zy1yMy5vLmxlbmNyLm9yZzAmBggrBgEFBQcwAoYaaHR0 + cDovL3N0Zy1yMy5pLmxlbmNyLm9yZy8wZQYDVR0RBF4wXIIUdGVzdC5zcHJlYWRz + cGFjZS5jb22CFHRlc3Quc3ByZWFkc3BhY2UubmV0ghR0ZXN0LnNwcmVhZHNwYWNl + Lm9yZ4IYdGVzdC5zcHJlYWRzcGFjZS5zeXN0ZW1zMBMGA1UdIAQMMAowCAYGZ4EM + AQIBMIIBAgYKKwYBBAHWeQIEAgSB8wSB8ADuAHUA7audHd2Dc5Wf9SqI5Gu0vMPE + zE12imDM/042LX+41mgAAAGJ2iUJgAAABAMARjBEAiB2GccK+Wwc6m2JIsJ4PbrC + Y+UXnoi9v0VPzir4bVYMGwIgIonr7RaEhjJ8QiEfkcBc0j6k0AzM3Ee9raoNKx4l + rKcAdQCwzIPlpfl9a698CcwoSQSHKsfoixMsY1C3xv0m4WxsdwAAAYnaJQtyAAAE + AwBGMEQCIHPBuvYBtUfsYU6WTMoa1IuCD2TeTGbCySEW/ZHlYtkEAiBzTQNkThq8 + tpregOqi7ypchg9JFS/JzMfjjuDlBnFndjANBgkqhkiG9w0BAQsFAAOCAQEAlG32 + KRc6Ln3AwhodYdDB9+SC8/vouCzaRTcgPVWYX/dZuXCvsWCGQ9bi9/VAWRgR0IuF + yibvGQ7dgL8cTDzfVvXdNa52VlgIxJ8Zag7CPSSHrmoOwH7j00t6mZveujmHpg4o + mtaiC3NHAXJopkNJjJYNKUSLYO8xULhaHrkbA8m9khdlTesraMQQyv80H/ohE3J2 + qWKB/qO2EpmlbolIVbFWJPvo6oynn4ELrVJBDbWLMoDqGq8suIIeWbSZvkoqm9O2 + AYroae5qP5GjB47gceH2SmQwqP69GKJimJhGhO3WDE/9PGSCUQB5vUGuK/wNmYrj + VWVPzMLHuAhSryY9Fw== + -----END CERTIFICATE----- + chain: + content: | + -----BEGIN CERTIFICATE----- + MIIFWzCCA0OgAwIBAgIQTfQrldHumzpMLrM7jRBd1jANBgkqhkiG9w0BAQsFADBm + MQswCQYDVQQGEwJVUzEzMDEGA1UEChMqKFNUQUdJTkcpIEludGVybmV0IFNlY3Vy + aXR5IFJlc2VhcmNoIEdyb3VwMSIwIAYDVQQDExkoU1RBR0lORykgUHJldGVuZCBQ + ZWFyIFgxMB4XDTIwMDkwNDAwMDAwMFoXDTI1MDkxNTE2MDAwMFowWTELMAkGA1UE + BhMCVVMxIDAeBgNVBAoTFyhTVEFHSU5HKSBMZXQncyBFbmNyeXB0MSgwJgYDVQQD + Ex8oU1RBR0lORykgQXJ0aWZpY2lhbCBBcHJpY290IFIzMIIBIjANBgkqhkiG9w0B + AQEFAAOCAQ8AMIIBCgKCAQEAu6TR8+74b46mOE1FUwBrvxzEYLck3iasmKrcQkb+ + gy/z9Jy7QNIAl0B9pVKp4YU76JwxF5DOZZhi7vK7SbCkK6FbHlyU5BiDYIxbbfvO + L/jVGqdsSjNaJQTg3C3XrJja/HA4WCFEMVoT2wDZm8ABC1N+IQe7Q6FEqc8NwmTS + nmmRQm4TQvr06DP+zgFK/MNubxWWDSbSKKTH5im5j2fZfg+j/tM1bGaczFWw8/lS + nukyn5J2L+NJYnclzkXoh9nMFnyPmVbfyDPOc4Y25aTzVoeBKXa/cZ5MM+WddjdL + biWvm19f1sYn1aRaAIrkppv7kkn83vcth8XCG39qC2ZvaQIDAQABo4IBEDCCAQww + DgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAS + BgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBTecnpI3zHDplDfn4Uj31c3S10u + ZTAfBgNVHSMEGDAWgBS182Xy/rAKkh/7PH3zRKCsYyXDFDA2BggrBgEFBQcBAQQq + MCgwJgYIKwYBBQUHMAKGGmh0dHA6Ly9zdGcteDEuaS5sZW5jci5vcmcvMCsGA1Ud + HwQkMCIwIKAeoByGGmh0dHA6Ly9zdGcteDEuYy5sZW5jci5vcmcvMCIGA1UdIAQb + MBkwCAYGZ4EMAQIBMA0GCysGAQQBgt8TAQEBMA0GCSqGSIb3DQEBCwUAA4ICAQCN + DLam9yN0EFxxn/3p+ruWO6n/9goCAM5PT6cC6fkjMs4uas6UGXJjr5j7PoTQf3C1 + vuxiIGRJC6qxV7yc6U0X+w0Mj85sHI5DnQVWN5+D1er7mp13JJA0xbAbHa3Rlczn + y2Q82XKui8WHuWra0gb2KLpfboYj1Ghgkhr3gau83pC/WQ8HfkwcvSwhIYqTqxoZ + Uq8HIf3M82qS9aKOZE0CEmSyR1zZqQxJUT7emOUapkUN9poJ9zGc+FgRZvdro0XB + yphWXDaqMYph0DxW/10ig5j4xmmNDjCRmqIKsKoWA52wBTKKXK1na2ty/lW5dhtA + xkz5rVZFd4sgS4J0O+zm6d5GRkWsNJ4knotGXl8vtS3X40KXeb3A5+/3p0qaD215 + Xq8oSNORfB2oI1kQuyEAJ5xvPTdfwRlyRG3lFYodrRg6poUBD/8fNTXMtzydpRgy + zUQZh/18F6B/iW6cbiRN9r2Hkh05Om+q0/6w0DdZe+8YrNpfhSObr/1eVZbKGMIY + qKmyZbBNu5ysENIK5MPc14mUeKmFjpN840VR5zunoU52lqpLDua/qIM8idk86xGW + xx2ml43DO/Ya/tVZVok0mO0TUjzJIfPqyvr455IsIut4RlCR9Iq0EDTve2/ZwCuG + hSjpTUFGSiQrR2JK2Evp+o6AETUkBCO1aw0PpQBPDQ== + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIIFVDCCBDygAwIBAgIRAO1dW8lt+99NPs1qSY3Rs8cwDQYJKoZIhvcNAQELBQAw + cTELMAkGA1UEBhMCVVMxMzAxBgNVBAoTKihTVEFHSU5HKSBJbnRlcm5ldCBTZWN1 + cml0eSBSZXNlYXJjaCBHcm91cDEtMCsGA1UEAxMkKFNUQUdJTkcpIERvY3RvcmVk + IER1cmlhbiBSb290IENBIFgzMB4XDTIxMDEyMDE5MTQwM1oXDTI0MDkzMDE4MTQw + M1owZjELMAkGA1UEBhMCVVMxMzAxBgNVBAoTKihTVEFHSU5HKSBJbnRlcm5ldCBT + ZWN1cml0eSBSZXNlYXJjaCBHcm91cDEiMCAGA1UEAxMZKFNUQUdJTkcpIFByZXRl + bmQgUGVhciBYMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALbagEdD + Ta1QgGBWSYkyMhscZXENOBaVRTMX1hceJENgsL0Ma49D3MilI4KS38mtkmdF6cPW + nL++fgehT0FbRHZgjOEr8UAN4jH6omjrbTD++VZneTsMVaGamQmDdFl5g1gYaigk + kmx8OiCO68a4QXg4wSyn6iDipKP8utsE+x1E28SA75HOYqpdrk4HGxuULvlr03wZ + GTIf/oRt2/c+dYmDoaJhge+GOrLAEQByO7+8+vzOwpNAPEx6LW+crEEZ7eBXih6V + P19sTGy3yfqK5tPtTdXXCOQMKAp+gCj/VByhmIr+0iNDC540gtvV303WpcbwnkkL + YC0Ft2cYUyHtkstOfRcRO+K2cZozoSwVPyB8/J9RpcRK3jgnX9lujfwA/pAbP0J2 + UPQFxmWFRQnFjaq6rkqbNEBgLy+kFL1NEsRbvFbKrRi5bYy2lNms2NJPZvdNQbT/ + 2dBZKmJqxHkxCuOQFjhJQNeO+Njm1Z1iATS/3rts2yZlqXKsxQUzN6vNbD8KnXRM + EeOXUYvbV4lqfCf8mS14WEbSiMy87GB5S9ucSV1XUrlTG5UGcMSZOBcEUpisRPEm + QWUOTWIoDQ5FOia/GI+Ki523r2ruEmbmG37EBSBXdxIdndqrjy+QVAmCebyDx9eV + EGOIpn26bW5LKerumJxa/CFBaKi4bRvmdJRLAgMBAAGjgfEwge4wDgYDVR0PAQH/ + BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFLXzZfL+sAqSH/s8ffNE + oKxjJcMUMB8GA1UdIwQYMBaAFAhX2onHolN5DE/d4JCPdLriJ3NEMDgGCCsGAQUF + BwEBBCwwKjAoBggrBgEFBQcwAoYcaHR0cDovL3N0Zy1kc3QzLmkubGVuY3Iub3Jn + LzAtBgNVHR8EJjAkMCKgIKAehhxodHRwOi8vc3RnLWRzdDMuYy5sZW5jci5vcmcv + MCIGA1UdIAQbMBkwCAYGZ4EMAQIBMA0GCysGAQQBgt8TAQEBMA0GCSqGSIb3DQEB + CwUAA4IBAQB7tR8B0eIQSS6MhP5kuvGth+dN02DsIhr0yJtk2ehIcPIqSxRRmHGl + 4u2c3QlvEpeRDp2w7eQdRTlI/WnNhY4JOofpMf2zwABgBWtAu0VooQcZZTpQruig + F/z6xYkBk3UHkjeqxzMN3d1EqGusxJoqgdTouZ5X5QTTIee9nQ3LEhWnRSXDx7Y0 + ttR1BGfcdqHopO4IBqAhbkKRjF5zj7OD8cG35omywUbZtOJnftiI0nFcRaxbXo0v + oDfLD0S6+AC2R3tKpqjkNX6/91hrRFglUakyMcZU/xleqbv6+Lr3YD8PsBTub6lI + oZ2lS38fL18Aon458fbc0BPHtenfhKj5 + -----END CERTIFICATE----- diff --git a/roles/nginx/vhost/tasks/main.yml b/roles/nginx/vhost/tasks/main.yml index c5e68732..55544733 100644 --- a/roles/nginx/vhost/tasks/main.yml +++ b/roles/nginx/vhost/tasks/main.yml @@ -7,6 +7,7 @@ vars: x509_certificate_name: "{{ nginx_vhost.name }}" x509_certificate_hostnames: "{{ nginx_vhost.hostnames }}" + x509_notify_on_change: reload nginx - name: install nginx configs from template when: "'template' in nginx_vhost" @@ -43,3 +44,4 @@ vars: x509_certificate_name: "{{ nginx_vhost.name }}" x509_certificate_hostnames: "{{ nginx_vhost.hostnames }}" + x509_notify_on_change: reload nginx diff --git a/roles/x509/acmetool/cert/meta/main.yml b/roles/x509/acmetool/cert/meta/main.yml index 8e6ac88d..472f5a8c 100644 --- a/roles/x509/acmetool/cert/meta/main.yml +++ b/roles/x509/acmetool/cert/meta/main.yml @@ -1,3 +1,4 @@ +--- dependencies: - role: x509/acmetool/cert/prepare - role: x509/acmetool/cert/finalize diff --git a/roles/x509/static/base/tasks/main.yml b/roles/x509/static/base/tasks/main.yml new file mode 100644 index 00000000..c5b6cafe --- /dev/null +++ b/roles/x509/static/base/tasks/main.yml @@ -0,0 +1,2 @@ +--- +# nothing to do here diff --git a/roles/x509/static/cert/finalize/tasks/main.yml b/roles/x509/static/cert/finalize/tasks/main.yml new file mode 100644 index 00000000..c5b6cafe --- /dev/null +++ b/roles/x509/static/cert/finalize/tasks/main.yml @@ -0,0 +1,2 @@ +--- +# nothing to do here diff --git a/roles/x509/static/cert/meta/main.yml b/roles/x509/static/cert/meta/main.yml new file mode 100644 index 00000000..c619208c --- /dev/null +++ b/roles/x509/static/cert/meta/main.yml @@ -0,0 +1,4 @@ +--- +dependencies: + - role: x509/static/cert/prepare + - role: x509/static/cert/finalize diff --git a/roles/x509/static/cert/prepare/defaults/main.yml b/roles/x509/static/cert/prepare/defaults/main.yml new file mode 100644 index 00000000..d632a5de --- /dev/null +++ b/roles/x509/static/cert/prepare/defaults/main.yml @@ -0,0 +1,35 @@ +--- +static_cert_hostnames: "{{ x509_certificate_hostnames }}" +static_cert_name: "{{ x509_certificate_name | default(static_cert_hostnames[0]) }}" + +static_cert_base_dir: "/etc/ssl" + +# static_cert_config: +# path: "{{ static_cert_base_dir }}/{{ static_cert_name }}" +# mode: "0750" +# owner: root +# group: www-data +# key: +# mode: "0640" +# owner: root +# group: www-data +# content: | +# -----BEGIN RSA PRIVATE KEY----- +# ... +# -----END RSA PRIVATE KEY----- +# cert: +# mode: "0644" +# owner: root +# group: www-data +# content: | +# -----BEGIN CERTIFICATE----- +# ... +# -----END CERTIFICATE----- +# chain: +# mode: "0644" +# owner: root +# group: www-data +# content: | +# -----BEGIN CERTIFICATE----- +# ... +# -----END CERTIFICATE----- diff --git a/roles/x509/static/cert/prepare/tasks/main.yml b/roles/x509/static/cert/prepare/tasks/main.yml new file mode 100644 index 00000000..1327c3b3 --- /dev/null +++ b/roles/x509/static/cert/prepare/tasks/main.yml @@ -0,0 +1,81 @@ +--- +- name: compute path to static certificate directory + set_fact: + static_cert_path: "{{ static_cert_config.path | default([static_cert_base_dir, static_cert_name] | path_join) }}" + +- name: create directory for static certificate + file: + path: "{{ static_cert_path }}" + state: directory + mode: "{{ static_cert_config.mode | default('0700') }}" + owner: "{{ static_cert_config.owner | default(omit) }}" + group: "{{ static_cert_config.group | default(omit) }}" + notify: "{{ x509_notify_on_change | default(omit) }}" + +- name: install key for static certificate + copy: + content: "{{ static_cert_config.key.content }}" + dest: "{{ static_cert_path }}/{{ static_cert_name }}-key.pem" + mode: "{{ static_cert_config.key.mode | default('0600') }}" + owner: "{{ static_cert_config.key.owner | default(omit) }}" + group: "{{ static_cert_config.key.group | default(omit) }}" + notify: "{{ x509_notify_on_change | default(omit) }}" + +- name: install static certificate + copy: + content: "{{ static_cert_config.cert.content }}" + dest: "{{ static_cert_path }}/{{ static_cert_name }}-crt.pem" + mode: "{{ static_cert_config.cert.mode | default('0644') }}" + owner: "{{ static_cert_config.cert.owner | default(omit) }}" + group: "{{ static_cert_config.cert.group | default(omit) }}" + notify: "{{ x509_notify_on_change | default(omit) }}" + +- name: export paths to basic certificate files + set_fact: + x509_certificate_path_key: "{{ static_cert_path }}/{{ static_cert_name }}-key.pem" + x509_certificate_path_fullchain: "{{ static_cert_path }}/{{ static_cert_name }}-crt.pem" + x509_certificate_path_cert: "{{ static_cert_path }}/{{ static_cert_name }}-crt.pem" + +- name: install chain and fullchain for static certificate + when: "'chain' in static_cert_config" + block: + - name: install chain for static certificate + copy: + content: "{{ static_cert_config.chain.content }}" + dest: "{{ static_cert_path }}/{{ static_cert_name }}-chain.pem" + mode: "{{ static_cert_config.chain.mode | default('0644') }}" + owner: "{{ static_cert_config.chain.owner | default(omit) }}" + group: "{{ static_cert_config.chain.group | default(omit) }}" + notify: "{{ x509_notify_on_change | default(omit) }}" + + - name: install fullchain for static certificate + copy: + content: | + {{ static_cert_config.cert.content | trim }} + {{ static_cert_config.chain.content }} + dest: "{{ static_cert_path }}/{{ static_cert_name }}-fullchain.pem" + mode: "{{ static_cert_config.cert.mode | default('0644') }}" + owner: "{{ static_cert_config.cert.owner | default(omit) }}" + group: "{{ static_cert_config.cert.group | default(omit) }}" + notify: "{{ x509_notify_on_change | default(omit) }}" + + - name: export paths to additional certificate files + set_fact: + x509_certificate_path_chain: "{{ static_cert_path }}/{{ static_cert_name }}-chain.pem" + x509_certificate_path_fullchain: "{{ static_cert_path }}/{{ static_cert_name }}-fullchain.pem" + +- name: make sure chain and fullchain files are removed + when: "'chain' not in static_cert_config" + block: + - name: remove chain/fullchain files + loop: + - chain + - fullchain + file: + path: "{{ static_cert_path }}/{{ static_cert_name }}-{{ item }}.pem" + state: absent + notify: "{{ x509_notify_on_change | default(omit) }}" + + - name: make sure variable that points to the chain certificate file is unset + set_fact: + x509_certificate_path_chain: "" -- cgit v1.2.3 From 7d3f6ae25ce4a5d6e14b3ec6d95cd54165e0a646 Mon Sep 17 00:00:00 2001 From: Christian Pointner Date: Wed, 16 Aug 2023 03:33:05 +0200 Subject: add role: x509/selfsigned --- dan/sk-testvm.yml | 35 ++++++++++- roles/x509/acmetool/cert/prepare/tasks/main.yml | 2 +- roles/x509/selfsigned/base/tasks/main.yml | 5 ++ roles/x509/selfsigned/cert/finalize/tasks/main.yml | 2 + roles/x509/selfsigned/cert/meta/main.yml | 4 ++ .../x509/selfsigned/cert/prepare/defaults/main.yml | 41 +++++++++++++ roles/x509/selfsigned/cert/prepare/tasks/main.yml | 69 ++++++++++++++++++++++ 7 files changed, 154 insertions(+), 4 deletions(-) create mode 100644 roles/x509/selfsigned/base/tasks/main.yml create mode 100644 roles/x509/selfsigned/cert/finalize/tasks/main.yml create mode 100644 roles/x509/selfsigned/cert/meta/main.yml create mode 100644 roles/x509/selfsigned/cert/prepare/defaults/main.yml create mode 100644 roles/x509/selfsigned/cert/prepare/tasks/main.yml (limited to 'roles/x509') diff --git a/dan/sk-testvm.yml b/dan/sk-testvm.yml index c66601cb..de8e66ba 100644 --- a/dan/sk-testvm.yml +++ b/dan/sk-testvm.yml @@ -11,7 +11,9 @@ - name: Payload Setup hosts: sk-testvm vars: - cert_provider: static + # cert_provider: acmetool + # cert_provider: static + cert_provider: selfsigned roles: - role: "x509/{{ cert_provider }}/base" - role: nginx/base @@ -54,7 +56,21 @@ '/': root: /var/www/default index: index.html - static_cert_config: "{{ static_cert_config__default }}" + # 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 + include_role: name: nginx/vhost @@ -91,6 +107,19 @@ '/': root: /var/www/test index: index.html - static_cert_config: "{{ static_cert_config__test }}" + # 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 include_role: name: nginx/vhost diff --git a/roles/x509/acmetool/cert/prepare/tasks/main.yml b/roles/x509/acmetool/cert/prepare/tasks/main.yml index 1f7dc724..146c5ac4 100644 --- a/roles/x509/acmetool/cert/prepare/tasks/main.yml +++ b/roles/x509/acmetool/cert/prepare/tasks/main.yml @@ -36,6 +36,6 @@ - name: export paths to certificate files set_fact: x509_certificate_path_key: "/var/lib/acme/live/{{ acmetool_cert_hostnames[0] }}/privkey" - x509_certificate_path_fullchain: "/var/lib/acme/live/{{ acmetool_cert_hostnames[0] }}/fullchain" 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" diff --git a/roles/x509/selfsigned/base/tasks/main.yml b/roles/x509/selfsigned/base/tasks/main.yml new file mode 100644 index 00000000..51397d67 --- /dev/null +++ b/roles/x509/selfsigned/base/tasks/main.yml @@ -0,0 +1,5 @@ +--- +- name: install needed packages + apt: + name: "{{ python_basename }}-openssl" + state: present diff --git a/roles/x509/selfsigned/cert/finalize/tasks/main.yml b/roles/x509/selfsigned/cert/finalize/tasks/main.yml new file mode 100644 index 00000000..c5b6cafe --- /dev/null +++ b/roles/x509/selfsigned/cert/finalize/tasks/main.yml @@ -0,0 +1,2 @@ +--- +# nothing to do here diff --git a/roles/x509/selfsigned/cert/meta/main.yml b/roles/x509/selfsigned/cert/meta/main.yml new file mode 100644 index 00000000..c7a30d00 --- /dev/null +++ b/roles/x509/selfsigned/cert/meta/main.yml @@ -0,0 +1,4 @@ +--- +dependencies: + - role: x509/selfsigned/cert/prepare + - role: x509/selfsigned/cert/finalize diff --git a/roles/x509/selfsigned/cert/prepare/defaults/main.yml b/roles/x509/selfsigned/cert/prepare/defaults/main.yml new file mode 100644 index 00000000..53dc3b06 --- /dev/null +++ b/roles/x509/selfsigned/cert/prepare/defaults/main.yml @@ -0,0 +1,41 @@ +--- +selfsigned_cert_hostnames: "{{ x509_certificate_hostnames }}" +selfsigned_cert_name: "{{ x509_certificate_name | default(selfsigned_cert_hostnames[0]) }}" + +selfsigned_cert_base_dir: "/etc/ssl" + +# selfsigned_cert_config: +# path: "{{ selfsigned_cert_base_dir }}/{{ selfsigned_cert_name }}" +# mode: "0750" +# owner: root +# group: www-data +# key: +# mode: "0640" +# owner: root +# group: www-data +# type: RSA +# size: 4096 +# cert: +# mode: "0644" +# owner: root +# group: www-data +# country_name: "AT" +# locality_name: "Graz" +# organization_name: "spreadspace" +# organizational_unit_name: "ansible" +# state_or_province_name: "Styria" +# basic_constraints: +# - "CA:TRUE" +# - "pathLenConstraint:0" +# basic_constraints_critical: no +# key_usage: +# - digitalSignature +# - keyAgreement +# key_usage_critical: yes +# extended_key_usage: +# - serverAuth +# extended_key_usage_critical: yes +# create_subject_key_identifier: yes +# digest: SHA256 +# not_before: +0h +# not_after: +520w diff --git a/roles/x509/selfsigned/cert/prepare/tasks/main.yml b/roles/x509/selfsigned/cert/prepare/tasks/main.yml new file mode 100644 index 00000000..c089d420 --- /dev/null +++ b/roles/x509/selfsigned/cert/prepare/tasks/main.yml @@ -0,0 +1,69 @@ +--- +- name: compute path to selfsigned certificate directory + set_fact: + selfsigned_cert_path: "{{ selfsigned_cert_config.path | default([selfsigned_cert_base_dir, selfsigned_cert_name] | path_join) }}" + +- name: create directory for selfsigned certificate + file: + path: "{{ selfsigned_cert_path }}" + state: directory + mode: "{{ selfsigned_cert_config.mode | default('0700') }}" + owner: "{{ selfsigned_cert_config.owner | default(omit) }}" + group: "{{ selfsigned_cert_config.group | default(omit) }}" + notify: "{{ x509_notify_on_change | default(omit) }}" + +- name: generate key for selfsigned certificate + openssl_privatekey: + path: "{{ selfsigned_cert_path }}/{{ selfsigned_cert_name }}-key.pem" + mode: "{{ selfsigned_cert_config.key.mode | default('0600') }}" + owner: "{{ selfsigned_cert_config.key.owner | default(omit) }}" + group: "{{ selfsigned_cert_config.key.group | default(omit) }}" + type: "{{ selfsigned_cert_config.key.type | default(omit) }}" + size: "{{ selfsigned_cert_config.key.size | default(omit) }}" + notify: "{{ x509_notify_on_change | default(omit) }}" + +- 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') }}" + 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" + create_subject_key_identifier: "{{ selfsigned_cert_config.cert.create_subject_key_identifier | default(omit) }}" + digest: "{{ selfsigned_cert_config.cert.digest | default(omit) }}" + common_name: "{{ selfsigned_cert_name }}" + subject_alt_name: "{{ ['DNS:'] | product(selfsigned_cert_hostnames) | map('join') | list }}" + subject_alt_name_critical: yes + use_common_name_for_san: no + country_name: "{{ selfsigned_cert_config.cert.country_name | default(omit) }}" + locality_name: "{{ selfsigned_cert_config.cert.locality_name | default(omit) }}" + organization_name: "{{ selfsigned_cert_config.cert.organization_name | default(omit) }}" + organizational_unit_name: "{{ selfsigned_cert_config.cert.organizational_unit_name | default(omit) }}" + state_or_province_name: "{{ selfsigned_cert_config.cert.state_or_province_name | default(omit) }}" + basic_constraints: "{{ selfsigned_cert_config.cert.basic_constraints | default(omit) }}" + basic_constraints_critical: "{{ selfsigned_cert_config.cert.basic_constraints_critical | default(omit) }}" + key_usage: "{{ selfsigned_cert_config.cert.key_usage | default(omit) }}" + key_usage_critical: "{{ selfsigned_cert_config.cert.key_usage_critical | default(omit) }}" + extended_key_usage: "{{ selfsigned_cert_config.cert.extended_key_usage | default(omit) }}" + extended_key_usage_critical: "{{ selfsigned_cert_config.cert.extended_key_usage_critical | default(omit) }}" + +- name: generate selfsigned certificate + community.crypto.x509_certificate: + path: "{{ selfsigned_cert_path }}/{{ selfsigned_cert_name }}-crt.pem" + 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" + csr_path: "{{ selfsigned_cert_path }}/{{ selfsigned_cert_name }}-csr.pem" + provider: selfsigned + selfsigned_digest: "{{ selfsigned_cert_config.cert.digest | default(omit) }}" + selfsigned_not_before: "{{ selfsigned_cert_config.cert.not_before | default(omit) }}" + selfsigned_not_after: "{{ selfsigned_cert_config.cert.not_after | default(omit) }}" + notify: "{{ x509_notify_on_change | default(omit) }}" + +- name: export paths to certificate files + set_fact: + x509_certificate_path_key: "{{ selfsigned_cert_path }}/{{ selfsigned_cert_name }}-key.pem" + x509_certificate_path_cert: "{{ selfsigned_cert_path }}/{{ selfsigned_cert_name }}-crt.pem" + x509_certificate_path_chain: "" + x509_certificate_path_fullchain: "{{ selfsigned_cert_path }}/{{ selfsigned_cert_name }}-crt.pem" -- cgit v1.2.3 From 5756978238ad7b7f2fe8dc46d511cfbd5245c0c3 Mon Sep 17 00:00:00 2001 From: Christian Pointner Date: Wed, 16 Aug 2023 23:38:07 +0200 Subject: uacme roles almost done --- dan/sk-testvm.yml | 59 ++++++++------- roles/nginx/vhost/templates/generic.conf.j2 | 8 +- roles/x509/selfsigned/cert/prepare/tasks/main.yml | 2 +- roles/x509/uacme/base/defaults/main.yml | 2 + roles/x509/uacme/base/tasks/main.yml | 11 ++- roles/x509/uacme/base/tasks/selfsigned.yml | 47 ------------ .../uacme/base/templates/uacme-reconcile.sh.j2 | 32 ++++++++ roles/x509/uacme/cert/finalize/defaults/main.yml | 3 + roles/x509/uacme/cert/finalize/tasks/main.yml | 5 ++ roles/x509/uacme/cert/meta/main.yml | 4 + roles/x509/uacme/cert/prepare/defaults/main.yml | 15 ++++ roles/x509/uacme/cert/prepare/tasks/main.yml | 88 ++++++++++++++++++++++ 12 files changed, 191 insertions(+), 85 deletions(-) delete mode 100644 roles/x509/uacme/base/tasks/selfsigned.yml create mode 100644 roles/x509/uacme/base/templates/uacme-reconcile.sh.j2 create mode 100644 roles/x509/uacme/cert/finalize/defaults/main.yml create mode 100644 roles/x509/uacme/cert/finalize/tasks/main.yml create mode 100644 roles/x509/uacme/cert/meta/main.yml create mode 100644 roles/x509/uacme/cert/prepare/defaults/main.yml create mode 100644 roles/x509/uacme/cert/prepare/tasks/main.yml (limited to 'roles/x509') 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: :base64() 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" -- cgit v1.2.3 From 775492cc28346ea86396a947e1371b8aa0784380 Mon Sep 17 00:00:00 2001 From: Christian Pointner Date: Thu, 17 Aug 2023 00:23:01 +0200 Subject: revamp x509 service reloading --- roles/nginx/vhost/tasks/main.yml | 16 +++++++++------- roles/x509/acmetool/cert/prepare/handlers/main.yml | 6 ++++++ roles/x509/acmetool/cert/prepare/tasks/main.yml | 1 + roles/x509/selfsigned/cert/prepare/handlers/main.yml | 6 ++++++ roles/x509/selfsigned/cert/prepare/tasks/main.yml | 6 +++--- roles/x509/static/cert/prepare/handlers/main.yml | 6 ++++++ roles/x509/static/cert/prepare/tasks/main.yml | 12 ++++++------ roles/x509/uacme/base/templates/uacme-reconcile.sh.j2 | 6 +++--- roles/x509/uacme/cert/prepare/handlers/main.yml | 6 ++++++ roles/x509/uacme/cert/prepare/tasks/main.yml | 14 ++++++++++---- roles/x509/uacme/cert/prepare/templates/updated.sh.j2 | 17 +++++++++++++++++ 11 files changed, 73 insertions(+), 23 deletions(-) create mode 100644 roles/x509/acmetool/cert/prepare/handlers/main.yml create mode 100644 roles/x509/selfsigned/cert/prepare/handlers/main.yml create mode 100644 roles/x509/static/cert/prepare/handlers/main.yml create mode 100644 roles/x509/uacme/cert/prepare/handlers/main.yml create mode 100644 roles/x509/uacme/cert/prepare/templates/updated.sh.j2 (limited to 'roles/x509') diff --git a/roles/nginx/vhost/tasks/main.yml b/roles/nginx/vhost/tasks/main.yml index 55544733..2c1f0f29 100644 --- a/roles/nginx/vhost/tasks/main.yml +++ b/roles/nginx/vhost/tasks/main.yml @@ -1,13 +1,14 @@ --- - name: ensure certificate exists (fake it, until you make it) when: "'tls' in nginx_vhost" - include_role: - name: "x509/{{ nginx_vhost.tls.certificate_provider }}/cert/prepare" - public: true vars: x509_certificate_name: "{{ nginx_vhost.name }}" x509_certificate_hostnames: "{{ nginx_vhost.hostnames }}" - x509_notify_on_change: reload nginx + x509_certificate_reload_services: + - nginx + include_role: + name: "x509/{{ nginx_vhost.tls.certificate_provider }}/cert/prepare" + public: true - name: install nginx configs from template when: "'template' in nginx_vhost" @@ -39,9 +40,10 @@ meta: flush_handlers - name: actually request the certificate - include_role: - name: "x509/{{ nginx_vhost.tls.certificate_provider }}/cert/finalize" vars: x509_certificate_name: "{{ nginx_vhost.name }}" x509_certificate_hostnames: "{{ nginx_vhost.hostnames }}" - x509_notify_on_change: reload nginx + x509_certificate_reload_services: + - nginx + include_role: + name: "x509/{{ nginx_vhost.tls.certificate_provider }}/cert/finalize" 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..b169d6ca --- /dev/null +++ b/roles/x509/acmetool/cert/prepare/handlers/main.yml @@ -0,0 +1,6 @@ +--- +- 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 index 146c5ac4..5bad1e5b 100644 --- a/roles/x509/acmetool/cert/prepare/tasks/main.yml +++ b/roles/x509/acmetool/cert/prepare/tasks/main.yml @@ -32,6 +32,7 @@ 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: diff --git a/roles/x509/selfsigned/cert/prepare/handlers/main.yml b/roles/x509/selfsigned/cert/prepare/handlers/main.yml new file mode 100644 index 00000000..b169d6ca --- /dev/null +++ b/roles/x509/selfsigned/cert/prepare/handlers/main.yml @@ -0,0 +1,6 @@ +--- +- name: reload services for x509 certificates + loop: "{{ x509_certificate_reload_services | default([]) }}" + service: + name: "{{ item }}" + state: reloaded diff --git a/roles/x509/selfsigned/cert/prepare/tasks/main.yml b/roles/x509/selfsigned/cert/prepare/tasks/main.yml index 1af6ef5e..e7a47742 100644 --- a/roles/x509/selfsigned/cert/prepare/tasks/main.yml +++ b/roles/x509/selfsigned/cert/prepare/tasks/main.yml @@ -10,7 +10,7 @@ mode: "{{ selfsigned_cert_config.mode | default('0700') }}" owner: "{{ selfsigned_cert_config.owner | default(omit) }}" group: "{{ selfsigned_cert_config.group | default(omit) }}" - notify: "{{ x509_notify_on_change | default(omit) }}" + notify: reload services for x509 certificates - name: generate key for selfsigned certificate openssl_privatekey: @@ -20,7 +20,7 @@ group: "{{ selfsigned_cert_config.key.group | default(omit) }}" type: "{{ selfsigned_cert_config.key.type | default(omit) }}" size: "{{ selfsigned_cert_config.key.size | default(omit) }}" - notify: "{{ x509_notify_on_change | default(omit) }}" + notify: reload services for x509 certificates - name: generate csr for selfsigned certificate community.crypto.openssl_csr: @@ -59,7 +59,7 @@ selfsigned_digest: "{{ selfsigned_cert_config.cert.digest | default(omit) }}" selfsigned_not_before: "{{ selfsigned_cert_config.cert.not_before | default(omit) }}" selfsigned_not_after: "{{ selfsigned_cert_config.cert.not_after | default(omit) }}" - notify: "{{ x509_notify_on_change | default(omit) }}" + notify: reload services for x509 certificates - name: export paths to certificate files set_fact: diff --git a/roles/x509/static/cert/prepare/handlers/main.yml b/roles/x509/static/cert/prepare/handlers/main.yml new file mode 100644 index 00000000..b169d6ca --- /dev/null +++ b/roles/x509/static/cert/prepare/handlers/main.yml @@ -0,0 +1,6 @@ +--- +- name: reload services for x509 certificates + loop: "{{ x509_certificate_reload_services | default([]) }}" + service: + name: "{{ item }}" + state: reloaded diff --git a/roles/x509/static/cert/prepare/tasks/main.yml b/roles/x509/static/cert/prepare/tasks/main.yml index 1327c3b3..03df7542 100644 --- a/roles/x509/static/cert/prepare/tasks/main.yml +++ b/roles/x509/static/cert/prepare/tasks/main.yml @@ -10,7 +10,7 @@ mode: "{{ static_cert_config.mode | default('0700') }}" owner: "{{ static_cert_config.owner | default(omit) }}" group: "{{ static_cert_config.group | default(omit) }}" - notify: "{{ x509_notify_on_change | default(omit) }}" + notify: reload services for x509 certificates - name: install key for static certificate copy: @@ -19,7 +19,7 @@ mode: "{{ static_cert_config.key.mode | default('0600') }}" owner: "{{ static_cert_config.key.owner | default(omit) }}" group: "{{ static_cert_config.key.group | default(omit) }}" - notify: "{{ x509_notify_on_change | default(omit) }}" + notify: reload services for x509 certificates - name: install static certificate copy: @@ -28,7 +28,7 @@ mode: "{{ static_cert_config.cert.mode | default('0644') }}" owner: "{{ static_cert_config.cert.owner | default(omit) }}" group: "{{ static_cert_config.cert.group | default(omit) }}" - notify: "{{ x509_notify_on_change | default(omit) }}" + notify: reload services for x509 certificates - name: export paths to basic certificate files set_fact: @@ -46,7 +46,7 @@ mode: "{{ static_cert_config.chain.mode | default('0644') }}" owner: "{{ static_cert_config.chain.owner | default(omit) }}" group: "{{ static_cert_config.chain.group | default(omit) }}" - notify: "{{ x509_notify_on_change | default(omit) }}" + notify: reload services for x509 certificates - name: install fullchain for static certificate copy: @@ -57,7 +57,7 @@ mode: "{{ static_cert_config.cert.mode | default('0644') }}" owner: "{{ static_cert_config.cert.owner | default(omit) }}" group: "{{ static_cert_config.cert.group | default(omit) }}" - notify: "{{ x509_notify_on_change | default(omit) }}" + notify: reload services for x509 certificates - name: export paths to additional certificate files set_fact: @@ -74,7 +74,7 @@ file: path: "{{ static_cert_path }}/{{ static_cert_name }}-{{ item }}.pem" state: absent - notify: "{{ x509_notify_on_change | default(omit) }}" + notify: reload services for x509 certificates - name: make sure variable that points to the chain certificate file is unset set_fact: diff --git a/roles/x509/uacme/base/templates/uacme-reconcile.sh.j2 b/roles/x509/uacme/base/templates/uacme-reconcile.sh.j2 index 73a7f4a3..ea02841d 100644 --- a/roles/x509/uacme/base/templates/uacme-reconcile.sh.j2 +++ b/roles/x509/uacme/base/templates/uacme-reconcile.sh.j2 @@ -16,9 +16,9 @@ for csr_file in "${csr_files[@]}"; do 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 + if [ -x "/var/lib/uacme.d/$id/updated.sh" ]; then + /var/lib/uacme.d/$id/updated.sh + fi ;; 1) echo "$id not updated." diff --git a/roles/x509/uacme/cert/prepare/handlers/main.yml b/roles/x509/uacme/cert/prepare/handlers/main.yml new file mode 100644 index 00000000..b169d6ca --- /dev/null +++ b/roles/x509/uacme/cert/prepare/handlers/main.yml @@ -0,0 +1,6 @@ +--- +- name: reload services for x509 certificates + loop: "{{ x509_certificate_reload_services | default([]) }}" + service: + name: "{{ item }}" + state: reloaded diff --git a/roles/x509/uacme/cert/prepare/tasks/main.yml b/roles/x509/uacme/cert/prepare/tasks/main.yml index 06b9f146..426a5eee 100644 --- a/roles/x509/uacme/cert/prepare/tasks/main.yml +++ b/roles/x509/uacme/cert/prepare/tasks/main.yml @@ -12,7 +12,7 @@ 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) }}" + notify: reload services for x509 certificates - name: generate csr for uacme-controlled certificate community.crypto.openssl_csr: @@ -60,7 +60,7 @@ selfsigned_not_after: "{{ remote_datetime_now.stdout }}" return_content: yes register: uacme_cert_selfsigned - notify: "{{ x509_notify_on_change | default(omit) }}" + notify: reload services for x509 certificates - name: make sure cert-only file exists copy: @@ -69,7 +69,7 @@ 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) }}" + notify: reload services for x509 certificates - name: make sure the chain file exists copy: @@ -78,7 +78,13 @@ 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) }}" + notify: reload services for x509 certificates + +- name: install script to be called when new certificate is generated + template: + src: updated.sh.j2 + dest: "/var/lib/uacme.d/{{ uacme_cert_name }}/updated.sh" + mode: 0755 - name: export paths to certificate files set_fact: diff --git a/roles/x509/uacme/cert/prepare/templates/updated.sh.j2 b/roles/x509/uacme/cert/prepare/templates/updated.sh.j2 new file mode 100644 index 00000000..b0fa705a --- /dev/null +++ b/roles/x509/uacme/cert/prepare/templates/updated.sh.j2 @@ -0,0 +1,17 @@ +#!/bin/sh + +# split fullchain and fix permissions +awk '{if(length($0) > 0) print} /-----END CERTIFICATE-----/ { exit }' "/var/lib/uacme.d/{{ uacme_cert_name }}/{{ uacme_cert_name }}-cert.pem" > "/var/lib/uacme.d/{{ uacme_cert_name }}/crt.pem" +awk '(show==1) {if(length($0) > 0) print} /-----END CERTIFICATE-----/ { show=1 }' "/var/lib/uacme.d/{{ uacme_cert_name }}/{{ uacme_cert_name }}-cert.pem" > "/var/lib/uacme.d/{{ uacme_cert_name }}/chain.pem" +chmod "{{ uacme_cert_config.cert.mode | default('0644') }}" /var/lib/uacme.d/{{ uacme_cert_name }}/{{ uacme_cert_name }}-cert.pem /var/lib/uacme.d/{{ uacme_cert_name }}/crt.pem /var/lib/uacme.d/{{ uacme_cert_name }}/chain.pem +{% if uacme_cert_config.cert.owner is defined %} +chown "{{ uacme_cert_config.cert.owner }}" /var/lib/uacme.d/{{ uacme_cert_name }}/{{ uacme_cert_name }}-cert.pem /var/lib/uacme.d/{{ uacme_cert_name }}/crt.pem /var/lib/uacme.d/{{ uacme_cert_name }}/chain.pem +{% endif %} +{% if uacme_cert_config.cert.group is defined %} +chgrp "{{ uacme_cert_config.cert.group }}" /var/lib/uacme.d/{{ uacme_cert_name }}/{{ uacme_cert_name }}-cert.pem /var/lib/uacme.d/{{ uacme_cert_name }}/crt.pem /var/lib/uacme.d/{{ uacme_cert_name }}/chain.pem +{% endif %} + +## reload services +{% for service in (x509_certificate_reload_services | default([])) %} +systemctl reload "{{ service }}.service" +{% endfor %} -- cgit v1.2.3 From 2ae1b55727449c61b320703a11bc622ec76b579a Mon Sep 17 00:00:00 2001 From: Christian Pointner Date: Thu, 17 Aug 2023 00:38:13 +0200 Subject: uacme: add automatic refresh timer/service --- roles/x509/uacme/base/tasks/main.yml | 15 ++++++++++++++- .../uacme/base/templates/uacme-reconcile.service.j2 | 18 ++++++++++++++++++ .../x509/uacme/base/templates/uacme-reconcile.timer.j2 | 10 ++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 roles/x509/uacme/base/templates/uacme-reconcile.service.j2 create mode 100644 roles/x509/uacme/base/templates/uacme-reconcile.timer.j2 (limited to 'roles/x509') diff --git a/roles/x509/uacme/base/tasks/main.yml b/roles/x509/uacme/base/tasks/main.yml index 9d67e0e7..17e6034f 100644 --- a/roles/x509/uacme/base/tasks/main.yml +++ b/roles/x509/uacme/base/tasks/main.yml @@ -50,4 +50,17 @@ dest: /usr/local/bin/uacme-reconcile.sh mode: 0755 -## TODO: add systemd units for automatic refreshing +- name: install systemd unit for automatic refresh + loop: + - service + - timer + template: + src: "uacme-reconcile.{{ item }}.j2" + dest: "/etc/systemd/system/uacme-reconcile.{{ item }}" + +- 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/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.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 -- cgit v1.2.3 From 70e61b9184dfa81a39926e66722ed3c1743a91c3 Mon Sep 17 00:00:00 2001 From: Christian Pointner Date: Mon, 21 Aug 2023 00:38:34 +0200 Subject: apps/mumble: add new generic certificate renewal support --- roles/apps/mumble/tasks/main.yml | 55 ++++++++++------------ roles/apps/mumble/templates/acmetool-reload.sh.j2 | 28 ----------- .../x509/acmetool/cert/finalize/handlers/main.yml | 1 + roles/x509/acmetool/cert/prepare/handlers/main.yml | 4 ++ roles/x509/acmetool/cert/prepare/tasks/main.yml | 37 +++++++++++++++ .../acmetool/cert/prepare/templates/reload.sh.j2 | 31 ++++++++++++ 6 files changed, 98 insertions(+), 58 deletions(-) delete mode 100644 roles/apps/mumble/templates/acmetool-reload.sh.j2 create mode 100644 roles/x509/acmetool/cert/prepare/templates/reload.sh.j2 (limited to 'roles/x509') diff --git a/roles/apps/mumble/tasks/main.yml b/roles/apps/mumble/tasks/main.yml index 5cd1f7a9..b59fb5fc 100644 --- a/roles/apps/mumble/tasks/main.yml +++ b/roles/apps/mumble/tasks/main.yml @@ -1,10 +1,4 @@ --- -- name: check if acme_client is set to acmetool - assert: - msg: "this role currently only works with acmetool" - that: - - mumble_tls.certificate_provider == "acmetool" - - name: add group for mumble group: name: mumble @@ -33,31 +27,32 @@ group: mumble mode: 0644 -- name: install acmetool hook script - template: - src: acmetool-reload.sh.j2 - dest: "/etc/acme/hooks/mumble-{{ mumble_instance }}" - mode: 0755 - -- name: install acmetool systemd unit snippet - copy: - dest: "/etc/systemd/system/acmetool.service.d/mumble-{{ mumble_instance }}.conf" - content: | - [Service] - ReadWritePaths={{ mumble_base_path }}/{{ mumble_instance }}/ssl - register: mumble_acmetool_snippet - -- name: reload systemd - when: mumble_acmetool_snippet is changed - systemd: - daemon_reload: yes - -- name: get certificate using acmetool - import_role: - name: x509/acmetool/cert +- name: generate/install/fetc TLS certificate vars: - acmetool_cert_name: "mumble-{{ mumble_instance }}" - acmetool_cert_hostnames: "{{ mumble_hostnames }}" + x509_certificate_name: "mumble-{{ mumble_instance }}" + x509_certificate_hostnames: "{{ mumble_hostnames }}" + x509_certificate_renewal: + install: + - dest: "{{ mumble_base_path }}/{{ mumble_instance }}/ssl/cert.pem" + src: + - fullchain + owner: root + group: mumble + mode: "0644" + - dest: "{{ mumble_base_path }}/{{ mumble_instance }}/ssl/privkey.pem" + src: + - key + owner: root + group: mumble + mode: "0640" + reload: | + pod_id=$(crictl pods -q --state ready --name "^mumble-{{ mumble_instance }}-{{ ansible_nodename }}$") + [ -n "$pod_id" ] || exit 42 + container_id=$(crictl ps -q --name '^mumble$' -p "$pod_id") + [ -n "$container_id" ] || exit 42 + crictl exec "$container_id" kill -USR1 1 + include_role: + name: "x509/{{ mumble_tls.certificate_provider }}/cert" - name: create mumble data directory file: diff --git a/roles/apps/mumble/templates/acmetool-reload.sh.j2 b/roles/apps/mumble/templates/acmetool-reload.sh.j2 deleted file mode 100644 index fd9f01ba..00000000 --- a/roles/apps/mumble/templates/acmetool-reload.sh.j2 +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh -set -e -EVENT_NAME="$1" -[ "$EVENT_NAME" = "live-updated" ] || exit 42 - -MAIN_HOSTNAME="{{ mumble_hostnames[0] }}" -SSL_D="{{ mumble_base_path }}/{{ mumble_instance }}/ssl" - -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 - - install -m 0644 -o root -g mumble "$certdir/fullchain" "$SSL_D/cert.pem" - install -m 0640 -o root -g mumble "$certdir/privkey" "$SSL_D/privkey.pem" - - pod_id=$(crictl pods -q --state ready --name "^mumble-{{ mumble_instance }}-{{ ansible_nodename }}$") - [ -n "$pod_id" ] || exit 42 - container_id=$(crictl ps -q --name '^mumble$' -p "$pod_id") - [ -n "$container_id" ] || exit 42 - crictl exec "$container_id" kill -USR1 1 - - break -done diff --git a/roles/x509/acmetool/cert/finalize/handlers/main.yml b/roles/x509/acmetool/cert/finalize/handlers/main.yml index a7fc43ed..02ffa598 100644 --- a/roles/x509/acmetool/cert/finalize/handlers/main.yml +++ b/roles/x509/acmetool/cert/finalize/handlers/main.yml @@ -2,5 +2,6 @@ - name: reconcile acmetool when: not acmetool_reconcile_disabled systemd: + daemon_reload: yes name: acmetool.service state: started diff --git a/roles/x509/acmetool/cert/prepare/handlers/main.yml b/roles/x509/acmetool/cert/prepare/handlers/main.yml index b169d6ca..330bcd11 100644 --- a/roles/x509/acmetool/cert/prepare/handlers/main.yml +++ b/roles/x509/acmetool/cert/prepare/handlers/main.yml @@ -1,4 +1,8 @@ --- +- name: reload systemd + systemd: + daemon_reload: yes + - name: reload services for x509 certificates loop: "{{ x509_certificate_reload_services | default([]) }}" service: diff --git a/roles/x509/acmetool/cert/prepare/tasks/main.yml b/roles/x509/acmetool/cert/prepare/tasks/main.yml index 5bad1e5b..2db332b8 100644 --- a/roles/x509/acmetool/cert/prepare/tasks/main.yml +++ b/roles/x509/acmetool/cert/prepare/tasks/main.yml @@ -40,3 +40,40 @@ 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 -- cgit v1.2.3 From f2d4ce732249e8711fc807fecd25d8c43a88175c Mon Sep 17 00:00:00 2001 From: Christian Pointner Date: Mon, 21 Aug 2023 01:02:51 +0200 Subject: x509/uacme: add support for special renewal actions --- dan/sk-testvm.yml | 4 +-- roles/x509/uacme/base/tasks/main.yml | 5 ++++ roles/x509/uacme/cert/prepare/handlers/main.yml | 4 +++ roles/x509/uacme/cert/prepare/tasks/main.yml | 30 +++++++++++++++++----- .../uacme/cert/prepare/templates/updated.sh.j2 | 26 +++++++++++++++---- 5 files changed, 56 insertions(+), 13 deletions(-) (limited to 'roles/x509') diff --git a/dan/sk-testvm.yml b/dan/sk-testvm.yml index 698eb7de..70b6f336 100644 --- a/dan/sk-testvm.yml +++ b/dan/sk-testvm.yml @@ -11,8 +11,8 @@ - name: Payload Setup hosts: sk-testvm vars: - # acme_client: uacme - acme_client: acmetool + acme_client: uacme + # acme_client: acmetool cert_provider: "{{ acme_client }}" # cert_provider: static # cert_provider: selfsigned diff --git a/roles/x509/uacme/base/tasks/main.yml b/roles/x509/uacme/base/tasks/main.yml index 17e6034f..3473d541 100644 --- a/roles/x509/uacme/base/tasks/main.yml +++ b/roles/x509/uacme/base/tasks/main.yml @@ -58,6 +58,11 @@ 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 diff --git a/roles/x509/uacme/cert/prepare/handlers/main.yml b/roles/x509/uacme/cert/prepare/handlers/main.yml index b169d6ca..330bcd11 100644 --- a/roles/x509/uacme/cert/prepare/handlers/main.yml +++ b/roles/x509/uacme/cert/prepare/handlers/main.yml @@ -1,4 +1,8 @@ --- +- name: reload systemd + systemd: + daemon_reload: yes + - name: reload services for x509 certificates loop: "{{ x509_certificate_reload_services | default([]) }}" service: diff --git a/roles/x509/uacme/cert/prepare/tasks/main.yml b/roles/x509/uacme/cert/prepare/tasks/main.yml index 426a5eee..a83651b3 100644 --- a/roles/x509/uacme/cert/prepare/tasks/main.yml +++ b/roles/x509/uacme/cert/prepare/tasks/main.yml @@ -80,15 +80,33 @@ group: "{{ uacme_cert_config.cert.group | default(omit) }}" notify: reload services for x509 certificates -- name: install script to be called when new certificate is generated - template: - src: updated.sh.j2 - dest: "/var/lib/uacme.d/{{ uacme_cert_name }}/updated.sh" - mode: 0755 - - 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" + +- name: install script to be called when new certificate is generated + template: + src: updated.sh.j2 + dest: "/var/lib/uacme.d/{{ uacme_cert_name }}/updated.sh" + mode: 0755 + +- name: install systemd unit snippet + when: "x509_certificate_renewal is defined and 'install' in x509_certificate_renewal" + copy: + dest: "/etc/systemd/system/uacme-reconcile.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 systemd unit snippet + when: "x509_certificate_renewal is undefined or 'install' not in x509_certificate_renewal" + file: + path: "/etc/systemd/system/uacme-reconcile.service.d/{{ x509_certificate_name }}.conf" + state: absent + notify: reload systemd diff --git a/roles/x509/uacme/cert/prepare/templates/updated.sh.j2 b/roles/x509/uacme/cert/prepare/templates/updated.sh.j2 index b0fa705a..275ca189 100644 --- a/roles/x509/uacme/cert/prepare/templates/updated.sh.j2 +++ b/roles/x509/uacme/cert/prepare/templates/updated.sh.j2 @@ -1,17 +1,33 @@ #!/bin/sh +BASE_D="/var/lib/uacme.d/{{ uacme_cert_name }}" + # split fullchain and fix permissions -awk '{if(length($0) > 0) print} /-----END CERTIFICATE-----/ { exit }' "/var/lib/uacme.d/{{ uacme_cert_name }}/{{ uacme_cert_name }}-cert.pem" > "/var/lib/uacme.d/{{ uacme_cert_name }}/crt.pem" -awk '(show==1) {if(length($0) > 0) print} /-----END CERTIFICATE-----/ { show=1 }' "/var/lib/uacme.d/{{ uacme_cert_name }}/{{ uacme_cert_name }}-cert.pem" > "/var/lib/uacme.d/{{ uacme_cert_name }}/chain.pem" -chmod "{{ uacme_cert_config.cert.mode | default('0644') }}" /var/lib/uacme.d/{{ uacme_cert_name }}/{{ uacme_cert_name }}-cert.pem /var/lib/uacme.d/{{ uacme_cert_name }}/crt.pem /var/lib/uacme.d/{{ uacme_cert_name }}/chain.pem +awk '{if(length($0) > 0) print} /-----END CERTIFICATE-----/ { exit }' "$BASE_D/{{ uacme_cert_name }}-cert.pem" > "$BASE_D/crt.pem" +awk '(show==1) {if(length($0) > 0) print} /-----END CERTIFICATE-----/ { show=1 }' "$BASE_D/{{ uacme_cert_name }}-cert.pem" > "$BASE_D/chain.pem" +chmod "{{ uacme_cert_config.cert.mode | default('0644') }}" $BASE_D/{{ uacme_cert_name }}-cert.pem $BASE_D/crt.pem $BASE_D/chain.pem {% if uacme_cert_config.cert.owner is defined %} -chown "{{ uacme_cert_config.cert.owner }}" /var/lib/uacme.d/{{ uacme_cert_name }}/{{ uacme_cert_name }}-cert.pem /var/lib/uacme.d/{{ uacme_cert_name }}/crt.pem /var/lib/uacme.d/{{ uacme_cert_name }}/chain.pem +chown "{{ uacme_cert_config.cert.owner }}" $BASE_D/{{ uacme_cert_name }}-cert.pem $BASE_D/crt.pem $BASE_D/chain.pem {% endif %} {% if uacme_cert_config.cert.group is defined %} -chgrp "{{ uacme_cert_config.cert.group }}" /var/lib/uacme.d/{{ uacme_cert_name }}/{{ uacme_cert_name }}-cert.pem /var/lib/uacme.d/{{ uacme_cert_name }}/crt.pem /var/lib/uacme.d/{{ uacme_cert_name }}/chain.pem +chgrp "{{ uacme_cert_config.cert.group }}" $BASE_D/{{ uacme_cert_name }}-cert.pem $BASE_D/crt.pem $BASE_D/chain.pem +{% endif %} +{% if x509_certificate_renewal is defined and '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 %} ## reload services {% for service in (x509_certificate_reload_services | default([])) %} systemctl reload "{{ service }}.service" {% endfor %} +{% if x509_certificate_renewal is defined and 'reload' in x509_certificate_renewal %} + +{{ x509_certificate_renewal.reload | trim }} +{% endif %} -- cgit v1.2.3