---
-
  name: "Create Directories for SSLs"
  ansible.builtin.file:
    path: "{{ item }}"
    state: directory
    owner: "{{ service_user }}"
    group: "{{ service_group }}"
    mode: '0755'
  with_items:
    - "{{ cert_dir }}"
    - "{{ cert_dir }}/key"
    - "{{ cert_dir }}/crt"
    - "{{ cert_dir }}/csr"
    - "{{ cert_dir }}/pfx"
    - "{{ cert_dir }}/kyr"
    - "{{ cert_dir }}/jks"
    - "{{ cert_dir }}/combined"
    - "{{ cert_dir }}/ca"
    - "/usr/local/share/ca-certificates/self-signed"

-
  name: "Using existing Certificate"
  when: not selfsigned_enabled and not letsencrypt_enabled
  block:
    -
      name: "Checking if SSL default certs exists"
      ansible.builtin.wait_for:
        path: "{{ item }}"
      with_items:
        - "{{ cert_dir }}/key/default-signed.key"
        - "{{ cert_dir }}/crt/default-signed.crt"
        - "{{ cert_dir }}/ca/default-signed.ca"

    -
      name: "Copying Signed SSL Key"
      ansible.builtin.copy:
        src: "{{ cert_dir }}/key/default-signed.key"
        dest: "{{ cert_dir }}/key/{{ settings.hostname }}.{{ settings.domain }}.key"
        owner: "{{ service_user }}"
        group: "{{ service_group }}"
        mode: '0644'
        remote_src: true

    -
      name: "Copying Signed SSL crt"
      ansible.builtin.copy:
        src: "{{ cert_dir }}/crt/default-signed.crt"
        dest: "{{ cert_dir }}/crt/{{ settings.hostname }}.{{ settings.domain }}.crt"
        owner: "{{ service_user }}"
        group: "{{ service_group }}"
        mode: '0644'
        remote_src: true

    -
      name: "Copying Signed SSL CA"
      ansible.builtin.copy:
        src: "{{ cert_dir }}/ca/default-signed.ca"
        dest: "{{ cert_dir }}/ca/{{ settings.hostname }}.{{ settings.domain }}.crt"
        owner: "{{ service_user }}"
        group: "{{ service_group }}"
        mode: '0644'
        remote_src: true

    -
      name: "Generating Signed PKCS12 file"
      community.crypto.openssl_pkcs12:
        action: export
        path: "{{ cert_dir }}/pfx/default-signed.pfk"
        certificate_path: "{{ cert_dir }}/crt/default-signed.crt"
        privatekey_path: "{{ cert_dir }}/key/default-signed.key"
        other_certificates_parse_all: true
        other_certificates:
          - "{{ cert_dir }}/ca/default-signed.ca"
        state: present
        friendly_name: 'pkcs12_file'
        owner: "{{ service_user }}"
        mode: '0777'

    -
      name: "Copying Signed SSL PFX"
      ansible.builtin.copy:
        src: "{{ cert_dir }}/pfx/default-signed.pfk"
        dest: "{{ cert_dir }}/pfx/{{ settings.hostname }}.{{ settings.domain }}.pfk"
        owner: "{{ service_user }}"
        group: "{{ service_group }}"
        mode: '0644'
        remote_src: true

    -
      name: "Parsing PKCS12 file to concatenated PEM"
      community.crypto.openssl_pkcs12:
        action: parse
        src: "{{ cert_dir }}/pfx/default-signed.pfk"
        path: "{{ cert_dir }}/combined/default-signed.pem"
        state: present
        owner: "{{ service_user }}"
        mode: '0777'

    -
      name: "Copying Combined cert"
      ansible.builtin.copy:
        src: "{{ cert_dir }}/combined/default-signed.crt"
        dest: "{{ cert_dir }}/combined/{{ settings.hostname }}.{{ settings.domain }}.pem"
        owner: "{{ service_user }}"
        group: "{{ service_group }}"
        mode: '0644'
        remote_src: true

    -
      name: "Creating a keystore for the given certificate/private key pair"
      become: true
      community.general.java_keystore:
        name: "{{ settings.hostname }}.{{ settings.domain }}"
        certificate: "{{ lookup('file', cert_dir + '/crt/default-signed.crt') }}"
        private_key: "{{ lookup('file', cert_dir + '/key/default-signed.key') }}"
        password: "{{ cert_pass }}"
        owner: "{{ service_user }}"
        mode: '0777'
        dest: "{{ cert_dir }}/jks/default-signed.jks"
      environment:
        PATH: "{{ ansible_env.PATH }}:{{ service_home_dir }}/.sdkman/candidates/java/current/bin"

    -
      name: "Copying JKS"
      ansible.builtin.copy:
        src: "{{ cert_dir }}/jks/default-signed.jks"
        dest: "{{ cert_dir }}/jks/{{ settings.hostname }}.{{ settings.domain }}.jks"
        owner: "{{ service_user }}"
        group: "{{ service_group }}"
        mode: '0644'
        remote_src: true

-
  name: "Generating Self Signed Certificate"
  when: selfsigned_enabled and not letsencrypt_enabled
  block:
    -
      name: "Using STARTcloud Certificate Authority"
      when: not generate_self_signed_certificate_authority
      block:
        -
          name: "Copying root CA certificate to trusted certificates directory"
          ansible.builtin.copy:
            src: "ssls/ca/ca-certificate.key"
            dest: "{{ cert_dir }}/ca/ca-certificate.key"
            owner: root
            group: root
            mode: '0644'

        -
          name: "Copying root CA certificate to trusted certificates directory"
          ansible.builtin.copy:
            src: "ssls/ca/ca-certificate.crt"
            dest: "{{ cert_dir }}/ca/ca-certificate.crt"
            owner: root
            group: root
            mode: '0644'

    -
      name: "Generating Certificate Authority"
      when: generate_self_signed_certificate_authority
      block:
        -
          name: "Creating private key for Certifcate Authority"
          community.crypto.openssl_privatekey:
            path: "{{ cert_dir }}/ca/ca-certificate.key"
            passphrase: "{{ ca_cert_pass }}"
            cipher: 'auto'
            mode: '0777'
    
        -
          name: "Creating certificate signing request (CSR) for Certifcate Authority certificate"
          community.crypto.openssl_csr_pipe:
            privatekey_path: "{{ cert_dir }}/ca/ca-certificate.key"
            privatekey_passphrase: "{{ ca_cert_pass }}"
            common_name: "{{ settings.domain }}"
            country_name: "{{ countrycode }}"
            organization_name: "{{ domino_organization }}"
            use_common_name_for_san: false
            basic_constraints:
              - 'CA:TRUE'
            basic_constraints_critical: true
            key_usage:
              - keyCertSign
            key_usage_critical: true
          register: ca_csr
    
        -
          name: "Creating self-signed CA certificate from CA CSR"
          community.crypto.x509_certificate:
            path: "{{ cert_dir }}/ca/ca-certificate.crt"
            csr_content: "{{ ca_csr.csr }}"
            privatekey_path: "{{ cert_dir }}/ca/ca-certificate.key"
            privatekey_passphrase: "{{ ca_cert_pass }}"
            provider: selfsigned
            owner: "{{ service_user }}"
            mode: '0777'

    -
      name: "Copying root CA certificate to trusted certificates directory"
      ansible.builtin.copy:
        src: "{{ cert_dir }}/ca/ca-certificate.crt"
        dest: "/usr/local/share/ca-certificates/self-signed/ca-certificate.crt"
        owner: root
        group: root
        mode: '0644'

    -
      name: "Updating system's certificate store"
      ansible.builtin.command: update-ca-certificates

    -
      name: "Generating Servers self signed SSL Key"
      community.crypto.openssl_privatekey:
        path: "{{ cert_dir }}/key/{{ settings.hostname }}.{{ settings.domain }}-self-signed.key"
        owner: "{{ service_user }}"
        type: "RSA"
        mode: '0777'

    -
      name: "Copying signed SSL Key"
      ansible.builtin.copy:
        src: "{{ cert_dir }}/key/{{ settings.hostname }}.{{ settings.domain }}-self-signed.key"
        dest: "{{ cert_dir }}/key/{{ settings.hostname }}.{{ settings.domain }}.key"
        owner: "{{ service_user }}"
        group: "{{ service_group }}"
        mode: '0644'
        remote_src: true

    -
      name: "Setting DNS entries as a fact to consume for SSL generation"
      ansible.builtin.set_fact:
        dns_entries: "{{ ['DNS:' + settings.hostname + '.' + settings.domain] }}"

    -
      name: "Setting DNS Subdomain entries as a fact"
      ansible.builtin.set_fact:
        dns_entries: "{{ dns_entries | default([]) + ['DNS:' + item + '.' + settings.hostname + '.' + settings.domain] }}"
      loop: "{{ dns_entries_list }}"

    -
      name: "Generating an OpenSSL CSR with subjectAltName extension with dynamic list"
      community.crypto.openssl_csr:
        path: "{{ cert_dir }}/csr/{{ settings.hostname }}.{{ settings.domain }}-self-signed.csr"
        privatekey_path: "{{ cert_dir }}/key/{{ settings.hostname }}.{{ settings.domain }}-self-signed.key"
        subject_alt_name: "{{ dns_entries | list }}"
        country_name: "{{ countrycode }}"
        organization_name: "{{ domino_organization }}"
        common_name: "{{ settings.hostname }}.{{ settings.domain }}"
        owner: "{{ service_user }}"
        mode: '0777'

    -
      name: "Generating self signed Certificate"
      community.crypto.x509_certificate:
        path: "{{ cert_dir }}/crt/{{ settings.hostname }}.{{ settings.domain }}-self-signed.crt"
        privatekey_path: "{{ cert_dir }}/key/{{ settings.hostname }}.{{ settings.domain }}-self-signed.key"
        csr_path: "{{ cert_dir }}/csr/{{ settings.hostname }}.{{ settings.domain }}-self-signed.csr"
        provider: ownca
        ownca_path: "{{ cert_dir }}/ca/ca-certificate.crt"
        ownca_privatekey_path: "{{ cert_dir }}/ca/ca-certificate.key"
        ownca_privatekey_passphrase: "{{ ca_cert_pass }}"
        owner: "{{ service_user }}"
        mode: '0777'

    -
      name: "Copying CRT"
      ansible.builtin.copy:
        src: "{{ cert_dir }}/crt/{{ settings.hostname }}.{{ settings.domain }}-self-signed.crt"
        dest: "{{ cert_dir }}/crt/{{ settings.hostname }}.{{ settings.domain }}.crt"
        owner: "{{ service_user }}"
        group: "{{ service_group }}"
        mode: '0644'
        remote_src: true

    -
      name: "Generating self signed PKCS12 file"
      community.crypto.openssl_pkcs12:
        action: export
        path: "{{ cert_dir }}/pfx/{{ settings.hostname }}.{{ settings.domain }}-self-signed.pfk"
        certificate_path: "{{ cert_dir }}/crt/{{ settings.hostname }}.{{ settings.domain }}-self-signed.crt"
        privatekey_path: "{{ cert_dir }}/key/{{ settings.hostname }}.{{ settings.domain }}-self-signed.key"
        state: present
        friendly_name: 'pkcs12_file'
        owner: "{{ service_user }}"
        mode: '0777'

    -
      name: "Copying PKCS12"
      ansible.builtin.copy:
        src: "{{ cert_dir }}/pfx/{{ settings.hostname }}.{{ settings.domain }}-self-signed.pfk"
        dest: "{{ cert_dir }}/pfx/{{ settings.hostname }}.{{ settings.domain }}.pfk"
        owner: "{{ service_user }}"
        group: "{{ service_group }}"
        mode: '0644'
        remote_src: true

    -
      name: "Parsing self-signed PKCS12 file to concatenated PEM"
      community.crypto.openssl_pkcs12:
        action: parse
        src: "{{ cert_dir }}/pfx/{{ settings.hostname }}.{{ settings.domain }}-self-signed.pfk"
        path: "{{ cert_dir }}/combined/{{ settings.hostname }}.{{ settings.domain }}-self-signed.pem"
        state: present
        owner: "{{ service_user }}"
        mode: '0777'

    -
      name: "Copying combined"
      ansible.builtin.copy:
        src: "{{ cert_dir }}/combined/{{ settings.hostname }}.{{ settings.domain }}-self-signed.pem"
        dest: "{{ cert_dir }}/combined/{{ settings.hostname }}.{{ settings.domain }}.pem"
        owner: "{{ service_user }}"
        group: "{{ service_group }}"
        mode: '0644'
        remote_src: true

    -
      name: "Append CA certificate to combined certificate"
      ansible.builtin.blockinfile:
        path: "{{ cert_dir }}/combined/{{ settings.hostname }}.{{ settings.domain }}.pem"
        block: "{{ lookup('file', cert_dir + '/ca/ca-certificate.crt') }}"
        marker: "# {mark} ANSIBLE MANAGED BLOCK - CA CERTIFICATE"
        owner: "{{ service_user }}"
        group: "{{ service_group }}"
        mode: '0644'

    -
      name: "Creating a keystore for the self-signed certificate/private key pair"
      community.general.java_keystore:
        name: "{{ settings.hostname }}.{{ settings.domain }}"
        certificate: "{{ lookup('file', cert_dir + '/crt/' + settings.hostname + '.' + settings.domain + '-self-signed.crt') }}"
        private_key: "{{ lookup('file', cert_dir + '/key/' + settings.hostname + '.' + settings.domain + '-self-signed.key') }}"
        password: "{{ cert_pass }}"
        owner: "{{ service_user }}"
        mode: '0777'
        dest: "{{ cert_dir }}/jks/{{ settings.hostname }}.{{ settings.domain }}-self-signed.jks"
      environment:
        PATH: "{{ ansible_env.PATH }}:{{ service_home_dir }}/.sdkman/candidates/java/current/bin"

    -
      name: "Copying JKS"
      ansible.builtin.copy:
        src: "{{ cert_dir }}/jks/{{ settings.hostname }}.{{ settings.domain }}-self-signed.jks"
        dest: "{{ cert_dir }}/jks/{{ settings.hostname }}.{{ settings.domain }}.jks"
        owner: "{{ service_user }}"
        group: "{{ service_group }}"
        mode: '0644'
        remote_src: true

-
  name: "Beginning Let's Encrypt Provisioning"
  when: selfsigned_enabled and letsencrypt_enabled
  block:
    -
      name: "Ensuring apt cache is updated"
      ansible.builtin.apt:
        cache_valid_time: 3600
        update_cache: true

    -
      name: "Upgrading all apt packages"
      ansible.builtin.apt:
        upgrade: dist
        update_cache: true

    -
      name: "Adding certbot via apt repo"
      ansible.builtin.apt:
        name: certbot
        state: present

    -
      name: "Checking if HAProxy is installed"
      register: haproxy_installed
      ansible.builtin.stat:
        path: "/etc/haproxy/haproxy.cfg"
        get_checksum: false

    -
      name: "Checking if HAProxy is configured for Let's Encrypt"
      when: haproxy_installed.stat.exists
      register: haproxy_status
      check_mode: true
      ansible.builtin.lineinfile:
        path: /etc/haproxy/haproxy.cfg
        regexp: '^\s*server\s+letsencrypt\s+127\.0\.0\.1:'
        line: '        server  letsencrypt             127.0.0.1:8181'
        state: present

    -
      name: "Set default haproxy_status when HAProxy is not installed"
      when: not haproxy_installed.stat.exists
      ansible.builtin.set_fact:
        haproxy_status:
          changed: true
          skipped: false

    -
      name: "Check if HAProxy is in enabled_roles"
      ansible.builtin.set_fact:
        haproxy_in_enabled_roles: "{{ 'startcloud.startcloud_roles.haproxy' in (enabled_roles | default([])) }}"

    -
      name: "Ensuring HAproxy is started if installed and letsencrypt via HAproxy is enabled"
      when: haproxy_installed.stat.exists and (not haproxy_status.changed or (haproxy_status.changed and haproxy_in_enabled_roles))
      ansible.builtin.service:
        name: "haproxy"
        state: started

    -
      name: "Setting LE entries as a fact to consume"
      ansible.builtin.set_fact:
        le_entries: "{{ ['-d ' + settings.hostname + '.' + settings.domain] }}"

    -
      name: "Add subdomain entries to LE entries"
      ansible.builtin.set_fact:
        le_entries: "{{ le_entries + ['-d ' + item + '.' + settings.hostname + '.' + settings.domain] }}"
      loop: "{{ dns_entries_list }}"

    -
      name: "Checking if certificate exists"
      register: letsencrypt_cert
      ansible.builtin.stat:
        path: "/etc/letsencrypt/live/{{ settings.hostname | lower }}.{{ settings.domain | lower }}/cert.pem"

    -
      name: "Generating new staging certificate request"
      ansible.builtin.shell: >-
        certbot certonly --standalone
        --noninteractive
        --agree-tos
        --key-type rsa
        --staging
        --email {{ settings.email }}
        {{ le_entries | join(' ') }}
      when: (haproxy_status.changed and not haproxy_in_enabled_roles) and not letsencrypt_cert.stat.exists and letsencrypt_staging_enabled

    -
      name: "Generating new staging request via HAProxy"
      ansible.builtin.shell: certbot certonly --standalone --noninteractive --agree-tos --key-type rsa --staging --email {{ settings.email }} {{ le_entries | join(' ') }} --http-01-port=8181
      when: (not haproxy_status.changed or (haproxy_status.changed and haproxy_in_enabled_roles)) and not letsencrypt_cert.stat.exists and letsencrypt_staging_enabled

    -
      name: "Generating new certificate request"
      ansible.builtin.shell: certbot certonly --standalone --noninteractive --agree-tos --key-type rsa --email {{ settings.email }} {{ le_entries | join(' ') }}
      when: (haproxy_status.changed and not haproxy_in_enabled_roles) and not letsencrypt_cert.stat.exists and not letsencrypt_staging_enabled

    -
      name: "Generating new certificate request via HAProxy"
      ansible.builtin.shell: certbot certonly --standalone --noninteractive --agree-tos --key-type rsa --email {{ settings.email }} {{ le_entries | join(' ') }} --http-01-port=8181
      when: (not haproxy_status.changed or (haproxy_status.changed and haproxy_in_enabled_roles)) and not letsencrypt_cert.stat.exists and not letsencrypt_staging_enabled

    -
      name: "Remove old certs Directories for SSLs"
      ansible.builtin.file:
        path: "{{ item }}"
        state: absent
      with_items:
        - "{{ cert_dir }}/key/{{ settings.hostname }}.{{ settings.domain }}.key"
        - "{{ cert_dir }}/crt/{{ settings.hostname }}.{{ settings.domain }}.crt"

    -
      name: "Checking if letsencrypt certificate exists"
      register: letsencrypt_cert_generated_check
      become: true
      ansible.builtin.stat:
        path: "/etc/letsencrypt/live/{{ settings.hostname | lower }}.{{ settings.domain | lower }}/fullchain.pem"

    -
      name: "Copying cert.pem from letsencrypt"
      when: letsencrypt_cert_generated_check.stat.exists | bool
      ansible.builtin.copy:
        src: "/etc/letsencrypt/live/{{ settings.hostname | lower }}.{{ settings.domain | lower }}/fullchain.pem"
        dest: "{{ cert_dir }}/crt/{{ settings.hostname }}.{{ settings.domain }}-letsencrypt.crt"
        owner: "{{ service_user }}"
        group: "{{ service_group }}"
        mode: '0644'
        remote_src: true

    -
      name: "Replacing presigned ssl with letsencrypt cert"
      when: letsencrypt_cert_generated_check.stat.exists | bool
      ansible.builtin.copy:
        src: "{{ cert_dir }}/crt/{{ settings.hostname }}.{{ settings.domain }}-letsencrypt.crt"
        dest: "{{ cert_dir }}/crt/{{ settings.hostname }}.{{ settings.domain }}.crt"
        owner: "{{ service_user }}"
        group: "{{ service_group }}"
        mode: '0644'
        remote_src: true

    -
      name: "Copying privkey.pem from letsencrypt"
      when: letsencrypt_cert_generated_check.stat.exists | bool
      ansible.builtin.copy:
        src: "/etc/letsencrypt/live/{{ settings.hostname | lower }}.{{ settings.domain | lower }}/privkey.pem"
        dest: "{{ cert_dir }}/key/{{ settings.hostname }}.{{ settings.domain }}-letsencrypt.key"
        owner: "{{ service_user }}"
        group: "{{ service_group }}"
        mode: '0777'
        remote_src: true

    -
      name: "Replacing presigned ssl with letsencrypt key"
      when: letsencrypt_cert_generated_check.stat.exists | bool
      become: true
      ansible.builtin.copy:
        src: "{{ cert_dir }}/key/{{ settings.hostname }}.{{ settings.domain }}-letsencrypt.key"
        dest: "{{ cert_dir }}/key/{{ settings.hostname }}.{{ settings.domain }}.key"
        owner: "{{ service_user }}"
        group: "{{ service_group }}"
        mode: '0777'
        remote_src: true

    -
      name: "Generating self signed PKCS12 file"
      become: true
      community.crypto.openssl_pkcs12:
        action: export
        path: "{{ cert_dir }}/pfx/{{ settings.hostname }}.{{ settings.domain }}-letsencrypt.pfk"
        certificate_path: "{{ cert_dir }}/crt/{{ settings.hostname }}.{{ settings.domain }}-letsencrypt.crt"
        privatekey_path: "{{ cert_dir }}/key/{{ settings.hostname }}.{{ settings.domain }}-letsencrypt.key"
        state: present
        friendly_name: 'pkcs12_file'
        owner: "{{ service_user }}"
        group: "{{ service_group }}"
        mode: '0644'

    -
      name: "Copying PFX"
      become: true
      ansible.builtin.copy:
        src: "{{ cert_dir }}/pfx/{{ settings.hostname }}.{{ settings.domain }}-letsencrypt.pfk"
        dest: "{{ cert_dir }}/pfx/{{ settings.hostname }}.{{ settings.domain }}.pfk"
        owner: "{{ service_user }}"
        group: "{{ service_group }}"
        mode: '0777'
        remote_src: true

    -
      name: "Parsing letsencrypt PKCS12 file to concatenated PEM"
      become: true
      community.crypto.openssl_pkcs12:
        action: parse
        src: "{{ cert_dir }}/pfx/{{ settings.hostname }}.{{ settings.domain }}-letsencrypt.pfk"
        path: "{{ cert_dir }}/combined/{{ settings.hostname }}.{{ settings.domain }}-letsencrypt.pem"
        state: present
        owner: "{{ service_user }}"
        group: "{{ service_group }}"
        mode: '0644'

    -
      name: "Copying Combined Cert"
      become: true
      ansible.builtin.copy:
        src: "{{ cert_dir }}/combined/{{ settings.hostname }}.{{ settings.domain }}-letsencrypt.pem"
        dest: "{{ cert_dir }}/combined/{{ settings.hostname }}.{{ settings.domain }}.pem"
        owner: "{{ service_user }}"
        group: "{{ service_group }}"
        mode: '0777'
        remote_src: true

    -
      name: "Creating a keystore for the letsencrypt certificate/private key pair"
      become: true
      community.general.java_keystore:
        name: "{{ settings.hostname }}.{{ settings.domain }}"
        certificate: "{{ lookup('file', cert_dir + '/crt/' + settings.hostname + '.' + settings.domain + '-letsencrypt.crt') }}"
        private_key: "{{ lookup('file', cert_dir + '/key/' + settings.hostname + '.' + settings.domain + '-letsencrypt.key') }}"
        password: "{{ cert_pass }}"
        owner: "{{ service_user }}"
        group: "{{ service_group }}"
        mode: '0644'
        dest: "{{ cert_dir }}/jks/{{ settings.hostname }}.{{ settings.domain }}-letsencrypt.jks"
      environment:
        PATH: "{{ ansible_env.PATH }}:{{ service_home_dir }}/.sdkman/candidates/java/current/bin"

    -
      name: "Copying JKS"
      become: true
      ansible.builtin.copy:
        src: "{{ cert_dir }}/jks/{{ settings.hostname }}.{{ settings.domain }}-letsencrypt.jks"
        dest: "{{ cert_dir }}/jks/{{ settings.hostname }}.{{ settings.domain }}.jks"
        owner: "{{ service_user }}"
        group: "{{ service_group }}"
        mode: '0777'
        remote_src: true
