--- - name: Install PKI directory for {{ pki_cert_name }} ansible.builtin.file: path: "{{ pki_cert_dir }}" state: directory mode: '0700' owner: root group: root - name: Check for existing certificate ansible.builtin.stat: path: "{{ pki_cert_dir }}/cert.pem" register: pki_cert_existing - name: Inspect existing certificate expiry community.crypto.x509_certificate_info: path: "{{ pki_cert_dir }}/cert.pem" valid_at: still_valid_before_renewal_window: "{{ pki_cert_renew_before }}" register: pki_cert_info when: pki_cert_existing.stat.exists - name: Determine whether certificate needs rotation ansible.builtin.set_fact: pki_cert_needs_rotation: "{{ pki_cert_existing.stat.exists and not pki_cert_info.valid_at.still_valid_before_renewal_window }}" - name: Archive certificate nearing expiry when: pki_cert_needs_rotation block: - name: Compute archive directory name ansible.builtin.set_fact: pki_cert_archive_dir: "{{ pki_cert_dir }}/{{ (pki_cert_info.not_before | to_datetime('%Y%m%d%H%M%SZ')).strftime('%Y-%m') }}" - name: Create archive directory ansible.builtin.file: path: "{{ pki_cert_archive_dir }}" state: directory mode: '0700' owner: root group: root - name: Check which certificate files exist ansible.builtin.stat: path: "{{ pki_cert_dir }}/{{ item }}" register: pki_cert_files loop: - cert.key - cert.pem - full-chain.pem loop_control: label: "{{ item }}" - name: Copy existing certificate files into archive ansible.builtin.copy: src: "{{ pki_cert_dir }}/{{ item.item }}" dest: "{{ pki_cert_archive_dir }}/{{ item.item }}" remote_src: true mode: preserve owner: root group: root loop: "{{ pki_cert_files.results }}" loop_control: label: "{{ item.item }}" when: item.stat.exists - name: Remove archived certificate files from live directory ansible.builtin.file: path: "{{ pki_cert_dir }}/{{ item.item }}" state: absent loop: "{{ pki_cert_files.results }}" loop_control: label: "{{ item.item }}" when: item.stat.exists # community.crypto.x509_certificate recomputes ownca_not_after/not_before # relative to "now" on every run, which never exactly matches the fixed # timestamps of an already-issued certificate. Left unguarded, that makes it # silently reissue (and extend) the certificate on every playbook run, # bypassing the archiving above. Only (re)generate when there is no # certificate yet, or when we've actually decided it needs rotating. - name: Issue certificate when: not pki_cert_existing.stat.exists or pki_cert_needs_rotation block: - name: Create private key for {{ pki_cert_name }} community.crypto.openssl_privatekey: path: "{{ pki_cert_dir }}/cert.key" - name: Create CSR for {{ pki_cert_name }} community.crypto.openssl_csr_pipe: privatekey_path: "{{ pki_cert_dir }}/cert.key" common_name: "{{ pki_cert_name }}" subject_alt_name: "{{ pki_cert_sans }}" register: pki_cert_csr - name: Sign with root ca community.crypto.x509_certificate: path: "{{ pki_cert_dir }}/cert.pem" csr_content: "{{ pki_cert_csr.csr }}" provider: ownca ownca_path: /etc/pki/konchin.com/rootca.pem ownca_privatekey_path: /etc/pki/konchin.com/rootca.key ownca_privatekey_passphrase: "{{ secret_ca_passphrase }}" ownca_not_after: +365d # valid for one year ownca_not_before: -1d # valid since yesterday return_content: true register: pki_cert_signed - name: Slurp root ca ansible.builtin.slurp: src: /etc/pki/konchin.com/rootca.pem register: pki_cert_rootca - name: Create full chain cert ansible.builtin.copy: content: | {{ pki_cert_signed.certificate | trim }} {{ pki_cert_rootca['content'] | b64decode | trim }} dest: "{{ pki_cert_dir }}/full-chain.pem" mode: '0600' owner: root group: root