forked from critical/dns-zones
Merge pull request 'add-secondary-ns-support' (#5) from add-secondary-ns-support into main
Reviewed-on: critical/dns-zones#5 Reviewed-by: Dirk Astrath <dirk@cacert.org>
This commit is contained in:
commit
1d6b970a6a
3 changed files with 105 additions and 32 deletions
72
README.md
Normal file
72
README.md
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
# CAcert DNS zones
|
||||||
|
|
||||||
|
CAcert runs its own public DNS nameservers on ns1 and ns2 in its BIT datacenter
|
||||||
|
rack in Ede.
|
||||||
|
|
||||||
|
We use [PowerDNS](https://doc.powerdns.com/authoritative/index.html) installed
|
||||||
|
on Debian systems.
|
||||||
|
|
||||||
|
This repository contains a Python script `update-zones.py` that is used for
|
||||||
|
updating DNS information from this Git repository.
|
||||||
|
|
||||||
|
The canonical URL for this repository is
|
||||||
|
[https://code.cacert.org/critical/dns-zones.git](https://code.cacert.org/critical/dns-zones.git).
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
The server certificate for https://code.cacert.org/ needs to be trusted.
|
||||||
|
Therefore the CAcert root CA certificate needs to be put into
|
||||||
|
`/usr/local/share/ca-certificates` and hast to be registered as trusted by
|
||||||
|
running
|
||||||
|
|
||||||
|
```shell
|
||||||
|
update-ca-certificates
|
||||||
|
```
|
||||||
|
|
||||||
|
The `update-zones.py` script needs `git`, `pdnsutil` and `python3`. We only use
|
||||||
|
the Python 3 standard library and no external dependencies. The script uses
|
||||||
|
`/usr/lib/sendmail` to send change mails. Mail sending has been tested with
|
||||||
|
ssmtp and exim4.
|
||||||
|
|
||||||
|
To make sure that all these prerequisites are met, you may run
|
||||||
|
|
||||||
|
```shell
|
||||||
|
apt install python3 ca-certificates pdns-server git mail-transport-agent
|
||||||
|
```
|
||||||
|
|
||||||
|
## Cloning the repository
|
||||||
|
|
||||||
|
The git configuration on ns1 and ns2 has been adapted to allow remembering the
|
||||||
|
credentials to clone the repository. A separate user pdnssync has been setup to
|
||||||
|
allow cloning the repository.
|
||||||
|
|
||||||
|
This repository is meant to be cloned on the CAcert DNS servers ns1 and ns2.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
cd ~
|
||||||
|
git config --global credential.helper store
|
||||||
|
git config --global pull.ff only
|
||||||
|
git clone https://code.cacert.org/critical/dns-zones.git
|
||||||
|
```
|
||||||
|
|
||||||
|
Credentials will only be asked for the initial clone. The credential helper
|
||||||
|
records them in in `~/.git-credentials`.
|
||||||
|
|
||||||
|
## Updating zones
|
||||||
|
|
||||||
|
The user running the update needs read access to the configuration in
|
||||||
|
`/etc/powerdns` (either member of the pdns group or root).
|
||||||
|
|
||||||
|
```
|
||||||
|
$ cd ~/dns-zones
|
||||||
|
$ git pull
|
||||||
|
$ ./update-zones.py
|
||||||
|
```
|
||||||
|
|
||||||
|
The `update-zones.py` tracks the local status in a branch (default
|
||||||
|
'provisioned') that is updated when
|
||||||
|
|
||||||
|
* a) zone changes have been applied
|
||||||
|
* b) the running PowerDNS is responsible as secondary nameserver
|
||||||
|
|
||||||
|
The `update-zones.py` script should be run on both nameservers.
|
21
import_zone
21
import_zone
|
@ -1,21 +0,0 @@
|
||||||
set -x
|
|
||||||
domain=$1
|
|
||||||
now=$(date +"%Y%m%d_%H%M%S")
|
|
||||||
pdnsutil list-zone $1 > $1.$now
|
|
||||||
grep -v SOA $1 >$1.new
|
|
||||||
grep SOA $1.$now >> $1.new
|
|
||||||
pdnsutil load-zone $1 $1.new
|
|
||||||
pdnsutil increase-serial $1
|
|
||||||
mysqldump powerdns > powerdns.dump.$now
|
|
||||||
|
|
||||||
echo "From: Nameserver NS2 <root@ns2.cacert.org>" > mail.txt
|
|
||||||
echo "To: critical-admin@cacert.org" >> mail.txt
|
|
||||||
echo "Subject: Update of zone $1" >> mail.txt
|
|
||||||
#echo "$1 has now the following zonefile-data:" >>mail.txt
|
|
||||||
pdnsutil list-zone $1 > $1.now
|
|
||||||
echo >>mail.txt
|
|
||||||
diff -u0 -b $1.$now $1.now >>mail.txt
|
|
||||||
echo " ------------------------- " >> mail.txt
|
|
||||||
pdnsutil list-zone $1 >> mail.txt
|
|
||||||
|
|
||||||
cat mail.txt | ssmtp -6 critical-admin@cacert.org
|
|
|
@ -44,11 +44,13 @@ def git_changed_files(reference_branch, target_branch):
|
||||||
return output.strip().splitlines()
|
return output.strip().splitlines()
|
||||||
|
|
||||||
|
|
||||||
def pdns_managed_zones():
|
def pdns_managed_zones(secondary_only=False):
|
||||||
|
command = ["pdnsutil", "list-all-zones"]
|
||||||
|
if secondary_only:
|
||||||
|
command += ["slave"]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
all_zones = run(
|
all_zones = run(command, check=True, capture_output=True, text=True)
|
||||||
["pdnsutil", "list-all-zones"], check=True, capture_output=True, text=True
|
|
||||||
)
|
|
||||||
zones = all_zones.stdout.strip().splitlines()
|
zones = all_zones.stdout.strip().splitlines()
|
||||||
except CalledProcessError as e:
|
except CalledProcessError as e:
|
||||||
print(
|
print(
|
||||||
|
@ -75,6 +77,14 @@ def calculate_changed_zones(files, zones):
|
||||||
return sorted(set(files).intersection(zones))
|
return sorted(set(files).intersection(zones))
|
||||||
|
|
||||||
|
|
||||||
|
def remove_secondary_zones(changed_zones):
|
||||||
|
"""
|
||||||
|
Remove DNS zones from the given set where the current server is a secondary DNS server.
|
||||||
|
"""
|
||||||
|
secondary_zones = pdns_managed_zones(secondary_only=True)
|
||||||
|
return sorted(set(changed_zones).difference(secondary_zones))
|
||||||
|
|
||||||
|
|
||||||
def generate_diff(zone, reference_branch, target_branch):
|
def generate_diff(zone, reference_branch, target_branch):
|
||||||
diffresult = run(
|
diffresult = run(
|
||||||
["git", "diff", f"{reference_branch}..{target_branch}", "--", zone],
|
["git", "diff", f"{reference_branch}..{target_branch}", "--", zone],
|
||||||
|
@ -190,6 +200,19 @@ def get_changelog(reference_branch, target_branch):
|
||||||
return r.stdout.strip()
|
return r.stdout.strip()
|
||||||
|
|
||||||
|
|
||||||
|
def update_reference_branch(reference_branch, target_branch):
|
||||||
|
"""
|
||||||
|
Update the local git reference branch to track the target branch.
|
||||||
|
"""
|
||||||
|
run(
|
||||||
|
["git", "branch", "-D", reference_branch],
|
||||||
|
check=True,
|
||||||
|
stdout=DEVNULL,
|
||||||
|
stderr=DEVNULL,
|
||||||
|
)
|
||||||
|
run(["git", "branch", reference_branch, target_branch], check=True)
|
||||||
|
|
||||||
|
|
||||||
def main(reference_branch, target_branch, audit_email_address, audit_sender_address):
|
def main(reference_branch, target_branch, audit_email_address, audit_sender_address):
|
||||||
changed_files = git_changed_files(
|
changed_files = git_changed_files(
|
||||||
reference_branch=reference_branch, target_branch=target_branch
|
reference_branch=reference_branch, target_branch=target_branch
|
||||||
|
@ -206,8 +229,13 @@ def main(reference_branch, target_branch, audit_email_address, audit_sender_addr
|
||||||
|
|
||||||
changed_zones = calculate_changed_zones(changed_files, zones_in_pdns)
|
changed_zones = calculate_changed_zones(changed_files, zones_in_pdns)
|
||||||
|
|
||||||
|
changed_zones = remove_secondary_zones(changed_zones)
|
||||||
|
|
||||||
if not changed_zones:
|
if not changed_zones:
|
||||||
print("no zones changed")
|
print("no zones changed")
|
||||||
|
|
||||||
|
update_reference_branch(reference_branch, target_branch)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
diffs = []
|
diffs = []
|
||||||
|
@ -246,13 +274,7 @@ def main(reference_branch, target_branch, audit_email_address, audit_sender_addr
|
||||||
|
|
||||||
changelog = get_changelog(reference_branch, target_branch)
|
changelog = get_changelog(reference_branch, target_branch)
|
||||||
|
|
||||||
run(
|
update_reference_branch(reference_branch, target_branch)
|
||||||
["git", "branch", "-D", reference_branch],
|
|
||||||
check=True,
|
|
||||||
stdout=DEVNULL,
|
|
||||||
stderr=DEVNULL,
|
|
||||||
)
|
|
||||||
run(["git", "branch", reference_branch, target_branch], check=True)
|
|
||||||
|
|
||||||
send_audit_mail(diffs, audit_email_address, audit_sender_address, changelog)
|
send_audit_mail(diffs, audit_email_address, audit_sender_address, changelog)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue