From d73a1baf5128973cf7ce18369d2b71e67f1f604b Mon Sep 17 00:00:00 2001 From: j4n Date: Mon, 30 Mar 2026 08:39:40 +0200 Subject: [PATCH] fix(cmdeploy/dns): align zones, add multiline test records And add requirements to lxc docs --- cmdeploy/src/cmdeploy/dns.py | 37 ++++++++++++-------- cmdeploy/src/cmdeploy/remote/rdns.py | 5 +-- cmdeploy/src/cmdeploy/tests/data/zftest.zone | 30 ++++++++-------- cmdeploy/src/cmdeploy/tests/test_dns.py | 17 +++++++++ doc/source/lxc.rst | 4 +++ 5 files changed, 61 insertions(+), 32 deletions(-) diff --git a/cmdeploy/src/cmdeploy/dns.py b/cmdeploy/src/cmdeploy/dns.py index adfdb3f4..639047c0 100644 --- a/cmdeploy/src/cmdeploy/dns.py +++ b/cmdeploy/src/cmdeploy/dns.py @@ -47,33 +47,40 @@ def get_filled_zone_file(remote_data): remote_data["sts_id"] = datetime.datetime.now().strftime("%Y%m%d%H%M") d = remote_data["mail_domain"] + + def rec(name, rtype, rdata, ttl=3600): + return f"{name:<40} {ttl:<6} IN {rtype:<5} {rdata}" + lines = ["; Required DNS entries"] if remote_data.get("A"): - lines.append(f"{d}. 3600 IN A {remote_data['A']}") + lines.append(rec(f"{d}.", "A", remote_data["A"])) if remote_data.get("AAAA"): - lines.append(f"{d}. 3600 IN AAAA {remote_data['AAAA']}") - lines.append(f"{d}. 3600 IN MX 10 {d}.") + lines.append(rec(f"{d}.", "AAAA", remote_data["AAAA"])) + lines.append(rec(f"{d}.", "MX", f"10 {d}.")) if remote_data.get("strict_tls"): lines.append( - f'_mta-sts.{d}. 3600 IN TXT "v=STSv1; id={remote_data["sts_id"]}"' + rec(f"_mta-sts.{d}.", "TXT", f'"v=STSv1; id={remote_data["sts_id"]}"') ) - lines.append(f"mta-sts.{d}. 3600 IN CNAME {d}.") - lines.append(f"www.{d}. 3600 IN CNAME {d}.") + lines.append(rec(f"mta-sts.{d}.", "CNAME", f"{d}.")) + lines.append(rec(f"www.{d}.", "CNAME", f"{d}.")) lines.append(remote_data["dkim_entry"]) lines.append("") lines.append("; Recommended DNS entries") - lines.append(f'{d}. 3600 IN TXT "v=spf1 a ~all"') - lines.append(f'_dmarc.{d}. 3600 IN TXT "v=DMARC1;p=reject;adkim=s;aspf=s"') + lines.append(rec(f"{d}.", "TXT", '"v=spf1 a ~all"')) + lines.append(rec(f"_dmarc.{d}.", "TXT", '"v=DMARC1;p=reject;adkim=s;aspf=s"')) if remote_data.get("acme_account_url"): lines.append( - f"{d}. 3600 IN CAA 0 issue" - f' "letsencrypt.org;accounturi={remote_data["acme_account_url"]}"' + rec( + f"{d}.", + "CAA", + f'0 issue "letsencrypt.org;accounturi={remote_data["acme_account_url"]}"', + ) ) - lines.append(f'_adsp._domainkey.{d}. 3600 IN TXT "dkim=discardable"') - lines.append(f"_submission._tcp.{d}. 3600 IN SRV 0 1 587 {d}.") - lines.append(f"_submissions._tcp.{d}. 3600 IN SRV 0 1 465 {d}.") - lines.append(f"_imap._tcp.{d}. 3600 IN SRV 0 1 143 {d}.") - lines.append(f"_imaps._tcp.{d}. 3600 IN SRV 0 1 993 {d}.") + lines.append(rec(f"_adsp._domainkey.{d}.", "TXT", '"dkim=discardable"')) + lines.append(rec(f"_submission._tcp.{d}.", "SRV", f"0 1 587 {d}.")) + lines.append(rec(f"_submissions._tcp.{d}.", "SRV", f"0 1 465 {d}.")) + lines.append(rec(f"_imap._tcp.{d}.", "SRV", f"0 1 143 {d}.")) + lines.append(rec(f"_imaps._tcp.{d}.", "SRV", f"0 1 993 {d}.")) lines.append("") return "\n".join(lines) diff --git a/cmdeploy/src/cmdeploy/remote/rdns.py b/cmdeploy/src/cmdeploy/remote/rdns.py index 3b1d5292..cd6ff488 100644 --- a/cmdeploy/src/cmdeploy/remote/rdns.py +++ b/cmdeploy/src/cmdeploy/remote/rdns.py @@ -57,9 +57,10 @@ def get_dkim_entry(mail_domain, pre_command, dkim_selector): dkim_value_raw = f"v=DKIM1;k=rsa;p={dkim_pubkey};s=email;t=s" dkim_value = '" "'.join(re.findall(".{1,255}", dkim_value_raw)) web_dkim_value = "".join(re.findall(".{1,255}", dkim_value_raw)) + name = f"{dkim_selector}._domainkey.{mail_domain}." return ( - f'{dkim_selector}._domainkey.{mail_domain}. 3600 IN TXT "{dkim_value}"', - f'{dkim_selector}._domainkey.{mail_domain}. 3600 IN TXT "{web_dkim_value}"', + f'{name:<40} 3600 IN TXT "{dkim_value}"', + f'{name:<40} 3600 IN TXT "{web_dkim_value}"', ) diff --git a/cmdeploy/src/cmdeploy/tests/data/zftest.zone b/cmdeploy/src/cmdeploy/tests/data/zftest.zone index 7ee9f0bf..fbce1e5e 100644 --- a/cmdeploy/src/cmdeploy/tests/data/zftest.zone +++ b/cmdeploy/src/cmdeploy/tests/data/zftest.zone @@ -1,18 +1,18 @@ ; Required DNS entries -zftest.testrun.org. 3600 IN A 135.181.204.127 -zftest.testrun.org. 3600 IN AAAA 2a01:4f9:c012:52f4::1 -zftest.testrun.org. 3600 IN MX 10 zftest.testrun.org. -_mta-sts.zftest.testrun.org. 3600 IN TXT "v=STSv1; id=202403211706" -mta-sts.zftest.testrun.org. 3600 IN CNAME zftest.testrun.org. -www.zftest.testrun.org. 3600 IN CNAME zftest.testrun.org. -opendkim._domainkey.zftest.testrun.org. 3600 IN TXT "v=DKIM1;k=rsa;p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoYt82CVUyz2ouaqjX2kB+5J80knAyoOU3MGU5aWppmwUwwTvj/oSTSpkc5JMtVTRmKKr8NUDWAL1Yw7dfGqqPHdHfwwjS3BIvDzYx+hzgtz62RnfNgV+/2MAoNpfX7cAFIHdRzEHNtwugc3RDLquqPoupAE3Y2YRw2T5zG5fILh4vwIcJZL5Uq6B92j8wwJqOex" "33n+vm1NKQ9rxo/UsHAmZlJzpooXcG/4igTBxJyJlamVSRR6N7Nul1v//YJb7J6v2o0iPHW6uE0StzKaPPNC2IVosSRFbD9H2oqppltptFSNPlI0E+t0JBWHem6YK7xcugiO3ImMCaaU8g6Jt/wIDAQAB;s=email;t=s" +zftest.testrun.org. 3600 IN A 135.181.204.127 +zftest.testrun.org. 3600 IN AAAA 2a01:4f9:c012:52f4::1 +zftest.testrun.org. 3600 IN MX 10 zftest.testrun.org. +_mta-sts.zftest.testrun.org. 3600 IN TXT "v=STSv1; id=202403211706" +mta-sts.zftest.testrun.org. 3600 IN CNAME zftest.testrun.org. +www.zftest.testrun.org. 3600 IN CNAME zftest.testrun.org. +opendkim._domainkey.zftest.testrun.org. 3600 IN TXT "v=DKIM1;k=rsa;p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoYt82CVUyz2ouaqjX2kB+5J80knAyoOU3MGU5aWppmwUwwTvj/oSTSpkc5JMtVTRmKKr8NUDWAL1Yw7dfGqqPHdHfwwjS3BIvDzYx+hzgtz62RnfNgV+/2MAoNpfX7cAFIHdRzEHNtwugc3RDLquqPoupAE3Y2YRw2T5zG5fILh4vwIcJZL5Uq6B92j8wwJqOex" "33n+vm1NKQ9rxo/UsHAmZlJzpooXcG/4igTBxJyJlamVSRR6N7Nul1v//YJb7J6v2o0iPHW6uE0StzKaPPNC2IVosSRFbD9H2oqppltptFSNPlI0E+t0JBWHem6YK7xcugiO3ImMCaaU8g6Jt/wIDAQAB;s=email;t=s" ; Recommended DNS entries -zftest.testrun.org. 3600 IN TXT "v=spf1 a ~all" -_dmarc.zftest.testrun.org. 3600 IN TXT "v=DMARC1;p=reject;adkim=s;aspf=s" -zftest.testrun.org. 3600 IN CAA 0 issue "letsencrypt.org;accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/1371472956" -_adsp._domainkey.zftest.testrun.org. 3600 IN TXT "dkim=discardable" -_submission._tcp.zftest.testrun.org. 3600 IN SRV 0 1 587 zftest.testrun.org. -_submissions._tcp.zftest.testrun.org. 3600 IN SRV 0 1 465 zftest.testrun.org. -_imap._tcp.zftest.testrun.org. 3600 IN SRV 0 1 143 zftest.testrun.org. -_imaps._tcp.zftest.testrun.org. 3600 IN SRV 0 1 993 zftest.testrun.org. +zftest.testrun.org. 3600 IN TXT "v=spf1 a ~all" +_dmarc.zftest.testrun.org. 3600 IN TXT "v=DMARC1;p=reject;adkim=s;aspf=s" +zftest.testrun.org. 3600 IN CAA 0 issue "letsencrypt.org;accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/1371472956" +_adsp._domainkey.zftest.testrun.org. 3600 IN TXT "dkim=discardable" +_submission._tcp.zftest.testrun.org. 3600 IN SRV 0 1 587 zftest.testrun.org. +_submissions._tcp.zftest.testrun.org. 3600 IN SRV 0 1 465 zftest.testrun.org. +_imap._tcp.zftest.testrun.org. 3600 IN SRV 0 1 143 zftest.testrun.org. +_imaps._tcp.zftest.testrun.org. 3600 IN SRV 0 1 993 zftest.testrun.org. diff --git a/cmdeploy/src/cmdeploy/tests/test_dns.py b/cmdeploy/src/cmdeploy/tests/test_dns.py index fc9cd299..35a190b5 100644 --- a/cmdeploy/src/cmdeploy/tests/test_dns.py +++ b/cmdeploy/src/cmdeploy/tests/test_dns.py @@ -132,11 +132,28 @@ def test_parse_zone_records(): ; Another comment www.some.domain. 3600 IN CNAME some.domain. + + ; Multi-word rdata + some.domain. 3600 IN MX 10 mail.some.domain. + + ; DKIM record (single line, multi-word TXT rdata) + dkim._domainkey.some.domain. 3600 IN TXT "v=DKIM1;k=rsa;p=MIIBIjANBgkqhkiG" "9w0BAQEFAAOCAQ8AMIIBCgKCAQEA" + + ; Another TXT record + _dmarc.some.domain. 3600 IN TXT "v=DMARC1;p=reject" """ records = list(parse_zone_records(text)) assert records == [ ("some.domain", "3600", "A", "1.1.1.1"), ("www.some.domain", "3600", "CNAME", "some.domain."), + ("some.domain", "3600", "MX", "10 mail.some.domain."), + ( + "dkim._domainkey.some.domain", + "3600", + "TXT", + '"v=DKIM1;k=rsa;p=MIIBIjANBgkqhkiG" "9w0BAQEFAAOCAQ8AMIIBCgKCAQEA"', + ), + ("_dmarc.some.domain", "3600", "TXT", '"v=DMARC1;p=reject"'), ] diff --git a/doc/source/lxc.rst b/doc/source/lxc.rst index 6bd60da1..9e447e94 100644 --- a/doc/source/lxc.rst +++ b/doc/source/lxc.rst @@ -15,6 +15,10 @@ as they would on a real Debian server or cloud VPS. Prerequisites ------------- +- Around 4-5 GiB free disk space +- `systemd-networkd` for the automagic hostname resolution +- No other service occupying Port 53 + Install `Incus `_ (LXC container manager). See the `official installation guide