diff --git a/playbooks/roles/cert/README.md b/playbooks/roles/cert/README.md new file mode 100644 index 0000000..a00253d --- /dev/null +++ b/playbooks/roles/cert/README.md @@ -0,0 +1,24 @@ +# Role `cert` + +A role for ordering and renewing certificates from Lets Encrypt via ACME. +It uses the DNS challenge and fullfills it via a BIND 9 server given to the role. + +## Supported Distributions + +The following distributions are supported: + +- Debian 11 + +## Required Arguments + +For the required arguments look at the [`argument_specs.yaml`](./meta/argument_specs.yml) + +## `hosts` + +The `hosts` for this role need to be the machines on which you want to have the certificates. + +## Links & Resources + +- +- +- diff --git a/playbooks/roles/cert/meta/argument_specs.yml b/playbooks/roles/cert/meta/argument_specs.yml index 664f8c6..c543079 100644 --- a/playbooks/roles/cert/meta/argument_specs.yml +++ b/playbooks/roles/cert/meta/argument_specs.yml @@ -22,16 +22,11 @@ argument_specs: description: E-Mail address for ACME account required: true type: str - cert__cloudflare_dns: - description: Cloudflare DNS API details + cert__bind_9_host: + description: The machine running BIND 9. required: true - type: dict - options: - api_token: - description: Cloudflare API token - required: true - type: str - zone: - description: DNS zone the domain is in - required: true - type: str + type: str + cert__bind_9_zone: + description: The zone to use for publishing the TXT record. + required: true + type: str diff --git a/playbooks/roles/cert/tasks/deploy_cert.yml b/playbooks/roles/cert/tasks/deploy_cert.yml index 821272d..d5219d5 100644 --- a/playbooks/roles/cert/tasks/deploy_cert.yml +++ b/playbooks/roles/cert/tasks/deploy_cert.yml @@ -74,17 +74,22 @@ - name: Retrieve certificate and fulfill challenge if needed # noqa no-handler when: cert__acme_challenge.changed # Can't be put in a handler, because then the block "always" tasks won't be executed for some reason block: - - name: Set DNS record via Cloudflare API to fulfill the challenge - when: not cert__acme_challenge.authorizations[item].status == "valid" - community.general.cloudflare_dns: - api_token: "{{ cert__cloudflare_dns.api_token }}" - zone: "{{ cert__cloudflare_dns.zone }}" - record: "{{ cert__acme_challenge.challenge_data[item]['dns-01'].record }}" - value: "{{ cert__acme_challenge.challenge_data[item]['dns-01'].resource_value }}" - type: TXT - ttl: 60 - solo: true - state: present + - name: Add file containing nsupdate commands for adding TXT record for DNS-01 challenge + ansible.builtin.template: + src: nsupdate_add_txt_record.j2 + dest: /root/nsupdate_add_txt_record + owner: root + group: root + mode: "0600" + vars: + cert__nsupdate_domain: "{{ cert__acme_challenge.challenge_data[item]['dns-01'].record }}" + cert__nsupdate_txt_data: "{{ cert__acme_challenge.challenge_data[item]['dns-01'].resource_value }}" + delegate_to: "{{ cert__bind_9_host }}" + + - name: Add DNS record to BIND 9 server via nsupdate # noqa: no-changed-when + ansible.builtin.command: /usr/bin/nsupdate -l /root/nsupdate_add_txt_record + delegate_to: "{{ cert__bind_9_host }}" + - name: Retrieve certificate community.crypto.acme_certificate: account_email: "{{ cert__acme_account_email }}" @@ -101,16 +106,35 @@ become: true notify: "{{ cert__handlers }}" always: - - name: Ensure DNS record is removed - when: not cert__acme_challenge.authorizations[item].status == "valid" - community.general.cloudflare_dns: - api_token: "{{ cert__cloudflare_dns.api_token }}" - zone: "{{ cert__cloudflare_dns.zone }}" - record: "{{ cert__acme_challenge.challenge_data[item]['dns-01'].record }}" - value: "{{ cert__acme_challenge.challenge_data[item]['dns-01'].resource_value }}" - type: TXT - ttl: 60 + - name: Remove file containing nsupdate commands for adding TXT record again + ansible.builtin.file: + path: /root/nsupdate_add_txt_record state: absent + delegate_to: "{{ cert__bind_9_host }}" + + - name: Remove TXT record again + block: + - name: Add file containing nsupdate commands for deleting TXT record for DNS-01 challenge + ansible.builtin.template: + src: nsupdate_delete_txt_record.j2 + dest: /root/nsupdate_delete_txt_record + owner: root + group: root + mode: "0600" + vars: + cert__nsupdate_domain: "{{ cert__acme_challenge.challenge_data[item]['dns-01'].record }}" + cert__nsupdate_txt_data: "{{ cert__acme_challenge.challenge_data[item]['dns-01'].resource_value }}" + delegate_to: "{{ cert__bind_9_host }}" + + - name: Remove DNS record from BIND 9 server via nsupdate # noqa: no-changed-when + ansible.builtin.command: /usr/bin/nsupdate -l /root/nsupdate_delete_txt_record + delegate_to: "{{ cert__bind_9_host }}" + always: + - name: Remove file containing nsupdate commands for deleting TXT record again + ansible.builtin.file: + path: /root/nsupdate_delete_txt_record + state: absent + delegate_to: "{{ cert__bind_9_host }}" - name: Ensure correct permissions for certificate are set ansible.builtin.file: diff --git a/playbooks/roles/cert/templates/nsupdate_add_txt_record.j2 b/playbooks/roles/cert/templates/nsupdate_add_txt_record.j2 new file mode 100644 index 0000000..1b0b9e7 --- /dev/null +++ b/playbooks/roles/cert/templates/nsupdate_add_txt_record.j2 @@ -0,0 +1,4 @@ +debug +zone {{ cert__bind_9_zone }} +update add {{ cert__nsupdate_domain }} 60 TXT {{ cert__nsupdate_txt_data }} +send diff --git a/playbooks/roles/cert/templates/nsupdate_delete_txt_record.j2 b/playbooks/roles/cert/templates/nsupdate_delete_txt_record.j2 new file mode 100644 index 0000000..274c76b --- /dev/null +++ b/playbooks/roles/cert/templates/nsupdate_delete_txt_record.j2 @@ -0,0 +1,4 @@ +debug +zone {{ cert__bind_9_zone }} +update delete {{ cert__nsupdate_domain }} 60 TXT {{ cert__nsupdate_txt_data }} +send