1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
|
#!/usr/bin/env python3
# SPDX-FileCopyrightText: 2026 Matthew Fennell <matthew@fennell.dev>
#
# SPDX-License-Identifier: AGPL-3.0-or-later
import urllib.parse
# We ultimately want the variables to be specified in the double-brace format
# recognised by ansible. However, we don't want those double braces or spaces
# to be encoded, so search for the placeholders ENVSUFFIX and DANEHASH from the
# original selects to replace them after encoding is complete.
def template_url(selects):
url = "&".join(
map(lambda select: urllib.parse.urlencode({"select": select}), selects)
)
url = "https://api.mythic-beasts.com/dns/v2/zones/{{ domain }}/records?" + url
url = url.replace("ENVSUFFIX", "{{ env_suffix }}")
url = url.replace("DANEHASH", "{{ dane_hash }}")
return url
# These select queries specify the records that will be replaced whenever we
# PUT new records to the endpoint.
# For most records, we only specify the host and type. For instance,
# host=chat&type=A will select any A record on the chat subdomain for
# replacement.
# For TLSA records, we additionally specify the data (which for these records
# is the hash of the cert).
# This is crucial to rollover new certs properly: when requesting a new cert
# with a different TLSA hash, we have to first add the new TLSA record, wait
# for propagation, only then update the cert, and finally delete the old
# record. While waiting for propagation, both the old and new TLSA records need
# to be present.
# Therefore, specifying the data prevents us from replacing the TLSA hash of
# the existing cert if we run the playbook while waiting for propagation. It
# simply ensures that a TLSA record with this hash exists, and leaves any
# others alone for manual cleanup.
common_selects = [
"host=chatENVSUFFIX&type=A",
"host=chatENVSUFFIX&type=AAAA",
"host=conferenceENVSUFFIX&type=CNAME",
"host=uploadENVSUFFIX&type=CNAME",
"host=_xmpp-client._tcpENVSUFFIX&type=SRV",
"host=_xmpps-client._tcpENVSUFFIX&type=SRV",
"host=_5222._tcp.chatENVSUFFIX&type=TLSA&data=DANEHASH",
"host=_5223._tcp.chatENVSUFFIX&type=TLSA&data=DANEHASH",
]
non_transport_selects = [
"host=_xmpp-server._tcpENVSUFFIX&type=SRV",
"host=_xmpps-server._tcpENVSUFFIX&type=SRV",
"host=_xmpps-server._tcp.conferenceENVSUFFIX&type=SRV",
"host=_xmpps-server._tcp.uploadENVSUFFIX&type=SRV",
"host=_5269._tcp.chatENVSUFFIX&type=TLSA&data=DANEHASH",
"host=_5270._tcp.chatENVSUFFIX&type=TLSA&data=DANEHASH",
]
common_url = template_url(common_selects)
non_transport_url = template_url(non_transport_selects)
print(common_url)
print(non_transport_url)
|