====== Bind dns server ======
* http://www.zytrax.com/books/dns/ very good documentation about dns and bind
===== Configuration =====
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;
};
};
===== Zone configuration =====
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:
- Master notifies all secondary servers about the new zone serial
- Secondary issue a AXFR (full) or IXFR (incremental) zone transfer
Bind can be used for secondary servers as well, but you might consider using [[soft:nsd|NSD]] instead.
===== Dynamic DNS update =====
You can dynamically modify a zone using [[https://tools.ietf.org/html/rfc2136|RFC 2136]], at time of writting, only bind and [[https://www.knot-dns.cz/|knot]] server implement this. But only Bind implement fine grained update policy.
==== DNS update script ====
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;
};
};
==== letsencrypt acme dns challenge ====
This is useful to issue letsencrypt certificates for internal domain names (belong a public domain), or for wildcard certificates.
* https://certbot-dns-rfc2136.readthedocs.io/en/stable/
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'