Articles
DNSSEC Explained: How It Works, How to Set It Up, and How to Test It
DNS

DNSSEC Explained: How It Works, How to Set It Up, and How to Test It

DNS answers can be forged. DNSSEC adds signatures so resolvers can prove they are genuine. A beginner friendly but technically accurate guide to the chain of trust, current algorithm choices, and signing and testing a zone with BIND and Windows DNS Server.

R

Roy Hagland

Published 20 September 2026

DNS

Every time you type a website name, your device asks DNS to turn it into an IP address. The uncomfortable part is that classic DNS has no way to prove the answer is genuine. If someone slips a fake answer into the conversation, your resolver believes it and sends you to the wrong server. DNSSEC fixes that. This article explains what it is, why it exists, how to turn it on for your own domain, and how to test that it actually works.

The problem DNSSEC solves

DNS was designed in the 1980s for a friendly network. A resolver asks a question, something replies, and the first plausible answer wins. There is no signature and no proof of who sent it. Attacks such as cache poisoning exploit this: an attacker races the real server, forges a reply, and the resolver stores the lie for as long as the record's TTL allows. Everyone using that resolver is then sent to the attacker's address.

DNSSEC (DNS Security Extensions) adds digital signatures to DNS data. A validating resolver checks those signatures and refuses to hand out anything that does not verify. The goal is authenticity and integrity: the answer really came from the zone owner and was not changed on the way.

What DNSSEC does not do

  • It does not encrypt anything. Anyone on the path can still see which names you look up. Encrypted transports such as DNS over TLS or DNS over HTTPS solve that separate problem.

  • It does not protect the website itself. It proves the IP address came from the domain owner, not that the server behind it is trustworthy. You still need HTTPS.

  • It only helps if the resolver validates. Signing your zone does nothing for users whose resolver ignores signatures.

The building blocks

You only need a handful of record types to understand DNSSEC.

  • RRSIG: the signature over a set of records. Every signed record set (for example all the A records for www) gets its own RRSIG, with a start and expiry time.

  • DNSKEY: the public key published in your zone, used to verify the signatures.

  • DS (Delegation Signer): a fingerprint (hash) of one of your DNSKEYs, published in the parent zone. This is the link that ties your zone to the zone above it.

  • NSEC / NSEC3: records that prove a name does not exist. Without them an attacker could forge "no such domain" answers, and you cannot sign something that is not there.

  • CDS / CDNSKEY: records in your zone that tell the parent which DS you want, allowing the registry to update it automatically.

KSK and ZSK

Traditionally a zone has two kinds of keys. The Key Signing Key (KSK) signs only the DNSKEY set, and its hash is what the parent stores as the DS. The Zone Signing Key (ZSK) signs everything else. Splitting them lets you rotate the busy ZSK often without touching the parent. Many modern setups use a single Combined Signing Key (CSK) that does both jobs, which is simpler and perfectly acceptable with modern algorithms.

The chain of trust

Here is the idea in plain words. Your resolver already trusts one thing: the public key of the DNS root, built into its software (the trust anchor). From there:

  • The root zone signs a DS record for com, so the resolver can trust the com keys.

  • The com zone holds a DS record for example.com, signed by com's keys, so the resolver can trust example.com's keys.

  • example.com signs its own records, so the resolver can trust the answer for www.example.com.

Each link vouches for the next. If any link is missing or wrong, the chain breaks. This is why the DS record at your registrar matters so much: without it, your zone is signed but nobody has a reason to trust it. This state is called "insecure" and behaves like ordinary DNS. With a wrong DS, the state is "bogus", and validating resolvers will return an error (SERVFAIL) for your domain.

Choosing algorithms in 2026

The official recommendations are now kept in the IANA registries for DNSSEC algorithms and DS digest types. RFC 9904 moved them there from the older RFC 8624, so check the registries rather than an old article, this one included. At the time of writing they say:

  • Algorithm 13, ECDSA P-256 with SHA-256: recommended for signing. Small keys and signatures, universally supported. This is the practical default.

  • Algorithm 15, Ed25519: also recommended for signing, compact and modern. Check that your software and registrar support it before choosing it.

  • Algorithm 8, RSA with SHA-256: still recommended and widely supported, but its keys and signatures are larger.

  • Algorithms 14 (ECDSA P-384) and 16 (Ed448): allowed (MAY), rarely needed.

  • Algorithms 5 and 7 (RSA with SHA-1): MUST NOT be used for signing. Resolvers still validate them, so old zones keep working, but never create new ones this way.

  • For the DS record digest use SHA-256 (digest type 2). Publishing SHA-1 (type 1) DS records is a MUST NOT.

If you use NSEC3 instead of plain NSEC, follow RFC 9276: use zero additional iterations (a MUST) and no salt (a SHOULD NOT use one). Extra iterations cost resolvers CPU and add no real protection, so validating resolvers may treat a zone with a high iteration count as insecure or even fail it.

Setting it up

Enabling DNSSEC is always the same three steps, whatever software you use:

  • Generate keys and sign the zone.

  • Give the parent (through your registrar) the DS record.

  • Test the whole chain.

Option 1: your DNS host does it for you

If your domain uses a managed DNS provider (Cloudflare, Route 53, and most others), signing is a toggle. The provider generates the keys and signs the zone. It then shows you the DS record, and you paste it at your registrar. If the registrar and DNS provider are the same company, it is often done for you. Skip to the testing section.

Option 2: signing on your own BIND server

Current BIND 9 can manage keys, signing and rollovers itself through a dnssec-policy. You no longer need to run key tools by hand. The examples use BIND 9.20. In your zone definition:

zone "example.com" {
    type primary;
    file "/var/lib/bind/example.com.db";
    dnssec-policy default;
    inline-signing yes;
};

The built-in default policy uses ECDSA P-256 (algorithm 13) with a single CSK, suitable for most zones. Reload the configuration and BIND creates the key and signs the zone within a few seconds. You can watch progress with:

rndc reload
rndc dnssec -status example.com
dig @127.0.0.1 example.com DNSKEY +multi

The status output shows the key, for example key: 19984 (ECDSAP256SHA256), CSK, and the state of each part of the rollout. Until you publish the DS at the parent, the DS state stays hidden, which is expected.

Keep the unsigned zone file as your source of truth. With inline signing BIND keeps the signed copy separately, so you edit the plain file as usual, increase the SOA serial, and reload. BIND signs new records automatically and by default refreshes signatures before they expire. With the default policy each signature is valid for 14 days.

If you want a different algorithm, define your own policy. This one uses Ed25519:

dnssec-policy "ed" {
    keys { csk lifetime unlimited algorithm ed25519; };
};

Option 3: signing on Windows DNS Server

If your DNS lives on Windows Server, typically on your domain controllers, you can sign zones without any extra software. The examples use the DnsServer PowerShell module on Windows Server 2022 with an Active Directory-integrated zone. Windows also has a signing wizard in DNS Manager, but PowerShell is easier to repeat and to document, so that is what is shown here. Run the commands in an elevated PowerShell session on the DNS server.

What the defaults give you

The quickest way to sign a zone is:

Invoke-DnsServerZoneSign -ZoneName "example.com" -SignWithDefault -Force

It works, and the zone is signed straight away. But look at what you get by default:

  • RSA/SHA-256 keys: a 2048 bit KSK and a 1024 bit ZSK. This is algorithm 8, still acceptable but not the modern choice above.

  • NSEC3 with 50 iterations and an 8 byte salt, which goes against RFC 9276.

  • DS records generated as both SHA-1 and SHA-256. Do not publish the SHA-1 ones.

  • Automatic key rollover switched on: the ZSK every 90 days and the KSK every 755 days.

You can read these back at any time:

Get-DnsServerSigningKey -ZoneName "example.com"
Get-DnsServerDnsSecZoneSetting -ZoneName "example.com"

One thing in that output can look alarming: NSec3HashAlgorithm shows RsaSha1. That is the hash NSEC3 uses to scramble names. It is the only one defined for NSEC3, it is unrelated to the signing algorithm, and it is not the SHA-1 signing problem mentioned earlier.

Signing with ECDSA and modern NSEC3 settings

Windows offers RSA (SHA-1, SHA-256, SHA-512) and ECDSA (P-256 and P-384). It does not offer Ed25519, and PowerShell rejects it as an invalid value. To get ECDSA P-256 (algorithm 13), zero NSEC3 iterations and SHA-256 only DS records, use this order. It matters, because Windows will refuse some steps at the wrong moment:

# 1. Sign with defaults first. This also makes this server the Key Master for the zone.
Invoke-DnsServerZoneSign -ZoneName "example.com" -SignWithDefault -Force

# 2. Add ECDSA P-256 keys.
Add-DnsServerSigningKey -ZoneName "example.com" -Type KeySigningKey -CryptoAlgorithm ECDsaP256Sha256
Add-DnsServerSigningKey -ZoneName "example.com" -Type ZoneSigningKey -CryptoAlgorithm ECDsaP256Sha256

# 3. Unsign the zone. The keys are remembered.
Invoke-DnsServerZoneUnsign -ZoneName "example.com" -Force

# 4. Remove the RSA keys (this only works while the zone is unsigned).
Get-DnsServerSigningKey -ZoneName "example.com" | Where-Object CryptoAlgorithm -eq "RsaSha256" | ForEach-Object { Remove-DnsServerSigningKey -ZoneName "example.com" -KeyId $_.KeyId -Force }

# 5. Set NSEC3 to zero iterations and no salt, and DS records to SHA-256 only.
Set-DnsServerDnsSecZoneSetting -ZoneName "example.com" -DenialOfExistence NSec3 -NSec3Iterations 0 -NSec3RandomSaltLength 0 -DSRecordGenerationAlgorithm Sha256

# 6. Sign again, using the keys and settings you just configured.
Invoke-DnsServerZoneSign -ZoneName "example.com" -Force

Do all of this before you publish anything at your registrar, so that the DS you publish is the final one. Three Windows behaviours explain the shape of that sequence:

  • On a zone that has never been signed, Add-DnsServerSigningKey fails with "not the Key Master", which is why step 1 comes first.

  • Windows will not delete the RSA keys from a signed zone (the removal fails), only from an unsigned one, which is why step 3 comes before step 4.

  • Do not use -DoResign on an unsigned zone. It fails because the zone is not signed. A plain Invoke-DnsServerZoneSign -Force uses the keys already configured.

Now check the result. The keys should show ECDsaP256Sha256, the settings should show NSEC3 with 0 iterations, and the signature and key records on the wire should say algorithm 13:

Get-DnsServerSigningKey -ZoneName "example.com"
Get-DnsServerDnsSecZoneSetting -ZoneName "example.com"
Resolve-DnsName www.example.com -Type A -DnssecOk -Server 127.0.0.1 -DnsOnly
Resolve-DnsName example.com -Type DNSKEY -Server 127.0.0.1 -DnsOnly

Getting the DS record for your registrar

New-Item -ItemType Directory -Path C:\Temp -Force
Export-DnsServerDnsSecPublicKey -ZoneName "example.com" -DigestType Sha256 -Path C:\Temp -Force
Get-Content C:\Temp\dsset-example.com

This writes a file named dsset-example.com in standard DS format. Copies of the dsset and keyset files are also kept in C:\Windows\System32\dns on the Key Master. You will see two DS lines, for example:

example.com. 3600 IN DS 17252 13 2 ( 3ec4...30a7 )
             3600 IN DS  6609 13 2 ( dfef...d651 )

There are two because Windows keeps a standby KSK, and the zone publishes four DNSKEY records (two KSKs and two ZSKs). Microsoft documents that automatic KSK rollover uses the double signature method, where the new key is added alongside the old one before the old one is retired. With that method the sensible practice is to publish the DS for the standby key at your registrar ahead of time, if it accepts more than one DS record. Windows does not update the registrar for you, so every KSK rollover means checking that the DS at the parent still matches.

Things that matter on a domain controller

  • Key storage and Key Master. For an AD-integrated zone the keys are stored in Active Directory (StoreKeysInAD shows True). One server is the Key Master, and Get-DnsServerDnsSecZoneSetting shows which one in the KeyMasterServer field. Write that server down. Key changes and settings are made through the Key Master, so move the role before you retire or rebuild that server. Run this on the server that should become the new Key Master, in a full logon session, not a remote PowerShell session (for example a scheduled task that runs on that server):

    Reset-DnsServerZoneKeyMasterRole -ZoneName "example.com" -KeyMasterServer "DC2.corp.example.com" -Force

    Both servers keep serving signed answers while the role moves. Run from a remote PowerShell session the same command fails, because the new Key Master has to contact the old one and a remote session cannot pass your credentials on to a second server. If the current Key Master is already gone, Microsoft documents a -SeizeRole switch for that case.

  • Other domain controllers serve the signed zone. Once AD replication has run, the other domain controllers serve the signed zone too. Allow time for replication, especially to domain controllers in other subnets or sites, before you test each server.

  • Dynamic updates are signed automatically. Records added to a signed zone by dynamic update are signed automatically, so you do not re-sign by hand.

  • Signing an internal AD zone is a separate decision. Most internal domains such as corp.example.com are never reachable from the internet. Signing a public zone that you host on Windows is the more common reason to use the steps above. If you also want your own DNS servers to validate an internal signed zone, they need a trust anchor for it. Read Microsoft's documentation on DNSSEC trust anchors first, because a mistake there makes names fail to resolve.

  • Removing DNSSEC. Invoke-DnsServerZoneUnsign -ZoneName "example.com" -Force unsigns the zone, but only after you have removed the DS from the parent, as described under "Keeping it healthy".

Option 4: other servers

Other authoritative DNS servers have their own tools for signing. The concepts above are identical whatever you use: pick a modern algorithm, sign, then publish the DS. Check your server's documentation for exactly which algorithms it offers, as support differs.

Publishing the DS record

Now the step everyone forgets. (On Windows, use the exported dsset file described above.) Ask the zone for the DS values:

dig @127.0.0.1 example.com DNSKEY | dnssec-dsfromkey -2 -f - example.com

This prints a DS record: a key tag, an algorithm number, digest type 2, and a long hex digest. Enter those four values in the DNSSEC or DS section of your registrar's control panel. Some registrars take the DNSKEY itself and work out the DS for you. Copy carefully. A typo here makes your domain unreachable for validating resolvers.

Some registries can take the DS from your zone automatically. For that your zone publishes CDS and CDNSKEY records (RFC 7344 and RFC 8078), which say which DS you want. BIND's built-in default policy does not publish them. To turn them on, define a policy with these two lines:

dnssec-policy "with-cds" {
    keys { csk lifetime unlimited algorithm ecdsap256sha256; };
    cdnskey yes;
    cds-digest-types { "sha-256"; };
};

Then dig example.com CDS +short returns a DS style line once the key has been published. Registries that support RFC 9615 can even bootstrap the very first DS from these signals, but support is far from universal, so plan on entering the first DS by hand and treat automation as a bonus.

Testing

Test in layers. Never assume success just because the registrar accepted the DS.

1. Is the zone signed?

dig +dnssec example.com A

Look for an RRSIG record next to your A record. If it is there, the zone is being signed.

2. Does the parent have the right DS?

dig example.com DS +short
dig example.com DNSKEY +short

The DS from the parent must match a DNSKEY in your zone. You can regenerate the DS from your DNSKEY with dnssec-dsfromkey and compare the key tag and digest.

3. Does a validating resolver accept it?

dig @1.1.1.1 +dnssec example.com A

In the header flags, look for ad (Authenticated Data). It means the resolver validated the answer. If you see no ad flag, either the chain is incomplete (still insecure) or the resolver does not validate. Try another public validating resolver to tell which. Remember that ad is only meaningful when you trust the path to the resolver, since an attacker in between could set it.

The delv tool that ships with BIND does its own validation and shows exactly where a chain breaks:

delv @1.1.1.1 example.com A +vtrace

A healthy result says fully validated.

4. Telling "bogus" from "just broken"

If a domain gives SERVFAIL, ask again with checking disabled:

dig @1.1.1.1 example.com A
dig @1.1.1.1 example.com A +cd

The +cd flag means "checking disabled". If the first fails but the second returns an answer, the problem is DNSSEC validation, not the record itself. That is the signature of an expired signature or a DS mismatch. You can see it live against the deliberately broken test name:

dig @1.1.1.1 sigfail.verteiltesysteme.net A       # status: SERVFAIL
dig @1.1.1.1 +cd sigfail.verteiltesysteme.net A   # status: NOERROR, with an answer

A DS at the parent that does not match the child's key produces exactly this: SERVFAIL normally, an answer with +cd, and delv reporting "broken trust chain". The resolver's log names the cause (Unbound logs "DS hash mismatches key"), so read the resolver log when you have access to it.

The reverse case is quieter. If your zone is signed but the parent has no DS, everything resolves normally, just without the ad flag. Nothing breaks and nothing is protected.

5. Online checkers

Web tools give a full picture in seconds: DNSViz (dnsviz.net) draws the whole chain of trust and highlights errors, Verisign's DNSSEC Analyzer and Zonemaster check for both DNSSEC and general delegation problems. Run one after every change.

Testing from Windows

You do not need Linux tools to check a zone. Resolve-DnsName can ask for DNSSEC records directly:

Resolve-DnsName example.com -Type A -DnssecOk -Server 1.1.1.1
Resolve-DnsName example.com -Type DNSKEY -Server 1.1.1.1
Resolve-DnsName example.com -Type A -DnssecOk -DnssecCd -Server 1.1.1.1

With -DnssecOk you should see RRSIG records in the output next to the A record. The last command sets the checking-disabled flag, so it is the Windows equivalent of dig +cd. Note that plain nslookup cannot ask for DNSSEC record types (it reports "unknown query type: RRSIG"), so use Resolve-DnsName instead. Windows does not ship delv, so for that check use a Linux machine or WSL, or rely on the online checkers above.

Is your own resolver validating?

Your users are only protected if the resolver they use validates. To test yours, query a domain that is deliberately broken. A validating resolver must refuse it:

dig sigfail.verteiltesysteme.net A
dig sigok.verteiltesysteme.net A

These are public test names for exactly this purpose. The first should return SERVFAIL on a validating resolver, and the second should succeed and carry the ad flag. Cloudflare (1.1.1.1), Google (8.8.8.8) and Quad9 (9.9.9.9) all behave this way, as does a local Unbound install with the root trust anchor. Unbound and BIND normally validate out of the box on current distributions.

Keeping it healthy

DNSSEC is not "set and forget" in the way ordinary DNS is. Signatures expire, so something has to keep re-signing. Modern tools automate this, but you should still know the failure modes.

  • Expired signatures. If re-signing stops (a crashed service, a stopped secondary), signatures run out and validating resolvers reject the whole zone. Monitor signature expiry.

  • Key rollovers. Keys should be replaced periodically or after a compromise. A rollover must follow a strict order: new keys published first, then used, then old keys removed, with waits based on TTLs. Let your software's policy handle this and do not do it by hand unless you must.

  • Changing DNS providers. This is the most common way people take their domain offline. Moving to a provider that cannot serve the old signatures while the old DS is still at the parent breaks validation. Either remove the DS at the registrar first and wait for its TTL to expire, or use a documented multi-signer setup. Then enable DNSSEC again on the new provider.

  • Turning DNSSEC off. Always remove the DS from the parent first, wait for the old TTL to pass, and only then stop signing. Doing it the other way round breaks the domain: a validating resolver returns SERVFAIL for a zone that is served unsigned while the parent still has its DS ("No DNSKEY record"), and removing the DS fixes it.

  • Larger responses. Signatures make DNS packets bigger. Make sure your firewall allows DNS over TCP as well as UDP, and that it does not drop fragmented or large UDP replies.

Should you bother?

For most public domains, yes. It is free with most providers, it is a small toggle, and it protects users against a real attack class. It also enables newer security features that depend on trustworthy DNS answers, such as DANE for email. The cost is operational: a mistake causes outages rather than silent failures, so test carefully and monitor. Start with a low-stakes domain, get comfortable with the tools above, and then roll it out to the ones that matter.

Quick reference

  • Algorithm: 13 (ECDSA P-256), or 15 (Ed25519) if supported everywhere you need it.

  • DS digest: SHA-256 (type 2).

  • NSEC3, if used: 0 iterations, no salt.

  • Sign, publish the DS at the registrar, then test with dig +dnssec, delv and DNSViz.

  • Remove the DS before you disable signing or leave a provider.

  • Look for the ad flag from a validating resolver, and use +cd to isolate validation failures.

Comments

Log in to comment

No comments yet. Be the first to comment.