mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2025-08-29 23:08:06 +02:00
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.
This commit is contained in:
@@ -25,7 +25,7 @@
|
||||
meta: flush_handlers
|
||||
|
||||
- name: "Create Mailu accounts"
|
||||
include_tasks: 02_create-mailu-user.yml
|
||||
include_tasks: 02_create-user.yml
|
||||
vars:
|
||||
MAILU_DOCKER_DIR: "{{ docker_compose.directories.instance }}"
|
||||
mailu_api_base_url: "http://127.0.0.1:8080/api/v1"
|
||||
@@ -45,6 +45,8 @@
|
||||
loop_var: item
|
||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||
|
||||
- name: Generate DKIM public key
|
||||
include_tasks: 04_generate-and-read-dkim.yml
|
||||
|
||||
- name: Set Mailu DNS records
|
||||
include_tasks: 04_set-mailu-dns-records.yml
|
||||
when: DNS_PROVIDER == 'cloudflare'
|
||||
include_tasks: 05_dns-records.yml
|
||||
|
@@ -25,5 +25,5 @@
|
||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||
|
||||
- name: "Create Mailu API Token for {{ mailu_user_name }}"
|
||||
include_tasks: 03_create-mailu-token.yml
|
||||
include_tasks: 03_create-token.yml
|
||||
when: "{{ 'mail-bot' in item.value.roles }}"
|
@@ -1,125 +0,0 @@
|
||||
- name: Generate DKIM public key
|
||||
include_tasks: 05_generate-and-read-dkim.yml
|
||||
|
||||
# A/AAAA record for the mail host in the **Hostname Zone**
|
||||
- name: "Set A record for Mailu host"
|
||||
community.general.cloudflare_dns:
|
||||
api_token: "{{ MAILU_CLOUDFLARE_API_TOKEN }}"
|
||||
zone: "{{ MAILU_HOSTNAME_DNS_ZONE }}"
|
||||
type: A
|
||||
name: "{{ MAILU_HOSTNAME }}" # Fully Qualified Domain Name of the mail host
|
||||
content: "{{ MAILU_IP4_PUBLIC }}"
|
||||
proxied: false
|
||||
ttl: 1
|
||||
state: present
|
||||
async: "{{ ASYNC_TIME if ASYNC_ENABLED | bool else omit }}"
|
||||
poll: "{{ ASYNC_POLL if ASYNC_ENABLED | bool else omit }}"
|
||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||
|
||||
- name: "Set AAAA record for Mailu host"
|
||||
community.general.cloudflare_dns:
|
||||
api_token: "{{ MAILU_CLOUDFLARE_API_TOKEN }}"
|
||||
zone: "{{ MAILU_HOSTNAME_DNS_ZONE }}"
|
||||
type: AAAA
|
||||
name: "{{ MAILU_HOSTNAME }}"
|
||||
content: "{{ MAILU_IP6_PUBLIC }}"
|
||||
proxied: false
|
||||
ttl: 1
|
||||
state: present
|
||||
when: MAILU_IP6_PUBLIC is defined and MAILU_IP6_PUBLIC | length > 0
|
||||
async: "{{ ASYNC_TIME if ASYNC_ENABLED | bool else omit }}"
|
||||
poll: "{{ ASYNC_POLL if ASYNC_ENABLED | bool else omit }}"
|
||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||
|
||||
# Autoconfig CNAME record in the **Mail Domain Zone**
|
||||
- name: "Set CNAME record for autoconfig"
|
||||
community.general.cloudflare_dns:
|
||||
api_token: "{{ MAILU_CLOUDFLARE_API_TOKEN }}"
|
||||
zone: "{{ MAILU_DOMAIN_DNS_ZONE }}"
|
||||
type: CNAME
|
||||
name: "autoconfig.{{ MAILU_DOMAIN_DNS_ZONE }}"
|
||||
value: "{{ MAILU_HOSTNAME }}" # Points to the Mailu host FQDN
|
||||
proxied: false
|
||||
ttl: 1
|
||||
state: present
|
||||
async: "{{ ASYNC_TIME if ASYNC_ENABLED | bool else omit }}"
|
||||
poll: "{{ ASYNC_POLL if ASYNC_ENABLED | bool else omit }}"
|
||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||
|
||||
# MX record in the **Mail Domain Zone**
|
||||
- name: "Set MX record"
|
||||
community.general.cloudflare_dns:
|
||||
api_token: "{{ MAILU_CLOUDFLARE_API_TOKEN }}"
|
||||
zone: "{{ MAILU_DOMAIN_DNS_ZONE }}"
|
||||
type: MX
|
||||
name: "{{ MAILU_DOMAIN }}" # Root mail domain
|
||||
value: "{{ MAILU_HOSTNAME }}" # Points to the Mailu host
|
||||
priority: 10
|
||||
ttl: 1
|
||||
state: present
|
||||
async: "{{ ASYNC_TIME if ASYNC_ENABLED | bool else omit }}"
|
||||
poll: "{{ ASYNC_POLL if ASYNC_ENABLED | bool else omit }}"
|
||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||
|
||||
# SRV records in the **Mail Domain Zone**
|
||||
- name: "Set SRV records"
|
||||
community.general.cloudflare_dns:
|
||||
api_token: "{{ MAILU_CLOUDFLARE_API_TOKEN }}"
|
||||
zone: "{{ MAILU_DOMAIN_DNS_ZONE }}"
|
||||
type: SRV
|
||||
service: "_{{ item.key }}"
|
||||
proto: "_tcp"
|
||||
priority: "{{ item.value.priority }}"
|
||||
weight: "{{ item.value.weight }}"
|
||||
port: "{{ item.value.port }}"
|
||||
value: "{{ MAILU_HOSTNAME }}" # Target = Mailu host FQDN
|
||||
ttl: 1
|
||||
state: present
|
||||
name: "{{ MAILU_DOMAIN }}"
|
||||
loop: "{{ MAILU_DNS_SRV_RECORDS | dict2items }}"
|
||||
ignore_errors: true
|
||||
async: "{{ ASYNC_TIME if ASYNC_ENABLED | bool else omit }}"
|
||||
poll: "{{ ASYNC_POLL if ASYNC_ENABLED | bool else omit }}"
|
||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||
|
||||
# SPF TXT record in the **Mail Domain Zone**
|
||||
- name: "Set SPF TXT record"
|
||||
community.general.cloudflare_dns:
|
||||
api_token: "{{ MAILU_CLOUDFLARE_API_TOKEN }}"
|
||||
zone: "{{ MAILU_DOMAIN_DNS_ZONE }}"
|
||||
type: TXT
|
||||
name: "{{ MAILU_DOMAIN }}"
|
||||
value: "v=spf1 mx a:{{ MAILU_HOSTNAME }} ~all"
|
||||
ttl: 1
|
||||
state: present
|
||||
async: "{{ ASYNC_TIME if ASYNC_ENABLED | bool else omit }}"
|
||||
poll: "{{ ASYNC_POLL if ASYNC_ENABLED | bool else omit }}"
|
||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||
|
||||
# DMARC TXT record in the **Mail Domain Zone**
|
||||
- name: "Set DMARC TXT record"
|
||||
community.general.cloudflare_dns:
|
||||
api_token: "{{ MAILU_CLOUDFLARE_API_TOKEN }}"
|
||||
zone: "{{ MAILU_DOMAIN_DNS_ZONE }}"
|
||||
type: TXT
|
||||
name: "_dmarc.{{ MAILU_DOMAIN_DNS_ZONE }}"
|
||||
value: "v=DMARC1; p=reject; ruf=mailto:{{ MAILU_DMARC_RUF }}; adkim=s; aspf=s"
|
||||
ttl: 1
|
||||
state: present
|
||||
async: "{{ ASYNC_TIME if ASYNC_ENABLED | bool else omit }}"
|
||||
poll: "{{ ASYNC_POLL if ASYNC_ENABLED | bool else omit }}"
|
||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||
|
||||
# DKIM TXT record in the **Mail Domain Zone**
|
||||
- name: "Set DKIM TXT record"
|
||||
community.general.cloudflare_dns:
|
||||
api_token: "{{ MAILU_CLOUDFLARE_API_TOKEN }}"
|
||||
zone: "{{ MAILU_DOMAIN_DNS_ZONE }}"
|
||||
type: TXT
|
||||
name: "dkim._domainkey.{{ MAILU_DOMAIN_DNS_ZONE }}"
|
||||
value: "{{ mailu_dkim_public_key }}"
|
||||
ttl: 1
|
||||
state: present
|
||||
async: "{{ ASYNC_TIME if ASYNC_ENABLED | bool else omit }}"
|
||||
poll: "{{ ASYNC_POLL if ASYNC_ENABLED | bool else omit }}"
|
||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
33
roles/web-app-mailu/tasks/05_dns-records.yml
Normal file
33
roles/web-app-mailu/tasks/05_dns-records.yml
Normal file
@@ -0,0 +1,33 @@
|
||||
- name: "DNS (Cloudflare) for Mailu"
|
||||
include_role:
|
||||
name: sys-dns-cloudflare-records
|
||||
when: DNS_PROVIDER | lower == 'cloudflare'
|
||||
vars:
|
||||
cloudflare_async_enabled: "{{ ASYNC_ENABLED | default(false) | bool }}"
|
||||
cloudflare_async_time: "{{ ASYNC_TIME | default(45) }}"
|
||||
cloudflare_async_poll: "{{ ASYNC_POLL | default(5) }}"
|
||||
cloudflare_no_log: "{{ MASK_CREDENTIALS_IN_LOGS | default(true) | bool }}"
|
||||
cloudflare_records:
|
||||
- { type: A, zone: "{{ MAILU_HOSTNAME_DNS_ZONE }}", name: "{{ MAILU_HOSTNAME }}", content: "{{ MAILU_IP4_PUBLIC }}", proxied: false }
|
||||
# - { type: AAAA, zone: "{{ MAILU_HOSTNAME_DNS_ZONE }}", name: "{{ MAILU_HOSTNAME }}", content: "{{ MAILU_IP6_PUBLIC }}", proxied: false }
|
||||
- { type: CNAME, zone: "{{ MAILU_DOMAIN_DNS_ZONE }}", name: "autoconfig.{{ MAILU_DOMAIN_DNS_ZONE }}", value: "{{ MAILU_HOSTNAME }}" }
|
||||
- { type: MX, zone: "{{ MAILU_DOMAIN_DNS_ZONE }}", name: "{{ MAILU_DOMAIN }}", value: "{{ MAILU_HOSTNAME }}", priority: 10 }
|
||||
- { type: TXT, zone: "{{ MAILU_DOMAIN_DNS_ZONE }}", name: "{{ MAILU_DOMAIN }}", value: "v=spf1 mx a:{{ MAILU_HOSTNAME }} ~all" }
|
||||
- { type: TXT, zone: "{{ MAILU_DOMAIN_DNS_ZONE }}", name: "_dmarc.{{ MAILU_DOMAIN_DNS_ZONE }}", value: "v=DMARC1; p=reject; ruf=mailto:{{ MAILU_DMARC_RUF }}; adkim=s; aspf=s" }
|
||||
- { type: TXT, zone: "{{ MAILU_DOMAIN_DNS_ZONE }}", name: "dkim._domainkey.{{ MAILU_DOMAIN_DNS_ZONE }}", value: "{{ mailu_dkim_public_key }}" }
|
||||
- { type: SRV, zone: "{{ MAILU_DOMAIN_DNS_ZONE }}", service: "_submission", proto: "_tcp", name: "{{ MAILU_DOMAIN }}", priority: 20, weight: 1, port: 587, value: "{{ MAILU_HOSTNAME }}" }
|
||||
- { type: SRV, zone: "{{ MAILU_DOMAIN_DNS_ZONE }}", service: "_submissions", proto: "_tcp", name: "{{ MAILU_DOMAIN }}", priority: 20, weight: 1, port: 465, value: "{{ MAILU_HOSTNAME }}" }
|
||||
- { type: SRV, zone: "{{ MAILU_DOMAIN_DNS_ZONE }}", service: "_imaps", proto: "_tcp", name: "{{ MAILU_DOMAIN }}", priority: 20, weight: 1, port: 993, value: "{{ MAILU_HOSTNAME }}" }
|
||||
- { type: SRV, zone: "{{ MAILU_DOMAIN_DNS_ZONE }}", service: "_imap", proto: "_tcp", name: "{{ MAILU_DOMAIN }}", priority: 20, weight: 1, port: 143, value: "{{ MAILU_HOSTNAME }}" }
|
||||
- { type: SRV, zone: "{{ MAILU_DOMAIN_DNS_ZONE }}", service: "_pop3s", proto: "_tcp", name: "{{ MAILU_DOMAIN }}", priority: 20, weight: 1, port: 995, value: "{{ MAILU_HOSTNAME }}" }
|
||||
- { type: SRV, zone: "{{ MAILU_DOMAIN_DNS_ZONE }}", service: "_pop3", proto: "_tcp", name: "{{ MAILU_DOMAIN }}", priority: 20, weight: 1, port: 110, value: "{{ MAILU_HOSTNAME }}" }
|
||||
- { type: SRV, zone: "{{ MAILU_DOMAIN_DNS_ZONE }}", service: "_autodiscover", proto: "_tcp", name: "{{ MAILU_DOMAIN }}", priority: 20, weight: 1, port: 443, value: "{{ MAILU_HOSTNAME }}" }
|
||||
|
||||
- name: "rDNS (Hetzner Cloud) for Mailu"
|
||||
include_role:
|
||||
name: sys-dns-hetzner-rdns
|
||||
when: HOSTING_PROVIDER | lower == 'hetzner'
|
||||
vars:
|
||||
rdns_records:
|
||||
- { resource: "server", ip_address: "{{ MAILU_IP4_PUBLIC }}", dns_ptr: "{{ MAILU_HOSTNAME }}" }
|
||||
# - { resource: "server", ip_address: "{{ MAILU_IP6_PUBLIC | default('') }}", dns_ptr: "{{ MAILU_HOSTNAME }}" }
|
@@ -43,7 +43,6 @@ MAILU_SUBNET: "{{ networks.local['web-app-mailu'].subnet
|
||||
|
||||
## Credentials
|
||||
MAILU_SECRET_KEY: "{{ applications | get_app_conf(application_id,'credentials.secret_key') }}"
|
||||
MAILU_CLOUDFLARE_API_TOKEN: "{{ CERTBOT_DNS_API_TOKEN }}"
|
||||
MAILU_API_TOKEN: "{{ applications | get_app_conf(application_id, 'credentials.api_token') }}"
|
||||
|
||||
## OIDC
|
||||
@@ -55,16 +54,7 @@ MAILU_OIDC_ENABLE_USER_CREATION: "{{ applications | get_app_conf(applicatio
|
||||
# @see https://github.com/heviat/Mailu-OIDC/tree/2024.06
|
||||
MAILU_DOCKER_FLAVOR: "{{ 'ghcr.io/heviat' if MAILU_OIDC_ENABLED | bool else 'ghcr.io/mailu' }}"
|
||||
|
||||
MAILU_DMARC_RUF: "{{ applications | get_app_conf(application_id, 'users.administrator.email') }}"
|
||||
MAILU_DMARC_RUF: "{{ applications | get_app_conf(application_id, 'users.administrator.email') }}"
|
||||
|
||||
MAILU_DKIM_KEY_FILE: "{{ MAILU_DOMAIN }}.dkim.key"
|
||||
MAILU_DKIM_KEY_PATH: "/dkim/{{ MAILU_DKIM_KEY_FILE }}"
|
||||
|
||||
MAILU_DNS_SRV_RECORDS:
|
||||
submission: { port: 587, priority: 20, weight: 1 }
|
||||
submissions: { port: 465, priority: 20, weight: 1 }
|
||||
imaps: { port: 993, priority: 20, weight: 1 }
|
||||
imap: { port: 143, priority: 20, weight: 1 }
|
||||
pop3s: { port: 995, priority: 20, weight: 1 }
|
||||
pop3: { port: 110, priority: 20, weight: 1 }
|
||||
autodiscover: { port: 443, priority: 20, weight: 1 }
|
||||
MAILU_DKIM_KEY_FILE: "{{ MAILU_DOMAIN }}.dkim.key"
|
||||
MAILU_DKIM_KEY_PATH: "/dkim/{{ MAILU_DKIM_KEY_FILE }}"
|
||||
|
Reference in New Issue
Block a user