Kevin Veen-Birkenbach 2620ee088e
refactor(dns): unify Cloudflare + Hetzner handling across roles
- replaced CERTBOT_DNS_API_TOKEN with CLOUDFLARE_API_TOKEN everywhere
- introduced generic sys-dns-cloudflare-records role for managing DNS records
- added sys-dns-hetzner-rdns role with both Cloud (hcloud) and Robot API flavors
- updated Mailu role to:
  - generate DKIM before DNS setup
  - delegate DNS + rDNS records to the new generic roles
- removed legacy per-role Cloudflare vars (MAILU_CLOUDFLARE_API_TOKEN)
- extended group vars with HOSTING_PROVIDER for rDNS flavor decision
- added hetzner.hcloud collection to requirements

This consolidates DNS management into reusable roles,
supports both Cloudflare and Hetzner providers,
and standardizes variable naming across the project.
2025-08-16 21:43:01 +02:00

43 lines
1.6 KiB
YAML

---
# Robot flavor (Robot Webservice API)
- name: Assert Robot credentials present
ansible.builtin.assert:
that:
- (HETZNER_ROBOT_USER | default('') | length) > 0
- (HETZNER_ROBOT_PASSWORD | default('') | length) > 0
fail_msg: "Robot credentials required: HETZNER_ROBOT_USER / HETZNER_ROBOT_PASSWORD."
no_log: "{{ hetzner_no_log | bool }}"
- name: Validate records (robot)
ansible.builtin.assert:
that:
- rdns_records | length > 0
- (rdns_records | selectattr('ip_address','defined') | list | length) == (rdns_records | length)
- (rdns_records | selectattr('dns_ptr','defined') | list | length) == (rdns_records | length)
fail_msg: "Each record must have ip_address and dns_ptr for Robot rDNS."
no_log: "{{ hetzner_no_log | bool }}"
- name: Apply rDNS via Hetzner Robot API
vars:
hetzner_robot_base_url: "{{ HETZNER_ROBOT_BASE_URL }}"
ip_path: "{{ item.ip_address | urlencode }}"
ansible.builtin.uri:
url: "{{ hetzner_robot_base_url }}/rdns/{{ ip_path }}"
method: POST
user: "{{ HETZNER_ROBOT_USER }}"
password: "{{ HETZNER_ROBOT_PASSWORD }}"
force_basic_auth: true
headers:
Accept: application/json
body_format: form-urlencoded
body:
ptr: "{{ item.dns_ptr }}"
status_code: [200, 201]
loop: "{{ rdns_records }}"
loop_control:
label: "{{ item.ip_address }} -> {{ item.dns_ptr }}"
async: "{{ hetzner_async_enabled | ternary(hetzner_async_time, omit) }}"
poll: "{{ hetzner_async_enabled | ternary(hetzner_async_poll, omit) }}"
no_log: "{{ hetzner_no_log | bool }}"