options { auth-nxdomain no; recursion no; listen-on-v6 port 53 { any; }; listen-on port 53 { any; }; notify explicit; rate-limit { responses-per-second 10; }; };
key schwarz.in.philpep.org. { algorithm hmac-sha512; secret "XXX XXX=="; }; zone "philpep.org" { type master; file "zones/philpep.org.db"; allow-transfer { key schwarz.in.philpep.org.; }; also-notify { 192.168.96.5 key schwarz.in.philpep.org.; }; };
This configure zone “philpep.org” with one secondary dns server on “192.168.96.5”.
Primary and secondary master use a symetric hmac-sha512 keys. Theses keys can be generated with dnssec-keygen -a HMAC-SHA512 -b 512 -n HOST keyname.
DNS zone transfer occur in two times:
Bind can be used for secondary servers as well, but you might consider using NSD instead.
You can dynamically modify a zone using RFC 2136, at time of writting, only bind and knot server implement this. But only Bind implement fine grained update policy.
I use this script running in crontab every minutes on a router behind a dynamic ip address.
#!/bin/sh set -e PATH=/sbin:/bin:/usr/sbin:/usr/bin export PATH IFACE="pppoe-wan" DNS_SERVER="5.39.85.37" DNS_NAME="foo.philpep.org" DNS_TTL="300" # 5 minutes DNS_KEY="/root/K0foo.philpep.org.+157+00000.private" LOGGER="logger -t dyndns" # address on $IFACE # addr=$(ip a show $PPP_IFACE | awk '$1 = "inet" && $3 == "peer" { print $2 }') # use an external service # addr=$(wget -O - https://ifconfig.co/ip) old_addr=$(dig @$DNS_SERVER +short +time=1 +tries=3 $DNS_NAME) # WAIT max 3 seconds if [ "$addr" != "$old_addr" ]; then $LOGGER "update dns from '$old_addr' to '$addr'" cat << EOF | nsupdate -t 5 -k $DNS_KEY server $DNS_SERVER update delete $DNS_NAME A update add $DNS_NAME $DNS_TTL A $addr send EOF $LOGGER "update dns from '$old_addr' to '$addr': done" fi
On server side, only allow the key to update A entry for “foo.example.com”
key foo.philpep.org. { algorithm hmac-sha512; secret "XXX XXX=="; }; zone "philpep.org" { # [...] update-policy { grant foo.philpep.org. name foo.philpep.org. a; }; };
This is useful to issue letsencrypt certificates for internal domain names (belong a public domain), or for wildcard certificates.
On client side, install and configure certbot-dns-rfc2136:
apt-get install certbot python3-certbot-dns-rfc2136
dns_rfc2136_server = 192.168.62.2 dns_rfc2136_port = 53 dns_rfc2136_name = foo.in.philpep.org. dns_rfc2136_secret = XXX XXX== dns_rfc2136_algorithm = HMAC-SHA512
Ensure to chmod 600 /etc/letsencrypt/rfc2136.ini
On server side, configure the secret key and add a grant policy:
key foo.in.philpep.org. { algorithm hmac-sha512; secret "XXX XXX=="; }; zone "philpep.org" { # [...] update-policy { # allow foo.in.philpep.org and/or *.foo.in.philpep.org grant foo.philpep.org. name _acme-challenge.foo.in.philpep.org. txt; # allow all subdomain of in.philpep.org # grant foo.in.philpep.org. zonesub txt; }; };
Then back on client, issue the certificate with:
certbot certonly --dns-rfc2136 --dns-rfc2136-credentials /etc/letsencrypt/rfc2136.ini -d foo.in.philpep.org -d '*.foo.in.philpep.org'