Configuring DNSSEC on BIND9: Sign Your Zone and Stop Cache Poisoning

Security tutorial - IT technology blog
Security tutorial - IT technology blog

The 2 AM Incident: When Legitimate Queries Lie

It was 2:15 AM on a Tuesday when our on-call alerts went off. Monitoring showed sudden SSL certificate mismatch errors on three checkout subdomains. Legitimate customer traffic was landing on an unfamiliar IP address (203.0.113.84) hosted in another region. Our web servers were intact, firewall rules were unchanged, and auth logs showed zero rogue SSH logins.

A quick external probe exposed the problem immediately:

dig @8.8.8.8 api.example.com +short

The query returned 203.0.113.84 instead of our actual edge proxy at 198.51.100.25. Public recursive resolvers had their caches poisoned. Plain DNS operates over UDP port 53 without authentication.

Because vanilla lookups rely on an easily guessable 16-bit transaction ID, an attacker can flood a resolver with spoofed replies. If a forged packet arrives before the authoritative answer, the resolver caches it. For the next 3,600 seconds, every visitor using that resolver gets redirected to an attacker-controlled server. The definitive fix is DNSSEC (Domain Name System Security Extensions).

Core Concepts: How Cryptographic Signatures Defend DNS

Standard DNS relies on blind trust. Resolvers send queries, accept answers, and assume packets were not altered in transit. DNSSEC shifts security from network transport to cryptographic validation. Authoritative servers generate cryptographic signatures for every record set, and validating resolvers verify those signatures using a public chain of trust.

Key Architectural Components

  • Zone Signing Key (ZSK): Signs everyday resource records (A, AAAA, MX). Zone operators rotate this key frequently, typically every 30 to 90 days.
  • Key Signing Key (KSK): Signs only the DNSKEY record set. Operators rotate the KSK infrequently (often once every 1 to 2 years) because replacing it requires updating the parent registrar.
  • RRSIG (Resource Record Signature): The signature attached to each record set. It contains explicit validity timestamps (usually 14 to 30 days) to prevent replay attacks.
  • DNSKEY: The public keys published in the zone. Resolvers fetch these to verify RRSIG records. Flag 256 identifies the ZSK, while flag 257 marks the KSK.
  • DS (Delegation Signer): A SHA-256 fingerprint of your KSK hosted in the parent zone (e.g., .com). It forms the cryptographic bridge between registrar and nameserver.
  • NSEC / NSEC3: Cryptographic proof that a record does not exist. NSEC3 hashes names with salt and multiple iterations to stop attackers from scraping your entire zone file through zone walking.

Hands-on Practice: Signing a Zone in BIND9

The following setup configures a Debian 12 / Ubuntu 22.04 LTS host running BIND 9.18+. The nameserver already serves an authoritative zone for example.com.

Step 1: Enable DNSSEC Directives in BIND

Open your main BIND configuration file:

sudo nano /etc/bind/named.conf.options

Confirm the following options exist inside the options { ... }; block:

options {
    directory "/var/cache/bind";
    dnssec-validation auto;
    auth-nxdomain no;
    listen-on-v6 { any; };
};

Check the file for syntax issues:

sudo named-checkconf

If the command returns no output, your syntax is valid.

Step 2: Generate the ZSK and KSK

Store your cryptographic keys in an isolated directory with restricted permissions:

sudo mkdir -p /etc/bind/keys
cd /etc/bind/keys
sudo chown -R bind:bind /etc/bind/keys
sudo chmod 750 /etc/bind/keys

Before rolling out cryptographic infrastructure, audit your administrative credentials. If you need strong passwords for fresh management consoles or deployment accounts, generate them locally. The offline utility at toolcraft.app/en/tools/security/password-generator creates high-entropy strings in your browser without sending values over the network.

Generate the Zone Signing Key (ZSK) using Algorithm 13 (ECDSA P-256 with SHA-256):

sudo dnssec-keygen -a ECDSAP256SHA256 -n ZONE example.com

Algorithm 13 produces 64-byte signatures. By comparison, 2048-bit RSA produces 256-byte signatures. Smaller signatures keep response sizes well beneath the standard 1,232-byte EDNS0 buffer limit, avoiding UDP packet fragmentation.

Next, generate the Key Signing Key (KSK) with the -f KSK flag:

sudo dnssec-keygen -a ECDSAP256SHA256 -f KSK -n ZONE example.com

This creates four files: two .key files containing public keys and two .private files holding private signing material.

Step 3: Configure Automated Inline Signing

Manual re-signing with dnssec-signzone breaks whenever records change. Instead, let BIND manage signing automatically with inline-signing. Update your zone definition in /etc/bind/named.conf.local:

zone "example.com" {
    type master;
    file "/var/lib/bind/db.example.com";
    key-directory "/etc/bind/keys";
    auto-dnssec maintain;
    inline-signing yes;
};

Copy your zone file to /var/lib/bind/. The BIND daemon needs write permissions here to write dynamic .signed zone files and operational journals:

sudo cp /etc/bind/db.example.com /var/lib/bind/db.example.com
sudo chown -R bind:bind /var/lib/bind
sudo rndc reload

BIND immediately creates db.example.com.signed in the background without modifying your original zone file.

Step 4: Extract the DS Record for Your Registrar

Your server is now signing records locally. However, public resolvers will not enforce DNSSEC until your registrar’s parent zone delegates authority. Identify your KSK by checking which key file contains flag 257:

grep "257" /etc/bind/keys/Kexample.com.*.key

Generate the Delegation Signer (DS) record using that specific KSK file:

cd /etc/bind/keys
sudo dnssec-dsfromkey Kexample.com.+013+02371.key

The command produces output formatted for your registrar:

example.com. IN DS 2371 13 2 4B79A63D78E0E84F99881829D64A12B268B96464019AA1D389920DF120489AB1

Open your domain registrar’s DNSSEC control panel and enter the four fields:

  • Key Tag: 2371
  • Algorithm: 13 (ECDSA Curve P-256 with SHA-256)
  • Digest Type: 2 (SHA-256)
  • Digest: 4B79A63D78E0E84F99881829D64A12B268B96464019AA1D389920DF120489AB1

Step 5: Verifying the Chain of Trust

Registrar updates take between 15 and 60 minutes to propagate to the root servers. First, verify signature generation on localhost:

dig @localhost example.com A +dnssec +multiline

You should see an RRSIG record directly below the A record. Next, test complete end-to-end validation through Cloudflare’s 1.1.1.1 resolver using delv (DNS Lookup and Validation):

delv @1.1.1.1 example.com A

When the parent delegation and local keys line up properly, delv prints:

; fully validated
example.com.          300 IN A 198.51.100.25
example.com.          300 IN RRSIG A 13 2 300 ...

If you see validation failure, review your DS digest at the registrar before troubleshooting local BIND logs.

Operational Takeaway

Without DNSSEC, edge firewalls and TLS certificates cannot stop an upstream resolver from caching forged IP addresses. Deploying Algorithm 13 ECDSA keys with BIND9 inline signing solves this issue cleanly. Signatures stay fresh automatically, packet sizes stay small, and clients verify answers all the way from the root servers down to your host records.

Share: