--- - name: Install required python libraries system wide when: ansible_facts['os_family'] == "Archlinux" community.general.pacman: name: - python-cryptography - python-dnspython state: latest update_cache: true - name: Set certificate path facts ansible.builtin.set_fact: acme_certificate_certificate_path: "/etc/ssl/private/{{ acme_certificate_subject }}.pem" acme_certificate_chain_path: "/etc/ssl/private/{{ acme_certificate_subject }}.chain.pem" acme_certificate_combined_path: "/etc/ssl/private/{{ acme_certificate_subject }}.combined.pem" acme_certificate_csr_path: "/etc/ssl/private/{{ acme_certificate_subject }}.csr" acme_certificate_fullchain_path: "/etc/ssl/private/{{ acme_certificate_subject }}.fullchain.pem" acme_certificate_key_path: "/etc/ssl/private/{{ acme_certificate_subject }}.key" acme_certificate_plain_combined_path: "/etc/ssl/private/{{ acme_certificate_subject }}.plain.combined.pem" acme_certificate_plain_key_path: "/etc/ssl/private/{{ acme_certificate_subject }}.plain.key" - name: Create ACME account key directory ansible.builtin.file: group: root mode: '0700' owner: root path: /etc/ssl/private/ACME state: directory - name: Create ACME account key community.crypto.openssl_privatekey: cipher: auto curve: secp384r1 format: auto_ignore group: root mode: '0600' owner: root passphrase: "{{ acme_certificate_account_key_passphrase }}" path: /etc/ssl/private/ACME/account.key size: 4096 state: present type: RSA - name: Generate RSA private key community.crypto.openssl_privatekey: cipher: auto curve: secp384r1 format: auto_ignore group: root mode: '0600' owner: root passphrase: "{{ ssl_passphrase }}" path: "{{ acme_certificate_key_path }}" size: 4096 state: present type: RSA register: genrsa_private_key - name: Generate CSR community.crypto.openssl_csr: common_name: "{{ acme_certificate_subject }}" country_name: "{{ acme_certificate_csr_country }}" digest: sha256 email_address: "{{ acme_certificate_csr_email }}" group: root locality_name: "{{ acme_certificate_csr_locality }}" mode: '0600' organization_name: "{{ acme_certificate_csr_organization }}" owner: root path: "{{ acme_certificate_csr_path }}" privatekey_passphrase: "{{ ssl_passphrase }}" privatekey_path: "{{ acme_certificate_key_path }}" state: present state_or_province_name: "{{ acme_certificate_csr_state }}" use_common_name_for_san: true - name: Submit ACME certificate request community.crypto.acme_certificate: account_email: "{{ acme_certificate_account_email }}" account_key_passphrase: "{{ acme_certificate_account_key_passphrase }}" account_key_src: /etc/ssl/private/ACME/account.key acme_directory: "{{ acme_certificate_directory }}" acme_version: 2 chain_dest: "{{ acme_certificate_chain_path }}" challenge: dns-01 csr: "{{ acme_certificate_csr_path }}" dest: "{{ acme_certificate_certificate_path }}" fullchain_dest: "{{ acme_certificate_fullchain_path }}" modify_account: true select_crypto_backend: cryptography terms_agreed: true validate_certs: true register: challenge - name: Debug ACME certificate challenge ansible.builtin.debug: var: challenge - name: Proceed if challenge is changed when: - challenge is changed - acme_certificate_subject in challenge.challenge_data block: - name: Answer ACME certificate challenge community.general.nsupdate: key_algorithm: "{{ rfc2136_key_algorithm }}" key_name: "{{ rfc2136_key_name }}" key_secret: "{{ rfc2136_key_secret }}" port: 53 protocol: tcp record: "{{ challenge.challenge_data[acme_certificate_subject]['dns-01'].record }}." server: "{{ rfc2136_server_address }}" state: present ttl: 3600 type: TXT value: "{{ challenge.challenge_data[acme_certificate_subject]['dns-01'].resource_value }}" # zone: "{{ acme_certificate_zone }}" register: nsupdate_result - name: Debug nsupdate result ansible.builtin.debug: var: nsupdate_result - name: Retrieve ACME certificate community.crypto.acme_certificate: account_email: "{{ acme_certificate_account_email }}" account_key_passphrase: "{{ acme_certificate_account_key_passphrase }}" account_key_src: /etc/ssl/private/ACME/account.key acme_directory: "{{ acme_certificate_directory }}" acme_version: 2 chain_dest: "{{ acme_certificate_chain_path }}" challenge: dns-01 csr: "{{ acme_certificate_csr_path }}" data: "{{ challenge }}" dest: "{{ acme_certificate_certificate_path }}" fullchain_dest: "{{ acme_certificate_fullchain_path }}" select_crypto_backend: cryptography terms_agreed: true validate_certs: true - name: Cleanup ACME challenge community.general.nsupdate: key_algorithm: "{{ rfc2136_key_algorithm }}" key_name: "{{ rfc2136_key_name }}" key_secret: "{{ rfc2136_key_secret }}" port: 53 protocol: tcp record: "{{ challenge.challenge_data[acme_certificate_subject]['dns-01'].record }}." server: "{{ rfc2136_server_address }}" state: absent ttl: 3600 type: TXT value: "{{ challenge.challenge_data[acme_certificate_subject]['dns-01'].resource_value }}" zone: "{{ acme_certificate_zone }}" - name: Slurp fullchain contents ansible.builtin.slurp: src: "{{ acme_certificate_fullchain_path }}" register: acme_certificate_fullchain_content - name: Slurp private key contents ansible.builtin.slurp: src: "{{ acme_certificate_key_path }}" register: acme_certificate_key_content - name: Create combined cert file ansible.builtin.template: dest: "{{ acme_certificate_combined_path }}" group: root mode: '0600' owner: root src: combined.pem.j2 - name: Check if plain key file exists ansible.builtin.stat: path: "{{ acme_certificate_plain_key_path }}" register: plain_key_file - name: Create a plain text copy of the SSL private key # noqa: no-handler when: | genrsa_private_key.changed or not plain_key_file.stat.exists ansible.builtin.command: cmd: openssl rsa -in {{ acme_certificate_key_path }} -passin pass:{{ ssl_passphrase }} -out {{ acme_certificate_plain_key_path }} changed_when: true - name: Slurp plain text private key contents ansible.builtin.slurp: src: "{{ acme_certificate_plain_key_path }}" register: acme_certificate_key_content - name: Create plain text combined cert file ansible.builtin.template: dest: "{{ acme_certificate_plain_combined_path }}" group: root mode: '0600' owner: root src: combined.pem.j2 - name: Dependant services block when: - (acme_certificate_restart_services | default([]) | length) >= 1 - challenge is changed block: - name: Check state of running services ansible.builtin.service_facts: - name: Restart dependant services when: - ansible_facts.services[item] is defined - ansible_facts.services[item].state in ['running','failed'] ansible.builtin.service: name: "{{ item }}" state: restarted loop: "{{ acme_certificate_restart_services }}"