---

- name: Create and validate a TLS certificate using LetsEncrypt with DNS-01 challenge type, and AWS Route53
  hosts: all
  gather_facts: false

  vars:
    account_email: someone@example.org
    acme_directory: https://acme-v02.api.letsencrypt.org/directory
    # acme_directory: https://acme-staging-v02.api.letsencrypt.org/directory
    common_name: service.example.org
    remaining_days: 7
    zone: example.org

  pre_tasks:

    - name: Generate private keys for an account and the certificate
      community.crypto.openssl_privatekey:
        path: "{{ item }}"
        type: RSA
        size: 4096
      with_items:
        - /tmp/{{ common_name }}.key
        - /tmp/acme.account.key.pem

    - name: Generate private keys for an account and the certificate - OpenSSH alternative
      when: false
      community.crypto.openssh_keypair:
        path: "{{ item }}"
        type: rsa
        size: 4096
      with_items:
        - /tmp/{{ common_name }}.key
        - /tmp/acme.account.key.pem

  tasks:

    - name: Generate the CRS for the certificate
      community.crypto.openssl_csr:
        path: /tmp/{{ common_name }}.crs
        privatekey_path: /tmp/{{ common_name }}.key
        common_name: "{{ common_name }}"

    - name: Create the DNS challenge for '{{ common_name }}'
      community.crypto.acme_certificate:
        challenge: dns-01
        acme_version: 2
        acme_directory: "{{ acme_directory }}"
        account_key_src: /tmp/acme.account.key.pem
        account_email: "{{ account_email }}"
        csr: /tmp/{{ common_name }}.crs
        dest: /tmp/{{ common_name }}.endpointOnly.crt  # endpoint only certificate
        fullchain_dest: /tmp/{{ common_name }}.crt     # full certificate chain
        terms_agreed: true
        remaining_days: "{{ remaining_days }}"
        # force: true
      register: dns_challenge
      notify: Create TXT records for challenge validation

  handlers:

    - name: Create TXT records for challenge validation
      when: common_name in dns_challenge.challenge_data
      amazon.aws.route53:
        zone: "{{ zone }}"
        record: "{{ dns_challenge.challenge_data[common_name]['dns-01'].record }}"
        type: TXT
        ttl: 60
        state: present
        overwrite: true
        wait: true
        value:
          # shall be enclosed in quotation marks
          >-
          {{
            dns_challenge.challenge_data[common_name]['dns-01'].resource_value
            | regex_replace('^(.*)$', '"\1"')
          }}
      notify: Validate the challenge and create the certificate

    - name: Validate the challenge and create the certificate
      community.crypto.acme_certificate:
        challenge: dns-01
        acme_version: 2
        acme_directory: "{{ acme_directory }}"
        account_key_src: /tmp/acme.account.key.pem
        account_email: "{{ account_email }}"
        csr: /tmp/{{ common_name }}.crs
        dest: /tmp/{{ common_name }}.endpointOnly.crt  # endpoint only certificate
        fullchain_dest: /tmp/{{ common_name }}.crt     # full certificate chain
        remaining_days: "{{ remaining_days }}"
        terms_agreed: true
        data: "{{ dns_challenge }}"
        # force: true

  post_tasks:
    - name: Delete TXT records for challenge validation
      vars:
        validation_record: "{{ ['_acme-challenge', common_name] | join('.') }}"
      when: query('community.dns.lookup', validation_record, type='TXT') != []
      amazon.aws.route53:
        zone: "{{ zone }}"
        record: "{{ validation_record }}"
        type: TXT
        state: absent
        wait: true
