As mentioned before, you can use the DNS services offered by your registrar or by your hosting provider, because this will allow you to avoid installing and maintaining your own BIND servers.
However, if neither your registrar or your hosting provider offer free DNS services and you don’t want to use Hurricane Electric’s free DNS services, or if you insist on having full control over your DNS servers, then you can install and maintain BIND on two (or more) of your servers, as we’ll describe below.
In order to install BIND, you must have at least two servers, each with its own IP and preferably in different geographic locations: one will host the master DNS server and the other will host the slave DNS server. Of course, you can have two, three and even more slave DNS servers, if you want, for redundancy purposes, but one master and one slave server is the minimum. All the slave DNS servers will be configured like the one we’ll present below, so if you know how to install a master and a slave BIND server, you will know how to configure a master and two slaves, three slaves, etc.
The following operations have to be performed both on the master and the slave server:
apt-get update
apt-get dist-upgrade
apt-get install bind9 bind9utils bind9-doc dnsutils
Check version number:
named -v
BIND 9.16.22-Debian (Extended Support Version) <id:59bfaba>
Check if it’s running:
systemctl status named
● bind9.service - BIND Domain Name Server
Loaded: loaded (/lib/systemd/system/bind9.service; enabled; vendor preset: enabled)
Active: active (running) since Wed 2020-09-30 16:18:23 EDT; 4min 9s ago
Docs: man:named(8)
Main PID: 29965 (named)
Tasks: 4 (limit: 3569)
Memory: 14.1M
CGroup: /system.slice/bind9.service
└─29965 /usr/sbin/named -u bind
Enable auto-start at boot time:
systemctl enable named
The BIND server runs as the bind
user, created during installation, and listens on port 53 over TCP and UDP, so, open port 53 with ufw
by running:
ufw allow 53
You can see the port on which BIND listens with:
netstat -lnptu | grep named
The BIND daemon is called named
. There is an important binary called rndc
(remote name daemon controller). The rndc
binary is used to reload, stop and control different aspects of the BIND daemon. Communication is done over TCP port 953 internally, so you don’t have to open port 953 to the public.
You can check the status of the BIND server by running:
rndc status
The result will look similar to this:
version: BIND 9.16.22-Debian (Extended Support Version) <id:59bfaba>
running on mail.example.com: Linux x86_64 5.10.0-10-amd64 #1 SMP Debian 5.10.84-1 (2021-12-08)
boot time: Thu, 23 Dec 2021 20:04:30 GMT
last configured: Thu, 23 Dec 2021 20:04:30 GMT
configuration file: /etc/bind/named.conf
CPUs found: 1
worker threads: 1
UDP listeners per interface: 1
number of zones: 102 (97 automatic)
debug level: 0
xfers running: 0
xfers deferred: 0
soa queries in progress: 0
query logging is OFF
recursive clients: 0/900/1000
tcp clients: 0/150
TCP high-water: 0
server is up and running
When it is installed, BIND provides recursive search for localhost and the local network. Since you are setting up an authoritative DNS server, you have to disable recursion. Make a copy of the original /etc/bind/named.conf.options file:
cp /etc/bind/named.conf.options /etc/bind/named.conf.options_orig
Open the /etc/bind/named.conf.options
file for editing:
nano /etc/bind/named.conf.options
Add the following lines in the options
clause, right before the closing bracket:
// hide version number from clients for security reasons.
version "not available";
// disable recursion on authoritative DNS server.
recursion no;
// enable the query log
querylog yes;
// disallow zone transfer
allow-transfer { none; };
// limit response rate to prevent DDOS attacks
rate-limit {
responses-per-second 10;
};
In the same file, also check if you have the following line, which enables IPv6:
listen-on-v6 { any; };
The rate-limit {}
clause limits the number of queries a server can send to BIND, in order to prevent DDOS attacks.
Restart BIND:
systemctl restart named
By default BIND logs data to /var/log/syslog
. This is done in the absence of the logging {}
clause in /etc/bind/named.conf
. The logging {}
clause can be used to configure BIND to write log data to a specific file, as explained further down below, in order to be able to use Fail2ban to block offending IPs.
31.1. Configure automatic BIND restart
When encountering an inconsistent state, BIND stops. This is an intentional process termination implemented for security reasons. Since BIND provides a service that is so important, it’s recommended to implement a method to restart it automatically once it exits for any reason. To do this, you need to edit the service file /lib/systemd/system/named.service
in a way that will preserve the modifications during future updates. Thus run the command:
systemctl edit named.service
In the new open file, right below these two lines:
### Editing /etc/systemd/system/named.service.d/override.conf
### Anything between here and the comment below will become the new contents of the file
add the following lines:
[Service]
Restart=always
The systemctl edit named.service
command will create the /etc/systemd/system/named.service.d
directory and will place the override.conf
file inside it. In this way, the directives contained in the override.conf
file will override those in the /lib/systemd/system/named.service
file.
Next run:
systemctl daemon-reload
systemctl restart named
From now on, if you run systemctl status named
, you will see something like this:
● named.service - BIND Domain Name Server
Loaded: loaded (/lib/systemd/system/named.service; enabled; vendor preset: enabled)
Drop-In: /etc/systemd/system/named.service.d
└─override.conf
All the configurations presented above have to be applied both on the master and the slave server. The configurations that follow have to be applied only on the specified server: master or slave.
31.2. Configure the master DNS server
The master DNS server is the server where the master copy of the zone file is stored. Changes of the DNS records are made on this server. A domain can have one or multiple DNS zones. Each DNS zone has a zone file which contains all the DNS records for that zone. In this case we’ll use a single DNS zone to manage all the DNS records for a domain name.
The /etc/bind/named.conf.default-zones
file defines the root zone and localhost zone.
To add a zone for a domain name, let’s say example.com
, edit the /etc/bind/named.conf.local
file:
nano /etc/bind/named.conf.local
Add the following lines to the bottom of this file:
zone "example.com" {
type master;
file "/etc/bind/db.example.com";
notify yes;
allow-transfer { 1.2.3.4; };
};
Replace example.com
with the domain for which you create the DNS records and 1.2.3.4
with the IP address of the slave DNS server. If you have multiple slave DNS servers, write their IPs folowed by a semicolon and space, one after the other, like this:
allow-transfer { 1.2.3.4; 12.12.12.12; 23.23.23.23; };
In the configuration from above, you created a new zone with the zone
clause and you specified that this is the master zone. The zone file is /etc/bind/db.example.com
, where you will add the DNS records. Zone transfer will only be allowed to the slave DNS server.
Please note that you’ll have to add a configuration block similar to the one presented above, for every domain that you want to add to BIND. The zone blocks should be added one below the other, like this:
zone "example.com" {
type master;
file "/etc/bind/db.example.com";
notify yes;
allow-transfer { 1.2.3.4; };
};
zone "secondsite.net" {
type master;
file "/etc/bind/db.secondsite.net";
notify yes;
allow-transfer { 1.2.3.4; };
};
Instead of creating a zone file from scratch, you can use a zone template file. Copy the content of db.empty
to a new file:
cp /etc/bind/db.empty /etc/bind/db.example.com
There are 3 types of entries that a zone file can contain:
- Comments: they start with a semicolon (;).
- Directives: they start with a dollar sign ($).
- Resource Records: DNS records. In general, a zone file consists of the following types of DNS records:
- The SOA (Start of Authority) record: defines the key characteristics of a zone. It’s the first DNS record in the zone file and is mandatory.
- NS (Name Server) record: specifies which servers are used to store DNS records and answer DNS queries for a domain name. There must be at least two NS records in a zone file.
- MX (Mail Exchanger) record: specifies which hosts are responsible for email delivery for a domain name.
- A (Address) record: Converts DNS names into IPv4 addresses.
- AAAA (Quad A) record: Converts DNS names into IPv6 addresses.
- CNAME record (Canonical Name): It’s used to create aliases for DNS names.
- TXT record: SPF, DKIM, DMARC, etc.
Next, open the new zone file:
nano /etc/bind/db.example.com
Edit this file to make it look like this:
; Zone file for example.com
$TTL 86400 ; default TTL for this zone (1 day)
$ORIGIN example.com. ; base domain name
; Start of Authority record
@ IN SOA ns1.example.com. hostmaster.example.com. (
2020100282 ; Serial. You must update it when this file is changed.The format is: yyyymmddxx, where xx is 01 for the first change on that day, 02 for the second >
21600 ; Refresh
7200 ; Retry
2419200 ; Expire
86400 ) ; Negative Cache TTL
; Name servers for this domain
@ IN NS ns1.example.com.
@ IN NS ns2.example.com.
; A records
ns1 IN A 123.123.123.123
ns2 IN A 1.2.3.4
@ IN A 123.123.123.123
www IN A 123.123.123.123
; AAAA records
ns1 IN AAAA 2000:2000:2000:2000::ec12
ns2 IN AAAA 1000:1000:1000:1000::da43
@ IN AAAA 2000:2000:2000:2000::ec12
www IN AAAA 2000:2000:2000:2000::ec12
; Mail servers for this domain
@ IN MX mail.example.com.
; CNAME records
; TXT records (SPF, DKIM, DMARC, etc.)
where 123.123.123.123
is the public IPv4 address of the master server and 1.2.3.4
is the public IPv4 address of the slave server. Similary, 2000:2000:2000:2000::ec12
is the public IPv6 address of the master server and 1000:1000:1000:1000::da43
is the public IPv6 address of the slave server.
Below is a description of the parameters used:
- The
$TTL
parameter defines the default Time to Live value for the zone, which is the time a DNS record can be cached on a DNS resolver. Time is specified in seconds. This directive is obligatory.
- The
$ORIGIN
parameter defines the base domain.
- Domain names must end with a dot (.), which is the root domain. The typical format of a fully qualified domain name (FQDN) is with a dot at the end.
- The
@
symbol references the base domain; it functions like a placeholder for the base domain.
IN
is the DNS class. It stands for Internet. There are other DNS classes, but they are rarely used.
The first record of a zone file should be the SOA (Start of Authority) record. This record contains the following data:
- The primary DNS server (
ns1.example.com
). - Email address of the zone administrator. The RFC 2142 standard recommends that the email address should be hostmaster@example.com. In the zone file, this email address takes the form: hostmaster.example.com. because the @ sign has special meaning in a zone file.
- Zone serial number. The serial number is a way in which the slave DNS server can track changes to the zone. The serial number has the format: yyyymmddxx, where yyyy is the four-digit year number, mm is the month, dd is the day, and xx records the number of changes on that day (xx is 01 for the first change on that day, 02 for the second change, 03 for the third change, etc.) You have to update the serial number each time you make changes to the zone file (if this is not done automatically, as we’ll explain later).
- Refresh value. When the refresh time is reached, the slave DNS server tries to read the SOA record from the master DNS server. If it notices that the serial number is higher, it initiates a zone transfer.
- Retry value. Defines the retry interval (in seconds) if the slave DNS server fails to connect to the master DNS server.
- Expiry. If the slave DNS server has been failing to connect to the master DNS server for this interval of time, the slave will stop responding to DNS queries for this zone.
- Negative cache TTL. Defines the “time to leave” value of DNS responses for non-existent DNS names.
TXT records can be enclosed in double quotes. DKIM records have to be enclosed with round brackets.
You can check if there are syntax errors in the main configuration file by running:
named-checkconf
If you have more than one slave server, you will need to add records similar to the ones for ns2
, for each additional slave server (ns3
, ns4
, etc.)
You can check the syntax of a zone file by running:
named-checkzone example.com /etc/bind/db.example.com
If there are no errors, restart BIND:
systemctl restart named
I
f you host the following domains: example.com
, secondsite.net
, thirdsite.info
, fourthsite.org
, fifthsite.us
, each domain’s zone file will mention the following name servers, respectively:
ns1.example.com
ns2.example.com
ns1.secondsite.net
ns2.secondsite.net
ns1.thirdsite.info
ns2.thirdsite.info
ns1.fourthsite.org
ns2.fourthsite.org
ns1.fifthsite.us
ns2.fifthsite.us
31.3. Configure the slave DNS server
Next, you’ll have to configure the slave DNS server.
Edit the /etc/bind/named.conf.local
file:
nano /etc/bind/named.conf.local
Add the following lines inside this file:
zone "example.com" {
type slave;
file "db.example.com";
allow-notify { 123.123.123.123; };
masters { 123.123.123.123; };
};
Replace 123.123.123.123
with the IP address of the master DNS server, and example.com
with the domain name you are configuring. Add a block similar to the one from above for every domain configured on the master server.
ou can check if there are syntax errors with:
Y
named-checkconf
If there are no errors restart BIND:
systemctl restart named
After BIND is restarted, a zone tranfer will start immediately. During a zone transfer, the slave DNS server will synchronize its DNS records with those on the master server.
31.4. Reverse Zone
A reverse zone contains a PTR record that maps an IP address to a domain name. In general, you will have to add a reverse DNS record, in order to make spam filters accept the emails coming from your mail server. This type of record cannot be added to a domain, in your BIND server’s configuration. This record has to be added on the administration panel/dashboard of your hosting account, or, if the administration panel/dashboard doesn’t offer this option, you should ask your hosting company to add the reverse DNS record for you, in a support ticket.
31.5. Create glue records and change Name Servers records with the registrar of your domains
Next, log in to your domain registrar’s website and create glue records, so that the IP addresses of your name servers become known on the Internet. The glue records are A and AAAA records for ns1.somedomain.com
and ns2.somedomain.com
, like the following:
A Record ns1.somedomain.com 123.123.123.123
A Record ns2.somedomain.com 1.2.3.4
AAAA Record ns1.somedomain.com 2000:2000:2000:2000::ec12
AAAA Record ns2.somedomain.com 1000:1000:1000:1000::da43
where somedomain.com
is the domain you are configuring, 123.123.123.123
is the IPv4 of the master server, 1.2.3.4
is the IPv4 of the slave server, 2000:2000:2000:2000::ec12
is the IPv6 of the master server and 1000:1000:1000:1000::da43
is the IPv6 of the slave server.
Please note that somedomain.com
stands for any domain on your server, including the main domain, which we have called example.com
in the previous chapters.
Then, change the Name Servers records for your domain, in the appropriate section of your domain registrar’s website. Thus, the Name Servers for the somedomain.com
domain, should be set to:
ns1.somedomain.com
ns2.somedomain.com
Repeat the steps from above for every domain configured in BIND, so that each domain has the proper glue records and Name Servers set up with the registrar of that domain.
After the Name Servers records and glue records have propagated, your DNS servers will respond to the DNS queries for the configured domain.
31.5.1. Setting up glue records in a namecheap.com account
Each registrar offers a different web interface. For namecheap.com, the steps that you have to follow in order to set up your own glue records for the somedomain.com
domain are the following:
– log in to your namecheap.com account.
– click on the ‘MANAGE’ button next to the domain that you want to configure.
– on the ‘Domain’ tab, in the ‘NAMESERVERS’ section, click on the dropdown list and choose ‘Namecheap BasicDNS’, then click on the tick sign (on the right, before the cancel sign) to save this setting.
– click on the ‘Advanced DNS’ tab on the upper bar.
– you can delete the following two records (by clicking on the delete sign), because you won’t need them:
'CNAME Record www parkingpage.namecheap.com 30 min'
'URL Redirect Record @ http://www.somedomain.com/ Unmasked'
– click on the ‘ADD NEW RECORD’ button and add two A records and two AAAA records for the name servers, like the following:
A Record ns1.somedomain.com 123.123.123.123 Automatic
A Record ns2.somedomain.com 1.2.3.4 Automatic
AAAA Record ns1.somedomain.com 2000:2000:2000:2000::ec12 Automatic
AAAA Record ns2.somedomain.com 1000:1000:1000:1000::da43 Automatic
where somedomain.com
is the domain you are configuring, 123.123.123.123
is the IPv4 of the master server, 1.2.3.4
is the IPv4 of the slave server, 2000:2000:2000:2000::ec12
is the IPv6 of the master server and 1000:1000:1000:1000::da43
is the IPv6 of the slave server.
Obviously, if you have more than one slave server, you’ll have to add more similar A and AAAA records.
– scroll down to the ‘PERSONAL DNS SERVER’ section. In the ‘Find Nameservers’ dropdown list make sure it’s ‘Standard Nameservers’ selected, then click on the ‘ADD NAMESERVER’ link; in the new window, click on ‘Nameserver’, enter manually the subdomain that the name server will have, in our example this will be ns1
, so enter manually ns1
, press Enter, then in the ‘IP Address’ field enter the IPv4 address of ns1.somedomain.com
, then click on ‘DONE’. Next, click again on the ‘ADD NAMESERVER’ button and do the same for ns2.somedomain.com
. Don’t forget that ns2
has a different IPv4 address than ns1
. Don’t repeat the process for the IPv6 addresses.
– next, click on the ‘Domain’ tab again, in the ‘NAMESERVERS’ section select ‘Custom DNS’ from the drop-down list, then in the text fields from below enter:
ns1.somedomain.com
ns2.somedomain.com
then click on the tick sign to save the records.
– the records will propagate and become functional in a few minutes or in a few hours.
If you want to check if the data is synchronized between the master and the slave server, run the following command on each server:
dig @123.123.123.123 somedomain.com. soa +norec
where 123.123.123.123
is the IPv4 address of the other server.
You can find the BIND9 referece manual here: https://bind9.readthedocs.io/en/latest/ .
31.6. Configure DNSSEC
An attacker can tamper with the DNS responses and send the clients to a malicious website having the legitimate domain name in the address bar. To prevent this, the DNSSEC (Domain Name System Security Extensions) was designed. DNSSEC is a set of extensions to DNS, which offers cryptographic authentication of DNS responses. It signs all the DNS resource records (A, AAAA, MX, etc.) of a zone using the Resource Public Key Infrastructure (RPKI), so that DNSSEC enabled DNS resolvers can verify the authenticity of a DNS reply using the public DNSKEY record.
DNSSEC requires the following resource records (RRs) in the zone file, to function:
- DNSKEY – it specifies the public key which resolvers use to decrypt the encrypted DNS response and verify its authenticity.
- RRSIG – it contains the signature for a DNSSEC-secured record set.
- DS – Delegation signer – the record used to identify the DNSSEC signing key of a delegated zone.
31.6.1. Master server configuration for DNSSEC
To configure the master server, first open the /etc/bind/named.conf.options
file:
nano /etc/bind/named.conf.options
Right above listen-on-v6 {any; };
add the following lines in the options configuration block:
dnssec-enable yes;
dnssec-validation yes;
dnssec-lookaside auto;
// conform to RFC1035
auth-nxdomain no;
Please note that the dnssec-validation
has to be changed from auto
to yes
.
Next, navigate to /etc/bind
:
cd /etc/bind
Create a Zone Signing Key (ZSK) for each domain, using the following command:
dnssec-keygen -a NSEC3RSASHA1 -b 2048 -n ZONE somedomain.com
Then create a Key Signing Key (KSK) for each domain by running:
dnssec-keygen -f KSK -a NSEC3RSASHA1 -b 4096 -n ZONE somedomain.com
These commands will create one pair of ZSK keys (private/public) and one pair of KSK keys (private/public) for each domain.
Next, add the following two lines at the bottom of the zone file db.somedomain.com
:
$INCLUDE Ksomedomain.com.+007+23232.key
$INCLUDE Ksomedomain.com.+007+54545.key
Replace the names of the two public key files for somedomain.com
with the actual names of your files.
Repeat the above step for each domain name configured with BIND, by including the two public key files for a domain, at the bottom of that respective domain’s zone file.
Then sign each zone using the following command:
dnssec-signzone -A -3 $(od -vN 8 -An -tx1 /dev/urandom | tr -d " \n" ; echo) -N INCREMENT -o somedomain.com -t db.somedomain.com
The output of the command from above will look similar to this:
Verifying the zone using the following algorithms: NSEC3RSASHA1.
Zone fully signed:
Algorithm: NSEC3RSASHA1: KSKs: 1 active, 0 stand-by, 0 revoked
ZSKs: 1 active, 0 stand-by, 0 revoked
db.example.com.signed
Signatures generated: 17
Signatures retained: 0
Signatures dropped: 0
Signatures successfully verified: 0
Signatures unsuccessfully verified: 0
Signing time in seconds: 0.032
Signatures per second: 519.845
Runtime in seconds: 0.041
This command:
od -vN 8 -An -tx1 /dev/urandom | tr -d " \n" ; echo
generates a string of 16 random hexadecimal characters, that is included as a salt, in the dnssec-signzone
command.
Signing the zone creates a new file called db.somedomain.com.signed
, which contains the RRSIG records for each DNS record.
Use the dnssec-signzone
command from above to sign the zone for each zone configured with BIND.
Next, you have to instruct BIND to load this “signed” zones:
nano /etc/bind/named.conf.local
Change the file
option inside the zone
section for somedomain.com
, by replacing db.somedomain.com
with db.somedomain.com.signed
. The zone section for somedomain.com
should look like this:
zone "somedomain.com" {
type master;
file "/etc/bind/db.somedomain.com.signed";
notify yes;
allow-transfer { 1.2.3.4; };
};
where 1.2.3.4
is the IPv4 of the slave DNS server. Do similar changes for all the other zones.
Next restart BIND:
systemctl restart named
You can check the DNSKEY record using the dig
command:
dig DNSKEY somedomain.com. @localhost +multiline
The output should look similar to this:
;; ANSWER SECTION:
example.com. 86400 IN DNSKEY 256 3 7 (
...
) ; ZSK; alg = NSEC3RSASHA1; key id = 68356
example.com. 86400 IN DNSKEY 257 3 7 (
...
) ; KSK; alg = NSEC3RSASHA1; key id = 29461
You can also check the RRSIG records by running:
dig A somedomain.com. @localhost +noadditional +dnssec +multiline
31.6.2. Slave server configuration for DNSSEC
On the slave server edit the /etc/bind/named.conf.options
file:
nano /etc/bind/named.conf.options
In the options
configuration block, right above listen-on-v6 { any; };
add the following lines:
dnssec-enable yes;
dnssec-validation yes;
dnssec-lookaside auto;
// conform to RFC1035
auth-nxdomain no;
Also edit the /etc/bind/named.conf.local
file:
nano /etc/bind/named.conf.local
Change the name of the zone file from db.somedomain.com
to db.somedomain.com.signed
. The zone section for somedomain.com
should look like this:
zone "somedomain.com" {
type slave;
file "db.somedomain.com.signed";
allow-notify { 123.123.123.123; };
masters { 123.123.123.123; };
};
where 123.123.123.123
is the IPv4 of the master server. Do the same for every zone.
Restart BIND:
systemctl restart named
31.7. Configure the DS records with your domain name registrar
When running the dnssec-signzone
command, apart from the db.somedomain.com.signed
file, a file named dsset-somedomain.com.
was also created. This file contains the DS record that has to be added in your domain names registrar’s account. Each registrar has a different web interface. We’ll describe how to add the DS record in a namecheap.com account and you should be able to adapt the instructions to other registrars.
31.7.1. Setting up DS records in a namecheap.com account
Log in to your namecheap.com account. Click on ‘Domain List’ on the left panel, click on the ‘MANAGE’ button next to the domain you want to configure, then click on the ‘Advanced DNS’ tab on the upper bar; next, in the ‘DNSSEC’ section toggle the Status switch to On, then add below a DS record, like this:
Key Tag Algorithm Digest Type Digest
58465 7 RSASHA1-NSEC3-SHA1 2 SHA-256 BD3A3BD829934F86BCB434A16E297D6E0E26B84A57EFA284B370ECDA4AF6FC36
where the number in the ‘Key Tag’ column is the first number that appears right after ‘IN DS’, on the first line of the /etc/bind/dsset-somedomain.com.
file. Please note that the digest string, as you copy it from the /etc/bind/dsset-somedomain.com.
file, contains a space. When you enter it in the ‘Digest’ field you have to remove the space, otherwise the record can’t be saved.
After you save the above record, you’ll have to wait about one hour for the settings to take effect. Then, to check your DNSSEC settings, you can use an online service like: http://dnssec-debugger.verisignlabs.com .
You have to add a DS record for each domain configured in BIND.
31.8. Editing zone records
The operations in this chapter will be performed only on the master server.
Each time you modify a zone file, you have to sign it again, for the DNSSEC to work. It’s best to use a script to automatically sign a zone after you modify it. Create a script:
nano /etc/bind/signzone.sh
Enter the following content inside this file:
#!/bin/bash
ZONE=$1
ZONEFILE=$2
cd /etc/bind
SERIAL=`/usr/sbin/named-checkzone $ZONE $ZONEFILE | egrep -ho '[0-9]{10}'`
sed -i 's/'$SERIAL'/'$(($SERIAL+1))'/' $ZONEFILE
/usr/sbin/dnssec-signzone -A -3 $(od -vN 8 -An -tx1 /dev/urandom | tr -d " \n" ; echo) -o $1 -t $2
systemctl reload named
Make the script executable:
chmod 700 /etc/bind/signzone.sh
When you want to change DNS settings for somedomain.com
, you must edit the db.somedomain.com
file and not the db.somedomain.com.signed
file. After editing the file just run the script by passing the domain name and the zone file name as parameters as follows:
/etc/bind/signzone.sh somedomain.com db.somedomain.com
The result of successful signing for the somedomain.com
domain will look similar to this:
Verifying the zone using the following algorithms: NSEC3RSASHA1.
Zone fully signed:
Algorithm: NSEC3RSASHA1: KSKs: 1 active, 0 stand-by, 0 revoked
ZSKs: 1 active, 0 stand-by, 0 revoked
db.example.com.signed
Signatures generated: 22
Signatures retained: 0
Signatures dropped: 0
Signatures successfully verified: 0
Signatures unsuccessfully verified: 0
Signing time in seconds: 0.058
Signatures per second: 378.572
Runtime in seconds: 0.077
If a zone can’t be signed because of wrong configurations, etc., the signing command will produce no output for that respective zone, so, the successful signing result block from above will be absent for zones that cannot be signed.
To prevent potential hackers to find the salt that was used to sign the zones, you have to change the salt regularly by resigning the zones. Each time the zones are resigned with the command presented above, a new salt is generated and used. To automate the periodic signing process you have to write a new script and set up a cron job that will run the script every 3 days. First, create the script:
nano /etc/bind/signallzones.sh
Enter the following content inside this file:
#!/bin/bash
# If you want to add a new domain to the DNSSEC zone signing process, just add the domain at the end of the "domains" array from below.
# If you want the signing process result to be sent to a different email address, just change the email address at the end of this script.
# If you don't want the script to send emails with the result of the signing process, just comment out the line before the final "fi" of the script.
if [[ $(( ($(date +%s)/86400) % 3 )) == 0 ]]
then
declare -a domains=("example.com" "secondsite.net" "thirdsite.info" "fourthsite.org" "fifthsite.us")
declare -a messages=()
declare -a failedzones=()
n=${#domains[@]}
k=0
cd /etc/bind
for i in "${!domains[@]}"
do
serial=`/usr/sbin/named-checkzone "${domains[$i]}" "db.${domains[$i]}" | egrep -ho '[0-9]{10}'`
sed -i 's/'$serial'/'$(($serial+1))'/' "db.${domains[$i]}"
result=`/usr/sbin/dnssec-signzone -A -3 $(od -vN 8 -An -tx1 /dev/urandom | tr -d " \n" ; echo) -o "${domains[$i]}" -t "db.${domains[$i]}"`
if [[ $result = *[!\ ]* ]]
then
messages+=("$result")
((k++))
else
failedzones+=("${domains[$i]}")
fi
done
systemctl reload named
failedlist=`printf "%s\n\n " "${failedzones[@]}"`
host=`hostname`
if (($k < $n))
then
warning=`printf "The 'signallzones.sh' script attempted to sign all the zones configured in BIND on $host but the following zones couldn't be signed: %s\n\n $failedlist Please check the configuration of the failed zones from above ! %s\n\n The zones for which the signing process succeeded are listed below."`
else
warning=`printf "The 'signallzones.sh' script successfully signed all the zones configured in BIND on $host. The result of the signing process is listed below."`
fi
finalmessage=`printf "%s\n\n" "${messages[@]}"`
echo -e "Subject: DNSSEC Zone Signing \n\n Hello, \n\n $warning \n\n $finalmessage \n\n\n Yours, \n 'signallzones.sh' on $host" | /usr/sbin/sendmail admin@example.com
fi
Replace the values in red with your own values. Later, when you want to add a new domain to the DNSSEC signing process, just add it at the end of the ‘domains’ array, between double quotation marks. If you don’t want the script to send an email with the results when signing the zones, just comment out the line before the final fi
.
Make the script executable, with the appropriate permissions:
chmod 700 signallzones.sh
Next, set up the cron job:
crontab -e
At the bottom of the file add the fowllowing lines:
# Run the DNS zones signing script every day at 1:36 AM
36 1 * * * /etc/bind/signallzones.sh > /dev/null 2>&1
The above cron job will run the zones signing script every day, at 1:36 AM. However, the following line located at the beginning of the script:
if [[ $(( ($(date +%s)/86400) % 3 )) == 0 ]]
will ensure that the signing process will take place only once every 3 days, which is in general frequent enough.
If, every 3 days you receive an email mentioning that “All the zones were signed successfully.”, this means everything is working as expected; if the email message tells you that one or more zones couldn’t be signed, it means that the respective zones were misconfigured or something else happened, so you have to investigate what caused the signing process to fail for those zones.
31.9. Configure Fail2ban to protect BIND
The following configurations have to be implemented on both the master server and the slave server.
To use Fail2ban to monitor BIND log and block attackers’ IPs first we have to configure BIND logging by editing the /etc/bind/named.conf
file:
nano /etc/bind/named.conf
Enter the following lines at the bottom of the file:
logging {
channel security_file {
file "/var/log/named/security.log" versions 3 size 30m;
severity dynamic;
print-time yes;
};
category security {
security_file;
};
};
Next, create a directory for BIND logs and set the proper ownership for it:
mkdir /var/log/named
chown bind:bind /var/log/named
Restart BIND to apply the changes:
systemctl restart named
After restart you can check that the new log file /var/log/named/security.log
has been created.
Since you configured BIND to write to a specific log file, you have to remember to also configure logrotate
to rotate the new logs, once they reach a certain dimension. Create the logrotate
configuration file:
nano /etc/logrotate.d/named-security
Enter the following content inside this file:
/var/log/named/security.log {
missingok
rotate 7
compress
delaycompress
notifempty
size 2M
create 640 bind bind
postrotate
/usr/sbin/invoke-rc.d named reload > /dev/null
endscript
}
Then open the local jail configuration file of Fail2ban:
nano /etc/fail2ban/jail.local
Search for the section that begins with [named-refused]
and make it look like this:
[named-refused]
enabled = true
port = domain,53,953
filter = named-refused
logpath = /var/log/named/security.log
findtime = 2100
maxretry = 3
bantime = 604800
You can adjust findtime
, maxretry
and bantime
according to your needs but banning an IP for 7 days (604800 seconds) after making 3 failed queries in 35 minutes (2100 seconds), is a reasonable policy. Please note that Fail2ban will listen on both TCP and UDP traffic, since you didn’t specify protocol = tcp
or protocol = udp
.
Next restart Fail2ban:
systemctl restart fail2ban
Then you can check if the new jail has been activated by running:
fail2ban-client status
Among the active jails listed you should see the new jail: ‘named-refused’.
31.10. Upgrading BIND
Since BIND has been installed from the official Debian repository, to upgrade it, all you need to do is to run apt-get update && apt-get dist-upgrade
with a specific frequency, as described in the Maintenance steps chapter. This command will upgrade BIND if there is a new version available. Also, during these upgrades, the configuration changes implemented as described above, will be preserved.