Add Ansible/playbook_netcup_tlsa_dane.yaml
This commit is contained in:
303
Ansible/playbook_netcup_tlsa_dane.yaml
Normal file
303
Ansible/playbook_netcup_tlsa_dane.yaml
Normal file
@@ -0,0 +1,303 @@
|
|||||||
|
---
|
||||||
|
- name: Zertifikate auf Mailcow (vom NPM) aktualisieren
|
||||||
|
hosts: localhost
|
||||||
|
gather_facts: false
|
||||||
|
|
||||||
|
vars:
|
||||||
|
# Host-Konfiguration
|
||||||
|
debug_dane: true
|
||||||
|
|
||||||
|
nginxproxymanager_host: npm
|
||||||
|
mailcow_host: mailcow
|
||||||
|
tlsa_host_label: "_25._tcp.mail"
|
||||||
|
|
||||||
|
# Mailcow Variablen
|
||||||
|
mailcow_cert_path: "/opt/mailcow-dockerized/data/assets/ssl/cert.pem"
|
||||||
|
mailcow_key_path: "/opt/mailcow-dockerized/data/assets/ssl/key.pem"
|
||||||
|
mailcow_owner: "root"
|
||||||
|
mailcow_group: "root"
|
||||||
|
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
################################################################
|
||||||
|
# 1) Neues Zertifikat/Key vom NginxProxyManager einlesen
|
||||||
|
################################################################
|
||||||
|
- name: "Neues Zertifikat vom NginxProxyManager slurpen"
|
||||||
|
slurp:
|
||||||
|
src: "{{ letsencrypt_cert }}"
|
||||||
|
delegate_to: "{{ nginxproxymanager_host }}"
|
||||||
|
register: new_cert_slurp
|
||||||
|
|
||||||
|
- name: "Neuen Key vom NginxProxyManager slurpen"
|
||||||
|
slurp:
|
||||||
|
src: "{{ letsencrypt_key }}"
|
||||||
|
delegate_to: "{{ nginxproxymanager_host }}"
|
||||||
|
register: new_key_slurp
|
||||||
|
|
||||||
|
################################################################
|
||||||
|
# 2) Mailcow-Check und -Update
|
||||||
|
################################################################
|
||||||
|
- name: "Mailcow: Altes Zertifikat (cert.pem) auslesen"
|
||||||
|
slurp:
|
||||||
|
src: "{{ mailcow_cert_path }}"
|
||||||
|
delegate_to: "{{ mailcow_host }}"
|
||||||
|
register: mailcow_old_cert
|
||||||
|
ignore_errors: true
|
||||||
|
|
||||||
|
- name: "Mailcow: Alter Key (key.pem) auslesen"
|
||||||
|
slurp:
|
||||||
|
src: "{{ mailcow_key_path }}"
|
||||||
|
delegate_to: "{{ mailcow_host }}"
|
||||||
|
register: mailcow_old_key
|
||||||
|
ignore_errors: true
|
||||||
|
|
||||||
|
- name: "Mailcow: Prüfen, ob Zertifikat oder Key neu sind"
|
||||||
|
set_fact:
|
||||||
|
mailcow_cert_is_new: >-
|
||||||
|
{{
|
||||||
|
(new_cert_slurp.content | b64decode) !=
|
||||||
|
(mailcow_old_cert.content is defined
|
||||||
|
and (mailcow_old_cert.content | b64decode)
|
||||||
|
or '')
|
||||||
|
or
|
||||||
|
(new_key_slurp.content | b64decode) !=
|
||||||
|
(mailcow_old_key.content is defined
|
||||||
|
and (mailcow_old_key.content | b64decode)
|
||||||
|
or '')
|
||||||
|
}}
|
||||||
|
|
||||||
|
- name: "Mailcow: Debug-Ausgabe, ob das Zertifikat neu ist"
|
||||||
|
debug:
|
||||||
|
msg: "Mailcow: Zertifikat neu? {{ mailcow_cert_is_new }}"
|
||||||
|
|
||||||
|
- name: "Mailcow: Zertifikatsupdate"
|
||||||
|
block:
|
||||||
|
- name: "Mailcow: Docker Compose stoppen"
|
||||||
|
ansible.builtin.shell: |
|
||||||
|
docker compose down
|
||||||
|
args:
|
||||||
|
chdir: "/opt/mailcow-dockerized/"
|
||||||
|
delegate_to: "{{ mailcow_host }}"
|
||||||
|
|
||||||
|
- name: "Mailcow: Neues Zertifikat (cert.pem) kopieren"
|
||||||
|
copy:
|
||||||
|
content: "{{ new_cert_slurp.content | b64decode }}"
|
||||||
|
dest: "{{ mailcow_cert_path }}"
|
||||||
|
owner: "{{ mailcow_owner }}"
|
||||||
|
group: "{{ mailcow_group }}"
|
||||||
|
mode: "0644"
|
||||||
|
delegate_to: "{{ mailcow_host }}"
|
||||||
|
|
||||||
|
- name: "Mailcow: Neuen Key (key.pem) kopieren"
|
||||||
|
copy:
|
||||||
|
content: "{{ new_key_slurp.content | b64decode }}"
|
||||||
|
dest: "{{ mailcow_key_path }}"
|
||||||
|
owner: "{{ mailcow_owner }}"
|
||||||
|
group: "{{ mailcow_group }}"
|
||||||
|
mode: "0644"
|
||||||
|
delegate_to: "{{ mailcow_host }}"
|
||||||
|
|
||||||
|
- name: "Mailcow: Docker Compose neu starten (force-recreate)"
|
||||||
|
ansible.builtin.shell: |
|
||||||
|
docker compose up -d --force-recreate
|
||||||
|
args:
|
||||||
|
chdir: "/opt/mailcow-dockerized/"
|
||||||
|
delegate_to: "{{ mailcow_host }}"
|
||||||
|
when: mailcow_cert_is_new
|
||||||
|
|
||||||
|
################################################################
|
||||||
|
# 3) TLSA-Record bei Netcup aktualisieren
|
||||||
|
################################################################
|
||||||
|
- name: "DANE: TLSA-Hash aus slurped cert.pem erzeugen (3 1 1)"
|
||||||
|
shell: |
|
||||||
|
echo "{{ mailcow_old_cert.content | b64decode }}" |
|
||||||
|
openssl x509 -pubkey -noout |
|
||||||
|
openssl pkey -pubin -outform DER |
|
||||||
|
openssl dgst -sha256 -binary |
|
||||||
|
hexdump -ve '1/1 "%.2x"'
|
||||||
|
register: tlsa_hash_result
|
||||||
|
changed_when: false
|
||||||
|
delegate_to: localhost
|
||||||
|
|
||||||
|
- name: "DANE: CA Issuer URI aus slurped cert.pem extrahieren"
|
||||||
|
shell: |
|
||||||
|
echo "{{ mailcow_old_cert.content | b64decode }}" |
|
||||||
|
openssl x509 -text -noout |
|
||||||
|
grep "CA Issuers" | sed -n 's/.*URI://p'
|
||||||
|
register: ca_uri_result
|
||||||
|
changed_when: false
|
||||||
|
delegate_to: localhost
|
||||||
|
|
||||||
|
- name: "DANE: TLSA-Hash der CA erzeugen (2 1 1)"
|
||||||
|
shell: |
|
||||||
|
wget -qO- "{{ ca_uri_result.stdout }}" |
|
||||||
|
openssl x509 -inform DER -outform PEM |
|
||||||
|
openssl x509 -pubkey -noout |
|
||||||
|
openssl pkey -pubin -outform DER |
|
||||||
|
openssl dgst -sha256 -binary |
|
||||||
|
hexdump -ve '1/1 "%.2x"'
|
||||||
|
register: tlsa_hash_ca_result
|
||||||
|
changed_when: false
|
||||||
|
when: ca_uri_result.stdout | length > 0
|
||||||
|
delegate_to: localhost
|
||||||
|
|
||||||
|
- name: "DANE: TLSA-Hashes speichern"
|
||||||
|
set_fact:
|
||||||
|
tlsa_hash_current: "{{ tlsa_hash_result.stdout }}"
|
||||||
|
tlsa_hash_ca: "{{ tlsa_hash_ca_result.stdout | default('') }}"
|
||||||
|
|
||||||
|
- name: "DANE: Netcup API Login"
|
||||||
|
uri:
|
||||||
|
url: "https://ccp.netcup.net/run/webservice/servers/endpoint.php?JSON"
|
||||||
|
method: POST
|
||||||
|
body_format: json
|
||||||
|
return_content: true
|
||||||
|
body:
|
||||||
|
action: "login"
|
||||||
|
param:
|
||||||
|
customernumber: "{{ netcup_customer_number }}"
|
||||||
|
apikey: "{{ netcup_api_key }}"
|
||||||
|
apipassword: "{{ netcup_api_password }}"
|
||||||
|
register: netcup_login
|
||||||
|
delegate_to: localhost
|
||||||
|
|
||||||
|
- name: "DANE: Session-ID sichern"
|
||||||
|
set_fact:
|
||||||
|
netcup_session_id: "{{ netcup_login.json.responsedata.apisessionid }}"
|
||||||
|
|
||||||
|
- name: "DANE: DNS-Records abrufen"
|
||||||
|
uri:
|
||||||
|
url: "https://ccp.netcup.net/run/webservice/servers/endpoint.php?JSON"
|
||||||
|
method: POST
|
||||||
|
body_format: json
|
||||||
|
return_content: true
|
||||||
|
body:
|
||||||
|
action: "infoDnsRecords"
|
||||||
|
param:
|
||||||
|
customernumber: "{{ netcup_customer_number }}"
|
||||||
|
apikey: "{{ netcup_api_key }}"
|
||||||
|
apisessionid: "{{ netcup_session_id }}"
|
||||||
|
domainname: "{{ netcup_domain }}"
|
||||||
|
register: netcup_dns_info
|
||||||
|
delegate_to: localhost
|
||||||
|
|
||||||
|
- name: "DANE: Bestehende TLSA-Records extrahieren"
|
||||||
|
set_fact:
|
||||||
|
existing_tlsa_record: >-
|
||||||
|
{{
|
||||||
|
(netcup_dns_info.json.responsedata.dnsrecords | selectattr('hostname', 'equalto', tlsa_host_label)
|
||||||
|
| selectattr('type', 'equalto', 'TLSA')
|
||||||
|
| selectattr('destination', 'search', '^3 1 1 ')
|
||||||
|
| list | first)
|
||||||
|
}}
|
||||||
|
existing_tlsa_record_ca: >-
|
||||||
|
{{
|
||||||
|
(netcup_dns_info.json.responsedata.dnsrecords | selectattr('hostname', 'equalto', tlsa_host_label)
|
||||||
|
| selectattr('type', 'equalto', 'TLSA')
|
||||||
|
| selectattr('destination', 'search', '^2 1 1 ')
|
||||||
|
| list | first)
|
||||||
|
}}
|
||||||
|
|
||||||
|
- name: "DANE: TLSA-Record (3 1 1) aktualisieren"
|
||||||
|
block:
|
||||||
|
- name: "DANE: TLSA-Record (3 1 1) wird aktualisiert"
|
||||||
|
uri:
|
||||||
|
url: "https://ccp.netcup.net/run/webservice/servers/endpoint.php?JSON"
|
||||||
|
method: POST
|
||||||
|
body_format: json
|
||||||
|
status_code: 200
|
||||||
|
body:
|
||||||
|
action: "updateDnsRecords"
|
||||||
|
param:
|
||||||
|
customernumber: "{{ netcup_customer_number }}"
|
||||||
|
apikey: "{{ netcup_api_key }}"
|
||||||
|
apisessionid: "{{ netcup_session_id }}"
|
||||||
|
domainname: "{{ netcup_domain }}"
|
||||||
|
dnsrecordset:
|
||||||
|
dnsrecords:
|
||||||
|
- id: "{{ existing_tlsa_record.id if existing_tlsa_record is defined else omit }}"
|
||||||
|
hostname: "{{ tlsa_host_label }}"
|
||||||
|
type: "TLSA"
|
||||||
|
destination: "3 1 1 {{ tlsa_hash_current }}"
|
||||||
|
state: "yes"
|
||||||
|
delegate_to: localhost
|
||||||
|
|
||||||
|
- name: "DANE: TLSA-Record (3 1 1) prüfen"
|
||||||
|
uri:
|
||||||
|
url: "https://ccp.netcup.net/run/webservice/servers/endpoint.php?JSON"
|
||||||
|
method: POST
|
||||||
|
body_format: json
|
||||||
|
return_content: true
|
||||||
|
body:
|
||||||
|
action: "infoDnsRecords"
|
||||||
|
param:
|
||||||
|
customernumber: "{{ netcup_customer_number }}"
|
||||||
|
apikey: "{{ netcup_api_key }}"
|
||||||
|
apisessionid: "{{ netcup_session_id }}"
|
||||||
|
domainname: "{{ netcup_domain }}"
|
||||||
|
register: netcup_verify_311
|
||||||
|
delegate_to: localhost
|
||||||
|
|
||||||
|
- name: "DANE: TLSA-Record (3 1 1) verifizieren"
|
||||||
|
set_fact:
|
||||||
|
verified_tlsa_311: >-
|
||||||
|
{{
|
||||||
|
(netcup_verify_311.json.responsedata.dnsrecords | selectattr('hostname', 'equalto', tlsa_host_label)
|
||||||
|
| selectattr('type', 'equalto', 'TLSA')
|
||||||
|
| selectattr('destination', 'equalto', '3 1 1 ' ~ tlsa_hash_current)
|
||||||
|
| list | length > 0)
|
||||||
|
}}
|
||||||
|
when: existing_tlsa_record is not defined or existing_tlsa_record.destination != ('3 1 1 ' ~ tlsa_hash_current)
|
||||||
|
|
||||||
|
- name: "DANE: TLSA-Record (2 1 1) aktualisieren"
|
||||||
|
block:
|
||||||
|
- name: "DANE: TLSA-Record (2 1 1) wird aktualisiert"
|
||||||
|
uri:
|
||||||
|
url: "https://ccp.netcup.net/run/webservice/servers/endpoint.php?JSON"
|
||||||
|
method: POST
|
||||||
|
body_format: json
|
||||||
|
status_code: 200
|
||||||
|
body:
|
||||||
|
action: "updateDnsRecords"
|
||||||
|
param:
|
||||||
|
customernumber: "{{ netcup_customer_number }}"
|
||||||
|
apikey: "{{ netcup_api_key }}"
|
||||||
|
apisessionid: "{{ netcup_session_id }}"
|
||||||
|
domainname: "{{ netcup_domain }}"
|
||||||
|
dnsrecordset:
|
||||||
|
dnsrecords:
|
||||||
|
- id: "{{ existing_tlsa_record_ca.id if existing_tlsa_record_ca is defined else omit }}"
|
||||||
|
hostname: "{{ tlsa_host_label }}"
|
||||||
|
type: "TLSA"
|
||||||
|
destination: "2 1 1 {{ tlsa_hash_ca }}"
|
||||||
|
state: "yes"
|
||||||
|
delegate_to: localhost
|
||||||
|
|
||||||
|
- name: "DANE: TLSA-Record (2 1 1) prüfen"
|
||||||
|
uri:
|
||||||
|
url: "https://ccp.netcup.net/run/webservice/servers/endpoint.php?JSON"
|
||||||
|
method: POST
|
||||||
|
body_format: json
|
||||||
|
return_content: true
|
||||||
|
body:
|
||||||
|
action: "infoDnsRecords"
|
||||||
|
param:
|
||||||
|
customernumber: "{{ netcup_customer_number }}"
|
||||||
|
apikey: "{{ netcup_api_key }}"
|
||||||
|
apisessionid: "{{ netcup_session_id }}"
|
||||||
|
domainname: "{{ netcup_domain }}"
|
||||||
|
register: netcup_verify_211
|
||||||
|
delegate_to: localhost
|
||||||
|
|
||||||
|
- name: "DANE: TLSA-Record (2 1 1) verifizieren"
|
||||||
|
set_fact:
|
||||||
|
verified_tlsa_211: >-
|
||||||
|
{{
|
||||||
|
(netcup_verify_211.json.responsedata.dnsrecords | selectattr('hostname', 'equalto', tlsa_host_label)
|
||||||
|
| selectattr('type', 'equalto', 'TLSA')
|
||||||
|
| selectattr('destination', 'equalto', '2 1 1 ' ~ tlsa_hash_ca)
|
||||||
|
| list | length > 0)
|
||||||
|
}}
|
||||||
|
when: tlsa_hash_ca | length > 0 and
|
||||||
|
(existing_tlsa_record_ca is not defined or
|
||||||
|
existing_tlsa_record_ca.destination != ('2 1 1 ' ~ tlsa_hash_ca))
|
||||||
Reference in New Issue
Block a user