Building a Secure DNS Infrastructure with BIND9


 "All the configurations and zone files I used are available on GitHub, and I'll walk you through the key parts that made the security features work."

When I decided to dive deep into DNS security, I knew I needed to move beyond the theoretical knowledge I'd picked up over the years. Sure, I understood how DNS queries worked and could troubleshoot basic resolution issues, but I had never actually implemented the security features that make DNS infrastructure robust and secure.

That's when I decided to build my own DNS infrastructure in my home lab using BIND9. My goal was simple: understand how DNS security really works by getting my hands dirty with the actual configurations.

Why BIND9 and Why Security?

I chose BIND9 for two main reasons - it's the most widely deployed DNS server software in enterprise environments, and it has comprehensive security features that I wanted to learn. I wasn't interested in just setting up basic DNS resolution; I wanted to understand split-horizon DNSTSIG authenticationsecure zone transfers, and dynamic DNS security. The learning approach was straightforward: build it, break it, fix it, and understand what's happening at every step.

The Lab Setup

I created a multi-VLAN environment in my home lab to simulate real-world network segmentation:

  • Primary DNS Server: dns1 (192.28.1.213)
  • Secondary DNS Server: dns2 (192.24.1.214)
  • Domain: gentech.solution
  • Internal Network: 192.28.1.0/24, 192.24.1.0/24
  • External Network: 192.27.1.0/24 (simulated via different VLAN)

The ease of this setup was that I could test different scenarios by simply switching between VMs on different VLANs - no need for actual separate physical networks.

What Split-Horizon DNS Actually Is

Think of split-horizon DNS like having two different phone books for the same company - one that internal employees see with everyone's extensions, and a public one that only shows the main reception number.

In normal DNS, everyone gets the same answer when they ask "where is vault.gentech.solution?" But with split-horizon DNS, your DNS server is smart enough to know who's asking and gives different answers based on whether you're inside the network or outside.

It's like having a bouncer at a club who knows the regulars. When someone from inside asks about internal systems, they get the real addresses. When strangers from the internet ask, they get nothing - or sometimes even fake information.

Split-Horizon DNS Actually Works

The moment that really made DNS security click for me was when I finally got split-horizon DNS working. I had configured different views in BIND9 - one for internal clients and another for external clients.

Here's what happened during my testing sequence:

  1. From my internal VM (192.28.1.x), I queried vault.gentech.solution
  2. Result: 192.24.1.130 - perfect!
  3. I switched to my external VM (192.27.1.x) and ran the same query
  4. Result: NXDOMAIN - The server acted like the record didn't exist

The same DNS server was giving completely different answers based on where the query came from. Internal users could see sensitive systems like the vault server, while external users got nothing. It wasn't just security through obscurity - it was network-level access control.

What TSIG Authentication Actually Is

Imagine you're running two bank branches that need to share customer account updates with each other. You can't just trust any random person who walks up claiming to be from the other branch - you need a secret handshake that proves they're legitimate.

TSIG (Transaction Signature) is basically that secret handshake for DNS servers. It's a shared secret key that two DNS servers use to prove to each other "yes, I'm really who I say I am, and this data hasn't been tampered with."

Without TSIG, anyone on the internet could potentially trick your DNS servers into accepting fake updates or stealing your entire DNS database through unauthorized zone transfers. With TSIG, every single DNS message gets cryptographically signed - like having a tamper-proof seal on every communication.

TSIG Authentication in Action

When I first configured TSIG between my primary and secondary DNS servers, I'll be honest - I wasn't entirely sure it would work. The concept seemed straightforward enough: generate a shared secret, configure both servers with the same key, and watch them authenticate each other.

But DNS is one of those things where you never really know if your security is working until you test it properly.

I generated a TSIG key (basically a long, random string that both servers would know) and added it to both my primary and secondary BIND9 configurations. The idea was simple: when my secondary server wanted to pull zone updates, it would sign its request with this key. The primary server would verify the signature before sending any data.

When I triggered a legitimate zone transfer with the proper TSIG key:

  1. The secondary server sent a signed request
  2. My primary server verified the signature and responded positively
  3. Zone data flowed smoothly between the servers
  4. Both servers logged successful, authenticated transactions
  5. Journal files were created and records updated automatically

It was like watching two security guards exchange proper credentials - professional, efficient, and secure.

Then I decided to play attacker. I spun up another VM and tried to request zone transfers without the TSIG key:

  1. The requests hit my primary DNS server
  2. Immediate rejection - not even a "wrong password" message, just flat denial
  3. Security events logged showing unauthorized transfer attempts
  4. Zero data leaked to the attacking system

The difference was that legitimate traffic flowed freely, while unauthorized requests got slammed shut immediately.

The Learning Process

What made this project valuable wasn't just getting the configurations working - it was understanding how these security features actually behave in practice. Reading about split-horizon DNS in documentation is one thing; watching it work in real-time with your own test queries is completely different.

The most challenging aspect was getting all the configurations properly coordinated between multiple servers, views, keys, and access control lists. But once everything clicked into place, I had a much deeper appreciation for how enterprise DNS infrastructure protects internal resources while maintaining necessary external services.

The Technical Details

Now, let's dive into the actual BIND9 configurations that created this secure DNS infrastructure. I'll walk you through each section and explain what's happening behind the scenes.

Setting Up Access Control Lists (ACLs)

First, I defined who's "internal" and who can be trusted:

include "/etc/bind/keys/zone-xfer.key";
acl "internal-network" {
192.28.1.0/24;
192.24.1.0/24;
127.0.0.1;
};
acl "secondaries" {
192.24.1.214;
};

What this does: Think of ACLs as VIP lists at a club. The internal-network ACL defines which IP ranges get the "insider" treatment - they can see everything. The secondaries ACL identifies my backup DNS server that's allowed to copy zone data.

The zone-xfer.key file contains the shared secret that makes TSIG authentication work. More on that in a moment.

Split-Horizon Views

Here's where the real thing happens - the same DNS server behaves completely differently based on who's asking:

Internal View (The VIP Section)

view "internal" {
match-clients { internal-network; };
zone "gentech.solution" {
type primary;
file "/etc/bind/zones/db.gentech.solution.internal";
allow-transfer { key "zone-xfer"; secondaries; };
also-notify { 192.24.1.214; };
allow-update { key "zone-xfer"; };
};

What this means: When someone from my internal networks (192.28.1.x or 192.24.1.x) asks about vault.gentech.solution, they get the internal zone file that contains all the sensitive servers, including the vault at 192.24.1.130.

The allow-transfer and allow-update lines mean "only accept zone transfers and dynamic updates if they're signed with our secret key." No key = no access.

External View (The Public Lobby)

view "external" {
match-clients { any; };
zone "gentech.solution" {
type primary;
file "/etc/bind/zones/db.gentech.solution.external";
allow-transfer { key "zone-xfer"; secondaries; };
also-notify { 192.24.1.214; };
allow-update { key "zone-xfer"; };
};
};

The key difference: External users get the external zone file that only contains basic public information. When they ask about vault.gentech.solution, they get NXDOMAIN - as far as they know, that server doesn't exist.

Comprehensive Security Logging

The logging setup was crucial for understanding what was happening:

logging {
channel security_log {
file "/var/log/named/security.log" versions 3 size 5m;
severity info;
print-time yes;
print-severity yes;
print-category yes;
};
channel update_log {
file "/var/log/named/update.log" versions 3 size 5m;
severity info;
print-time yes;
print-severity yes;
print-category yes;
};
// … more channels
category security { security_log; };
category update { update_log; };
category update-security { security_log; };
};

Why this matters: Every TSIG authentication attempt, every zone transfer, every dynamic update gets logged with timestamps and client IPs. When I tested unauthorized access, I could see exactly when and how the attempts were blocked.

Hardening the DNS Server

The security options lock down the server:

The security thinking:

  • recursion no means this server only answers for domains it's authoritative for
  • allow-transfer { none; } blocks zone transfers unless explicitly allowed per-zone
  • The "Not Disclosed" settings prevent information leakage about the server
  • Rate limiting stops abuse and DDoS attempts

How the TSIG Authentication Works

The real security comes from the TSIG keys. Every zone transfer and dynamic update requires this shared secret:

allow-transfer { key "zone-xfer"; secondaries; };
allow-update { key "zone-xfer"; };

In practice: When my secondary server requests a zone transfer, it signs the request with the shared key. BIND verifies the signature and only then allows the transfer. Without the key, requests get denied and logged as security events.

This is what made watching the logs so satisfying - I could see legitimate transfers succeeding and unauthorized attempts getting blocked in real-time.

The Result

This configuration creates multiple layers of security:

  1. Network segmentation through views
  2. Cryptographic authentication via TSIG
  3. Complete audit trails through comprehensive logging
  4. DDoS protection via rate limiting
  5. Information hiding to reduce the attack surface

The best thing is that it's all transparent to legitimate users while blocking unauthorized access at every level.

The Zone Files: Where Split-Horizon Happens

Here's where you can see the real difference between what internal and external users get when they query the same domain:

External Zone File

When external users query gentech.solution, they get this zone file:

@ IN NS ns1.gentech.solution.
@ IN NS ns2.gentech.solution.
; Name server A records (glue)
ns1 IN A 208.67.222.222 # OpenDNS
ns2 IN A 8.8.8.8 # Google DNS
www IN A 8.8.4.4 # Google DNS alt
mail IN A 1.1.1.1 # Cloudflare DNS

What external users see: Just basic public services with generic public IP addresses. No internal systems, no sensitive infrastructure. If they query for vault.gentech.solution - they get NXDOMAIN (doesn't exist).

Internal Zone File

When internal users query the same domain, they get completely different information:

ns1 A 192.28.1.213 # Real internal DNS server
ns2 A 192.24.1.214 # Real backup DNS server
vault A 192.24.1.130 # SECRET - only internals see this
hrsystem A 192.24.1.135 # HR system - internal only
intranet A 192.28.1.120 # Company intranet
exam A 192.24.1.218 # Exam system
testhost A 192.28.1.199 # Dynamic DNS test host

What internal users see: All the real infrastructure with actual internal IP addresses. The vault.gentech.solution what external users can't even see? Internal users get 192.24.1.130.

The Split-Horizon Effect in Action

Same query, different results:

  • Internal user queries vault.gentech.solution → Gets 192.24.1.130
  • External user queries vault.gentech.solution → Gets NXDOMAIN (server pretends it doesn't exist)

This is security through network segregation - not just hiding information, but serving completely different zone data based on who's asking.

Reverse DNS - Complete the Picture

The reverse zones ensure that IP-to-name lookups also work correctly:

192.24.1.0/24 reverse zone:

214 IN PTR ns2.gentech.solution.
130 IN PTR vault.gentech.solution. # The secret server
135 IN PTR hrsystem.gentech.solution.

192.28.1.0/24 reverse zone:

213 IN PTR ns1.gentech.solution.
120 IN PTR intranet.gentech.solution.

Why reverse zones matter: When internal monitoring tools do reverse DNS lookups on 192.24.1.130, they get back vault.gentech.solution. External users can't even reach that IP range, so the reverse lookup is irrelevant to them.

The Security Beauty

This setup creates:

  1. External attackers scanning gentech.solution only see generic public services
  2. Internal users get full access to all company resources with proper internal routing
  3. No information leakage - sensitive server names and IPs are completely hidden from external view

The same DNS infrastructure serves both audiences with completely different reality maps. That's the power of split-horizon DNS - one server, multiple truths.

Secondary DNS Server: Building Redundancy with TSIG Security

Now that the primary DNS server was working, I needed to set up the secondary server for redundancy. This is where TSIG authentication really shines - ensuring that only authorized servers can replicate zone data.

Secondary Server Configuration

The secondary server configuration is much simpler, but the security is just as tight:

view "internal" {
match-clients { internal-network; };
zone "gentech.solution" {
type secondary;
file "/var/cache/bind/db.gentech.solution.internal.slave";
primaries { 192.28.1.213 key "zone-xfer"; };
notify no;
allow-notify { 192.28.1.213; };
};

What this does: The secondary server says, "I'm a slave for this zone, get data from 192.28.1.213, but ONLY if they provide the correct TSIG key." No key = no zone transfer.

The notify no setting means the secondary doesn't send notifications, while allow-notify restricting who can tell it about zone updates.

The Moment of Truth: Testing Everything

Once both servers were configured, I ran comprehensive tests to prove the security model actually worked. Here are the results that convinced me this setup was secure:

Dynamic DNS Security Test

Authorized update (with TSIG key):

$ nsupdate -k /opt/zone_key/zone-xfer.key -v /tmp/ddns-test.txt
[Success - no output]

Unauthorized update (no key):

$ nsupdate -v /tmp/ddns-test.txt update failed: REFUSED

Security logs showed exactly what happened:

update-security: info: signer "zone-xfer" approved
update-security: error: update 'gentech.solution/IN' denied

This was great, legitimate updates succeeded and created journal files automatically, while unauthorized attempts were blocked and logged with full audit trails.

Split-Horizon Results That Proved It Works

Internal client (192.28.1.217) querying vault:

$ dig @192.28.1.213 vault.gentech.solution
vault.gentech.solution. 604800 IN A 192.24.1.130

External client (192.27.1.219) same query:

$ dig @192.28.1.213 vault.gentech.solution
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 13715

Same server, same query, completely different results. Internal users got the real vault server IP, external users got "doesn't exist."

Zone Transfer Security in Action

Authorized transfer (from secondary with TSIG):

xfer-out: info: transfer of 'gentech.solution/IN': AXFR started: TSIG zone-xfer
xfer-out: info: AXFR ended: 1 messages, 11 records, 388 bytes

Unauthorized transfer attempts:

$ dig @192.28.1.213 gentech.solution AXFR ; Transfer failed.

Security log:

security: error: zone transfer 'gentech.solution/AXFR/IN' denied

The logging was incredibly detailed - I could see exactly when transfers succeeded with proper authentication, and when unauthorized attempts were blocked.

What Impressed Me Most

The incremental zone transfer (IXFR) logs showed:

xfer-out: info: transfer of 'gentech.solution/IN': IXFR started: TSIG zone-xfer (serial 2025081707 -> 2025081708)

This wasn't just copying entire zone files - the system was intelligently transferring only the changes between serial numbers, all cryptographically authenticated. When I added that exam.gentech.solution record via dynamic DNS, only that specific change got replicated to the secondary server.

The Security Model That Actually Works

After all this testing, I had built a DNS infrastructure with:

Multiple security layers:

  • Network-based access control (views)
  • Cryptographic authentication (TSIG keys)
  • Complete audit logging (every operation tracked)
  • Automated redundancy (secondary server with secure replication)

Real-world features:

  • Split-horizon for internal vs external users
  • Secure dynamic DNS updates
  • Authenticated zone transfers
  • Rate limiting against DDoS
  • Information hiding to reduce the attack surface

What This Taught Me

The biggest learning wasn't just getting the configurations right - it was seeing how DNS security actually behaves in practice. Reading about TSIG authentication is one thing; watching unauthorized transfer attempts get blocked while legitimate ones succeed with full audit trails is completely different.

The comprehensive logging meant that in a production environment, security teams would have complete forensic evidence of every DNS operation. No unauthorized access could happen without leaving detailed traces.

Most importantly: This wasn't theoretical security - it was practical, tested, working security that I could verify with my own hands in my home lab.

This project transformed my understanding of DNS from "name resolution service" to "critical infrastructure that requires multiple layers of cryptographic and network-based protection."

Resources & Full Configuration Files

GitHub Repository: https://github.com/Deba1995/DNS-Infrastructure-Design-and-Implementation

This repo contains all the BIND9 configuration files, zone files, and test logs mentioned in this post. Feel free to clone it and adapt it for your own lab environment.

What you'll find:

  • Complete primary and secondary server configs
  • Internal and external zone files
  • TSIG key examples
  • Test output logs showing security in action

Have you implemented TSIG authentication or split-horizon DNS in your environment? What security challenges did you face? Share your experiences in the comments below.

Post a Comment

Previous Post Next Post