From 18e0446c9c545f396d7737b406e6e207748e7926 Mon Sep 17 00:00:00 2001 From: Christian Pointner Date: Thu, 22 Dec 2022 13:01:30 +0100 Subject: move acmetool to new x509 subdir --- roles/x509/acmetool/base/tasks/main.yml | 65 ++++++++++++ roles/x509/acmetool/base/tasks/selfsigned.yml | 145 ++++++++++++++++++++++++++ 2 files changed, 210 insertions(+) create mode 100644 roles/x509/acmetool/base/tasks/main.yml create mode 100644 roles/x509/acmetool/base/tasks/selfsigned.yml (limited to 'roles/x509/acmetool/base/tasks') diff --git a/roles/x509/acmetool/base/tasks/main.yml b/roles/x509/acmetool/base/tasks/main.yml new file mode 100644 index 00000000..5f2ae4ab --- /dev/null +++ b/roles/x509/acmetool/base/tasks/main.yml @@ -0,0 +1,65 @@ +--- +- name: check if acmetool package is new enough + ansible.builtin.debug: + msg: "Check distribution_release" + failed_when: (ansible_distribution == 'Debian' and (ansible_distribution_major_version | int) < 9) or (ansible_distribution == 'Ubuntu' and (ansible_distribution_major_version | int) < 17) or (ansible_distribution != 'Debian' and ansible_distribution != 'Ubuntu') + +- name: install needed packages + ansible.builtin.apt: + name: + - acmetool + - "{{ python_basename }}-openssl" + state: present + +- name: create initial directory structure + ansible.builtin.command: acmetool --batch + args: + creates: /var/lib/acme/conf + +- name: create acmetool response file + ansible.builtin.template: + src: responses.j2 + dest: /var/lib/acme/conf/responses + +- name: create non-standard acmetool webroot path + ansible.builtin.file: + name: "{{ acmetool_challenge_webroot_path }}" + state: directory + when: acmetool_challenge_webroot_path is defined + +- name: run quickstart to create account and default target configuration + ansible.builtin.command: acmetool --batch quickstart + environment: + http_proxy: "{{ acmetool_http_proxy | default('') }}" + https_proxy: "{{ acmetool_https_proxy | default('') }}" + args: + creates: /var/lib/acme/conf/target + +- name: generate selfsigned interim certificate + ansible.builtin.include_tasks: selfsigned.yml + +- name: install service reload configuration + ansible.builtin.template: + src: acme-reload.j2 + dest: /etc/default/acme-reload + owner: root + group: root + mode: 0644 + when: acmetool_reload_services is defined + +- name: create system unit snippet directory + ansible.builtin.file: + path: /etc/systemd/system/acmetool.service.d/ + state: directory + +- name: install systemd unit snippet + ansible.builtin.template: + src: systemd-override.conf.j2 + dest: /etc/systemd/system/acmetool.service.d/override.conf + +- name: enable/start systemd timer for acmetool + ansible.builtin.systemd: + name: acmetool.timer + state: started + enabled: yes + daemon_reload: yes diff --git a/roles/x509/acmetool/base/tasks/selfsigned.yml b/roles/x509/acmetool/base/tasks/selfsigned.yml new file mode 100644 index 00000000..449fbdb9 --- /dev/null +++ b/roles/x509/acmetool/base/tasks/selfsigned.yml @@ -0,0 +1,145 @@ +--- +- name: get id of existing selfsigned interim certificate + ansible.builtin.shell: cat /var/lib/acme/.selfsigned-interim-cert || true + changed_when: false + check_mode: false + register: existing_selfsigned_interim_cert_id + +- name: set existing_selfsigned_interim_cert_id variable + ansible.builtin.set_fact: + existing_selfsigned_interim_cert_id: "{{ existing_selfsigned_interim_cert_id.stdout }}" + +- name: check if selfsigned interim certificate does exist + ansible.builtin.stat: + path: "/var/lib/acme/certs/{{ existing_selfsigned_interim_cert_id }}" + register: existing_selfsigned_interim_cert_stat + +- name: create selfsigned interim certificate + when: not existing_selfsigned_interim_cert_id or not existing_selfsigned_interim_cert_stat.stat.exists + block: + - name: create temporary directory + ansible.builtin.tempfile: + path: /var/lib/acme/tmp + prefix: selfsigned-interim-cert- + state: directory + register: tmpdir + + - name: set tmpdir variable + ansible.builtin.set_fact: + tmpdir: "{{ tmpdir.path }}" + + - name: generate private key for selfsigned interim certificate + ansible.builtin.openssl_privatekey: + path: "{{ tmpdir }}/privkey" + mode: 0600 + + - name: generate csr for selfsigned interim certificate + community.crypto.openssl_csr_pipe: + privatekey_path: "{{ tmpdir }}/privkey" + common_name: "{{ ansible_fqdn }}" + register: selfsigned_interim_cert_req + + + ### 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 + ansible.builtin.command: date -d '10 seconds ago' -u '+%Y%m%d%H%M%SZ' + register: remote_datetime_10sago + + - name: get remote date-time now + ansible.builtin.command: date -u '+%Y%m%d%H%M%SZ' + register: remote_datetime_now + + - name: generate selfsigned interim certificate + community.crypto.x509_certificate_pipe: + privatekey_path: "{{ tmpdir }}/privkey" + csr_content: "{{ selfsigned_interim_cert_req.csr }}" + provider: selfsigned + ## make sure the certificate is not valid anymore to force acmetool to create a new cert + selfsigned_not_before: "{{ remote_datetime_10sago.stdout }}" + selfsigned_not_after: "{{ remote_datetime_now.stdout }}" + register: selfsigned_interim_cert + + - name: install selfsigned interim certificate and fullchain + loop: + - cert + - fullchain + ansible.builtin.copy: + content: "{{ selfsigned_interim_cert.certificate }}" + dest: "{{ tmpdir }}/{{ item }}" + + - name: create additional empty files + loop: + - chain + - selfsigned + ansible.builtin.copy: + content: "" + dest: "{{ tmpdir }}/{{ item }}" + + ### TODO: remove this once acmetool respects it's own storage layout + ### see: https://github.com/hlandau/acme/blob/master/_doc/SCHEMA.md#temporary-use-of-self-signed-certificates + - name: generate fake url file + ansible.builtin.copy: + content: "https://acme.example.com/acme/cert/self-signed\n" + dest: "{{ tmpdir }}/url" + + - name: get key id + ansible.builtin.shell: "openssl x509 -in '{{ tmpdir }}/cert' -noout -pubkey | openssl enc -base64 -d | openssl sha256 -binary | base32 | tr -d '=' | tr '[:upper:]' '[:lower:]'" + register: selfsigned_interim_key_id + + - name: set selfsigned_interim_key_id variable + ansible.builtin.set_fact: + selfsigned_interim_key_id: "{{ selfsigned_interim_key_id.stdout }}" + + - name: create directory for private key of selfsigned interim certificate + ansible.builtin.file: + path: "/var/lib/acme/keys/{{ selfsigned_interim_key_id }}" + state: directory + mode: 0700 + + - name: move private key to its directory + ansible.builtin.command: "mv '{{ tmpdir }}/privkey' '/var/lib/acme/keys/{{ selfsigned_interim_key_id }}/privkey'" + + - name: create symlink to privkey + ansible.builtin.file: + src: "../../keys/{{ selfsigned_interim_key_id }}/privkey" + dest: "{{ tmpdir }}/privkey" + state: link + + # - name: get certificate id + # ansible.builtin.shell: "openssl x509 -in '{{ tmpdir }}/cert' -outform der | openssl sha256 -binary | base32 | tr -d '=' | tr '[:upper:]' '[:lower:]'" + # register: selfsigned_interim_cert_id + + # - name: set selfsigned_interim_cert_id variable + # ansible.builtin.set_fact: + # selfsigned_interim_cert_id: "selfsigned-{{ selfsigned_interim_cert_id.stdout }}" + + ### TODO: replace with the above once acmetool respects it's own storage layout + ### see: https://github.com/hlandau/acme/blob/master/_doc/SCHEMA.md#temporary-use-of-self-signed-certificates + - name: get certificate id + ansible.builtin.shell: "cat '{{ tmpdir }}/url' | tr -d '\n' | openssl sha256 -binary | base32 | tr -d '=' | tr '[:upper:]' '[:lower:]'" + register: selfsigned_interim_cert_id + + - name: set selfsigned_interim_cert_id variable + ansible.builtin.set_fact: + selfsigned_interim_cert_id: "{{ selfsigned_interim_cert_id.stdout }}" + + - name: set permissions for selfsigned interim certificate directory + ansible.builtin.file: + path: "{{ tmpdir }}" + mode: 0755 + state: directory + + - name: move selfsigned interim certificate directory into place + ansible.builtin.command: "mv '{{ tmpdir }}' '/var/lib/acme/certs/{{ selfsigned_interim_cert_id }}'" + + - name: write cert-id of selfsigned interim certificate to state directory + ansible.builtin.copy: + content: "{{ selfsigned_interim_cert_id }}" + dest: /var/lib/acme/.selfsigned-interim-cert + + rescue: + - name: remove temporary directory for selfsigned interim certificate + ansible.builtin.file: + path: "{{ tmpdir }}" + state: absent -- cgit v1.2.3