What IS broken are the number of small networks, or isolated subnets of larger networks that don't have a DNS server. I was recently doing some security consulting for a client, and a recommended that they disable netbios on all the machines (NetBIOS can help to mitigate an attacker's ability to: poison and spoof responses, obtain a user's hashed credentials, inspect web traffic, etc. That is another blog post) and the next day I got a call that they couldn't reach any network resources any more..... huh? No dns, they were relying on netbios to resolve everything. It's madness.
I have seen this all over the place, or worse, I have seen where net-admins don't want to spend the time to put dns on an isolated network or protected DMZ and just put everything in HOST files... MADNESS.
A DNS server, a DNS server, my Kingdom for a DNS server
We are going to walk through a simple, but powerful DNS server option called PowerDNS. It is extensible, capable, flexible, and powerful... see what I did there. We are going to use a SQL backend, because anyone can use a zone file (technically this can to). The advantage of the SQL backend is historical data and the speed of not having to parse an entire text file. We can even talk about front end options. At the very end, we will add in a recursor, for those who need more than an authoritative dns for a closed system (i.e. internet access)
I don't know the state of your server, but lets assume your the type of person who has been relying on NETBIOS and logs into SSH as root.
1. Forget about the Ubuntu server and run CentOS, otherwise lots of this tutorial won't make sense.
2. Create a user that can sudo
adduser username passwd username usermod -aG wheel username
2. Remove root from being able to ssh
sudo vi /etc/ssh/sshd_config PermitRootLogin no sudo service sshd restart
3. Setup the firewall
sudo yum install firewalld sudo systemctl enable firewalld sudo systemctl start firewalld sudo firewall-cmd --list-all sudo firewall-cmd --zone=public --permanent --add-service=dns sudo firewall-cmd --reload
5. Make sure you are fresh and clean .... update.
sudo yum update
Finally to Business
1. Install Pre-Reqs
sudo yum install epel-release yum-plugin-priorities wget bind-utils net-tools
2. Install and configure MariaDB
sudo yum -y install mariadb-server mariadb sudo systemctl enable mariadb.service sudo systemctl start mariadb.service sudo mysql_secure_installation
3. Install PowerDNS
sudo curl -o /etc/yum.repos.d/powerdns-auth-41.repo https://repo.powerdns.com/repo-files/centos-auth-41.repo sudo yum install pdns sudo yum install pdns-backend-mysql
4. Do Scary things with MariaDB
Don't freak out, we will take these one at a time
mysql -u root -p
CREATE DATABASE powerdns; GRANT ALL ON powerdns.* TO 'powerdns'@'localhost' IDENTIFIED BY 'PASSWORD'; FLUSH PRIVILEGES; USE powerdns;
SCHEME CREATE TABLE domains ( id INT AUTO_INCREMENT, name VARCHAR(255) NOT NULL, master VARCHAR(128) DEFAULT NULL, last_check INT DEFAULT NULL, type VARCHAR(6) NOT NULL, notified_serial INT UNSIGNED DEFAULT NULL, account VARCHAR(40) CHARACTER SET 'utf8' DEFAULT NULL, PRIMARY KEY (id) ) Engine=InnoDB CHARACTER SET 'latin1'; CREATE UNIQUE INDEX name_index ON domains(name);
CREATE TABLE records ( id BIGINT AUTO_INCREMENT, domain_id INT DEFAULT NULL, name VARCHAR(255) DEFAULT NULL, type VARCHAR(10) DEFAULT NULL, content VARCHAR(64000) DEFAULT NULL, ttl INT DEFAULT NULL, prio INT DEFAULT NULL, change_date INT DEFAULT NULL, disabled TINYINT(1) DEFAULT 0, ordername VARCHAR(255) BINARY DEFAULT NULL, auth TINYINT(1) DEFAULT 1, PRIMARY KEY (id) ) Engine=InnoDB CHARACTER SET 'latin1';
CREATE INDEX nametype_index ON records(name,type); CREATE INDEX domain_id ON records(domain_id); CREATE INDEX ordername ON records (ordername);
CREATE TABLE supermasters ( ip VARCHAR(64) NOT NULL, nameserver VARCHAR(255) NOT NULL, account VARCHAR(40) CHARACTER SET 'utf8' NOT NULL, PRIMARY KEY (ip, nameserver) ) Engine=InnoDB CHARACTER SET 'latin1';
CREATE TABLE comments ( id INT AUTO_INCREMENT, domain_id INT NOT NULL, name VARCHAR(255) NOT NULL, type VARCHAR(10) NOT NULL, modified_at INT NOT NULL, account VARCHAR(40) CHARACTER SET 'utf8' DEFAULT NULL, comment TEXT CHARACTER SET 'utf8' NOT NULL, PRIMARY KEY (id) ) Engine=InnoDB CHARACTER SET 'latin1';
CREATE INDEX comments_name_type_idx ON comments (name, type); CREATE INDEX comments_order_idx ON comments (domain_id, modified_at);
CREATE TABLE domainmetadata ( id INT AUTO_INCREMENT, domain_id INT NOT NULL, kind VARCHAR(32), content TEXT, PRIMARY KEY (id) ) Engine=InnoDB CHARACTER SET 'latin1'; CREATE INDEX domainmetadata_idx ON domainmetadata (domain_id, kind);
CREATE TABLE cryptokeys ( id INT AUTO_INCREMENT, domain_id INT NOT NULL, flags INT NOT NULL, active BOOL, content TEXT, PRIMARY KEY(id) ) Engine=InnoDB CHARACTER SET 'latin1'; CREATE INDEX domainidindex ON cryptokeys(domain_id);
CREATE TABLE tsigkeys ( id INT AUTO_INCREMENT, name VARCHAR(255), algorithm VARCHAR(50), secret VARCHAR(255), PRIMARY KEY (id) ) Engine=InnoDB CHARACTER SET 'latin1'; CREATE UNIQUE INDEX namealgoindex ON tsigkeys(name, algorithm); quit;
That was a bit..... now go get a coffee and some chocolate, maybe a nice glass of scotch. In this example we are installing PDNS 4.1 because I like it and I think it is very stable. If you install a different version, there is a different scheme... always reference this: https://doc.powerdns.com/authoritative/guides/basic-database.html
5. Configure PDNS
sudo mv /etc/pdns/pdns.conf /etc/pdns/pdns.conf.bu sudo vi /etc/pdns/pdns.conf
# pdns.conf launch=gmysql gmysql-host=localhost gmysql-dbname=powerdns gmysql-user=powerdns gmysql-password=PASSWORD gmysql-dnssec=yes loglevel=10 log-dns-queries=1
6. Start her up
sudo systemctl enable pdns.service sudo systemctl start pdns.service
7. Add Zones and Records
Start Simple. Use the pdnsutil command to create zones and records (https://doc.powerdns.com/authoritative/manpages/pdnsutil.1.html)
create-zone ZONECreate an empty zone named ZONE.
add-record ZONE NAME TYPE [TTL] CONTENT
Add one or more records of NAME and TYPE to ZONE with CONTENT and optional TTL. If TTL
is not set, the default will be used.
# pdnsutil create-zone example.com ns1.example.com Creating empty zone 'example.com.' Also adding one NS record # pdnsutil add-record example.com ns1 A 192.168.1.2 New rrset: ns1.example.com. IN A 3600 192.168.1.2 # pdnsutil list-zone example.com example.com. 3600 IN NS ns1.example.com. example.com. 3600 IN SOA ns1.example.com hostmaster.example.com 1 10800 3600 604800 3600 ns1.example.com. 3600 IN A 192.168.1.2 $ dig +noall +answer ns1.example.com @127.0.0.1 ns1.example.com. 3600 IN A 192.168.1.2
Done .... ishThere are 3 other, possible simpler, methods for managing PDNS.
1. Webmin - Follow the instructions, use the MySQL plugin to manage your data.
2. phpMyAdmin - Same as above. Follow the instructions, manage everything in the tables you just created.
3. PowerAdmin - PowerAdmin is purpose built for PDNS. I recommend it on at least one machine. I don't use it on all of them, because I have replication enabled, but it is a simple powerful interface with minimal weight.
To install PowerAdmin
Follow these Directions: https://www.howtoforge.com/how-to-install-powerdns-and-poweradmin-on-centos-7/
So, everything is installed, and running, if you have worked through some bugs, but now have a major hangup.... it resolves all of your internal networks, but it won't resolve the google.com ... or *gasp* it won't resolve tomvoboril.com.
Recursion.In a network, it is really a better practice to separate out your authoritative DNS servers, which we just built, and your internal recursive DNS servers. Simple said. If you did not need anything to resolve internally, you would just point to your ISPs DNS, or google's DNS, or OpenDNS, etc. It is very simple to install a small recursor to break out traffic between internal and external. We will run it on the same server as the authoritative, and do some fancy binding.
1. Install PowerDNS Recursor
sudo yum install pdns-recursor
2. Configure pdns-recursor
sudo mv /etc/pdns-recursor/pdns-recursor.conf /etc/pdns/pdns-recursor.conf.bu sudo vi /etc/pdns-recursor/pdns-recursor.conf
2 lines of config. make sure you bind it to the boxes IP, and the network.local is whatever you want the authoritative to run.
3. Configure PDNS to bind to local.
sudo mv /etc/pdns/pdns.conf /etc/pdns/pdns.conf.bu2 sudo vi /etc/pdns/pdns.conf
local-address=127.0.0.1 launch=gmysql gmysql-host=localhost gmysql-dbname=powerdns gmysql-user=powerdns gmysql-password=PASSWORD gmysql-dnssec=yes loglevel=10 log-dns-queries=1
Add the yellow highlighted line to your PDNS config
sudo systemctl restart pdns.service sudo systemctl enable pdns-recursor.service sudo systemctl start pdns-recursor.service
Try it now....