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/prepare/tasks/main.yml | 41 +++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 roles/x509/acmetool/cert/prepare/tasks/main.yml (limited to 'roles/x509/acmetool/cert/prepare/tasks') 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" -- 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/acmetool/cert/prepare/tasks') 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 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/acmetool/cert/prepare/tasks') 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 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/acmetool/cert/prepare/tasks') 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