We are going to set up a DNS failover using Master/Slave configuration and configure dynamic updates.
This article is part of the Homelab Project with KVM, Katello and Puppet series.
Homelab
We have two CentOS 7 (minimal) servers installed which we want to configure as follows:
admin1.hl.local (10.11.1.2) – will be configured as a DNS master server
admin2.hl.local (10.11.1.3) – will be configured as a DNS slave server
Both servers have SELinux set to enforcing mode.
See the image below to identify the homelab part this article applies to.
Software
Software used in this article:
- CentOS 7
- Bind 9.9
Configure Master DNS Server
Installation and Firewall
Install packages and ensure that the service is enabled:
[admin1]# yum install bind bind-utils [admin1]# systemctl enable named
Configure firewall to allow inbount DNS traffic (we use iptables):
[admin1]# iptables -A INPUT -s 10.11.1.0/24 -p tcp -m state --state NEW --dport 53 -j ACCEPT [admin1]# iptables -A INPUT -s 10.11.1.0/24 -p udp -m state --state NEW --dport 53 -j ACCEPT
Do the following if you use firewalld:
[admin1]# firewall-cmd --add-service=dns [admin1]# firewall-cmd --add-service=dns --permanent
Logs Directory
Configure a custom logs directory:
[admin1]# mkdir -m0700 /var/log/named [admin1]# chown named:named /var/log/named
RNDC Key Configuration
Do automatic rndc configuration, and use an authentication key of 512 bits. Note that the default key name is rndc-key.
[admin1]# rndc-confgen -a -b 512 -r /dev/urandom wrote key file "/etc/rndc.key"
Harden file ownership and permissions:
[admin1]# chown root:named /etc/rndc.key [admin1]# chmod 0640 /etc/rndc.key
Master named.conf Configuration and Internal Zones
The content of the master configuration file /etc/named.conf
can be seen below.
Note how the internal zone updates are only allowed for the servers that know the key.
include "/etc/named.rfc1912.zones"; include "/etc/named.root.key"; include "/etc/rndc.key"; # Allow rndc management controls { inet 127.0.0.1 port 953 allow { 127.0.0.1; } keys { "rndc-key"; }; }; # Limit access to local network and homelab LAN acl "clients" { 127.0.0.0/8; 10.11.1.0/24; }; options { listen-on port 53 { 127.0.0.1; 10.11.1.2; }; ## MASTER listen-on-v6 { none; }; directory "/var/named"; dump-file "/var/named/data/cache_dump.db"; statistics-file "/var/named/data/named_stats.txt"; memstatistics-file "/var/named/data/named_mem_stats.txt"; tcp-clients 50; # Disable built-in server information zones version none; hostname none; server-id none; recursion yes; recursive-clients 50; allow-recursion { clients; }; allow-query { clients; }; allow-transfer { localhost; 10.11.1.3; }; ## SLAVE auth-nxdomain no; notify no; dnssec-enable yes; dnssec-validation auto; dnssec-lookaside auto; bindkeys-file "/etc/named.iscdlv.key"; managed-keys-directory "/var/named/dynamic"; pid-file "/run/named/named.pid"; session-keyfile "/run/named/session.key"; }; # Specifications of what to log, and where the log messages are sent logging { channel "common_log" { file "/var/log/named/named.log" versions 10 size 5m; severity dynamic; print-category yes; print-severity yes; print-time yes; }; category default { "common_log"; }; category general { "common_log"; }; category queries { "common_log"; }; category client { "common_log"; }; category security { "common_log"; }; category query-errors { "common_log"; }; category lame-servers { null; }; }; zone "." IN { type hint; file "named.ca"; }; # Internal zone definitions zone "hl.local" { type master; file "data/db.hl.local"; allow-update { key rndc-key; }; notify yes; }; zone "1.11.10.in-addr.arpa" { type master; file "data/db.1.11.10"; allow-update { key rndc-key; }; notify yes; };
The content of the internal zone file /var/named/data/db.hl.local
:
$TTL 86400 ; 1 day @ IN SOA dns1.hl.local. root.hl.local. ( 2018010700 ; Serial 3600 ; Refresh (1 hour) 3600 ; Retry (1 hour) 604800 ; Expire (1 week) 3600 ; Minimum (1 hour) ) @ NS dns1.hl.local. @ NS dns2.hl.local. @ A 10.11.1.2 @ A 10.11.1.3 dns1 A 10.11.1.2 dns2 A 10.11.1.3 admin1 A 10.11.1.2 admin2 A 10.11.1.3 katello A 10.11.1.4 mikrotik A 10.11.1.1 pve A 10.11.1.5
The content of the internal reverse zone file /var/named/data/db.1.11.10
:
$TTL 86400 ; 1 day @ IN SOA dns1.hl.local. root.hl.local. ( 2018010700 ; Serial 3600 ; Refresh (1 hour) 3600 ; Retry (1 hour) 604800 ; Expire (1 week) 3600 ; Minimum (1 hour) ) @ NS dns1.hl.local. @ NS dns2.hl.local. @ PTR hl.local. dns1 A 10.11.1.2 dns2 A 10.11.1.3 2 PTR dns1.hl.local. 3 PTR dns2.hl.local. 1 PTR mikrotik.hl.local. 2 PTR admin1.hl.local. 3 PTR admin2.hl.local. 4 PTR katello.hl.local. 5 PTR pve.hl.local.
Ensure that file ownership is sane and SELinux file context applied.
[admin1]# chown named:named /var/named/data/db.hl.local /var/named/data/db.1.11.10 [admin1]# semanage fcontext -a -t named_zone_t /var/named/data/db.hl.local [admin1]# semanage fcontext -a -t named_zone_t /var/named/data/db.1.11.10 [admin1]# restorecon -Rv /var/named/
Allow named to write master zones:
[admin1]# setsebool -P named_write_master_zones=1
Checks the syntax of the master configuration file:
[admin1]# named-checkconf /etc/named.conf
Check zone files:
[admin1]# named-checkzone hl.local /var/named/data/db.hl.local zone hl.local/IN: loaded serial 2018010700 OK
[admin1]# named-checkzone hl.local /var/named/data/db.1.11.10 zone hl.local/IN: loaded serial 2018010700 OK
The content of /etc/resolv.conf
can be seen below:
nameserver 10.11.1.2
Restart the service:
[admin1]# systemctl restart named
Display status of the server:
[admin1]# rndc status version: 9.9.4-RedHat-9.9.4-51.el7 (version.bind/txt/ch disabled) CPUs found: 1 worker threads: 1 UDP listeners per interface: 1 number of zones: 103 debug level: 0 xfers running: 0 xfers deferred: 0 soa queries in progress: 0 query logging is ON recursive clients: 0/0/50 tcp clients: 0/50 server is up and runnin
Dig the zone:
[admin1]# dig @10.11.1.2 ns hl.local ; <<>> DiG 9.9.4-RedHat-9.9.4-51.el7 <<>> @10.11.1.2 ns hl.local ; (1 server found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 22854 ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 3 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 4096 ;; QUESTION SECTION: ;hl.local. IN NS ;; ANSWER SECTION: hl.local. 86400 IN NS dns2.hl.local. hl.local. 86400 IN NS dns1.hl.local. ;; ADDITIONAL SECTION: dns1.hl.local. 86400 IN A 10.11.1.2 dns2.hl.local. 86400 IN A 10.11.1.3 ;; Query time: 0 msec ;; SERVER: 10.11.1.2#53(10.11.1.2) ;; WHEN: Sun Jan 07 16:20:28 GMT 2018 ;; MSG SIZE rcvd: 107
Configure Slave DNS Server
Installation and Firewall
This part is the same as for the master server. Install packages:
[admin2]# yum install bind bind-utils [admin2]# systemctl enable named
Configure firewall to allow inbount DNS traffic (we use iptables):
[admin2]# iptables -A INPUT -s 10.11.1.0/24 -p tcp -m state --state NEW --dport 53 -j ACCEPT [admin2]# iptables -A INPUT -s 10.11.1.0/24 -p udp -m state --state NEW --dport 53 -j ACCEPT
Logs Directory
Configure a custom logs directory:
[admin2]# mkdir -m0700 /var/log/named [admin2]# chown named:named /var/log/named
Slave named.conf Configuration
The content of the slave configuration file /etc/named.conf
can be seen below.
include "/etc/named.rfc1912.zones"; include "/etc/named.root.key"; acl "clients" { 127.0.0.0/8; 10.11.1.0/24; }; options { listen-on port 53 { 127.0.0.1; 10.11.1.3; }; ## SLAVE listen-on-v6 { none; }; directory "/var/named"; dump-file "/var/named/data/cache_dump.db"; statistics-file "/var/named/data/named_stats.txt"; memstatistics-file "/var/named/data/named_mem_stats.txt"; tcp-clients 50; # Disable built-in server information zones version none; hostname none; server-id none; recursion yes; recursive-clients 50; allow-recursion { clients; }; allow-query { clients; }; allow-transfer { none; }; auth-nxdomain no; notify no; dnssec-enable yes; dnssec-validation auto; dnssec-lookaside auto; bindkeys-file "/etc/named.iscdlv.key"; managed-keys-directory "/var/named/dynamic"; pid-file "/run/named/named.pid"; session-keyfile "/run/named/session.key"; }; # Specifications of what to log, and where the log messages are sent logging { channel "common_log" { file "/var/log/named/named.log" versions 10 size 5m; severity dynamic; print-category yes; print-severity yes; print-time yes; }; category default { "common_log"; }; category general { "common_log"; }; category queries { "common_log"; }; category client { "common_log"; }; category security { "common_log"; }; category query-errors { "common_log"; }; category lame-servers { null; }; }; zone "." IN { type hint; file "named.ca"; }; # Internal zone definitions zone "hl.local" { type slave; file "data/db.hl.local"; masters { 10.11.1.2; }; allow-notify { 10.11.1.2; }; }; zone "1.11.10.in-addr.arpa" { type slave; file "data/db.1.11.10"; masters { 10.11.1.2; }; allow-notify { 10.11.1.2; }; };
Checks the syntax of the slave configuration file:
[admin2]# named-checkconf /etc/named.conf
The content of /etc/resolv.conf
can be seen below:
nameserver 10.11.1.3 nameserver 10.11.1.2
Allow named to write master zones:
[admin2]# setsebool -P named_write_master_zones=1
Restart the service:
[admin2]# systemctl restart named
Dig the zone:
[admin2]# dig @10.11.1.3 ns hl.local ; <<>> DiG 9.9.4-RedHat-9.9.4-51.el7 <<>> @10.11.1.3 ns hl.local ; (1 server found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 37134 ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 3 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 4096 ;; QUESTION SECTION: ;hl.local. IN NS ;; ANSWER SECTION: hl.local. 86400 IN NS dns2.hl.local. hl.local. 86400 IN NS dns1.hl.local. ;; ADDITIONAL SECTION: dns1.hl.local. 86400 IN A 10.11.1.2 dns2.hl.local. 86400 IN A 10.11.1.3 ;; Query time: 0 msec ;; SERVER: 10.11.1.3#53(10.11.1.3) ;; WHEN: Sun Jan 07 16:20:07 GMT 2018 ;; MSG SIZE rcvd: 107
How to Edit Dynamic DNS
Dynamic DNS editor, nsupdate, is used to make edits on a dynamic DNS without the need to edit zone files and restart the DNS server. Because we have declared a zone dynamic, this is the way that we should be making edits.
For example, to delete all records of any type attached to a domain name, we can do:
# nsupdate -k /etc/rndc.key > update delete example.hl.local > send > quit
Note that rndc won’t allow us to reload a dynamic zone:
# rndc reload hl.local rndc: 'reload' failed: dynamic zone
To do that, we need to temporarily stop allowing dynamic updates:
# rndc freeze hl.local
Now we can edit the zone file if required. When done, we can allow dynamic updates again:
# rndc reload hl.local # rndc thaw hl.local
Hello,
Thanks for the great guide! I have a question though.
Is the assumption here that the servers have two nics? (One NAT and the other one in the 10.11.1.0 range?)
If so, is there any configuring involved to only let the service be active for a particular interface?
Thanks!
All servers have one NIC and are one the same LAN 10.11.1.0/24.
If you have multiple NICs and multiple IPs, then you can bind services on specific IPs that you need them listening on.
Thanks for the quick answer.
I’m asking because I’m using my own computer with virt-manager and thus using a virtual network. Should I just create a virtual (isolated) network and put all the servers in there? Or, coming back to the first question, give them each 2 nics, one NAT for internet access and one for the 10.11.1.0 LAN?
I have some KVM hosts that I manage with virt-manager/virsh, but they all are on a bridged network (standard libvirt installation provides NAT based connectivity – I don’t use that).
I’m not sure I understand what you want to achieve here. You can use 2 NICs if you want to, and then you can bind services to specific IPs if you want them isolated.
If I just bridge those to my home network, wouldn’t I get issues with the DHCP service colliding on my home router and the one I’m configuring here?
You can have more than one DHCP server issuing the same range of network addresses out to your clients. When a client broadcasts a discovery request, the first DHCP server to respond with an IP offer is used.
Your home router will have a pool of addresses that it can issue to clients. If you have more than one DHCP server offering addresses to the same subnet, then they should have different IP pools (or ranges) that don’t overlap, e.g. 10.11.1.40-10.11.1.59 and 10.11.1.60-10.11.1.90.
Sorry for the late response. Only now found the time to continue this project. I understand now and will go ahead to try this. Thank you for the help!
the use of bind-chroot would be more secure…
No worries, go for it!
Bonjour,
Merci pour votre article.
Je me trompe peut-être, mais l’idée d’une IP Failover n’est pas qu’un slave bascule en master en cas de panne de ce dernier ? En quoi la configuration présentée ici permet l’IP Failover ? C’est uniquement la configuration d’un DNS secondaire.
Merci pour vos éclaircissements
Hi Tarwan, perhaps failover isn’t the best word to describe it. Master-slave replication would be more appropriate. You still benefit from higher availability because if your master is down, the slave has all the records and can provide the service. I hope this clarifies things.
Hello and tks. for a great resource!
For starters, please take my question with a grain of salt, I’m at the beginning with iptables…
Can you, please, explain, why you only mention the NEW ip_tables ACCEPT INPUT chain entries for port 53?
What about the continuation of the session? Am I missing something here?
Hi, thanks. That’s a good question. In most cases you almost always have a rule at the end of your iptables ruleset to allow all related and established traffic, before you reject or drop everyhing else.
For example, you will normally see the following entries:
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-port-unreachable
With this in mind, creating rules that allow NEW sessions is sufficient.
Hello,
Thank you for this write up and it has been very helpful. I am trying to set up DHCP server with Dynamic DNS with the config above and cannot get the db.h1.local file to dynamically update when DHCP gives out an IP lease.
Hi Michael, thanks. Do you get any errors at all?