Skip to content

Instantly share code, notes, and snippets.

@stolendata
Created May 4, 2025 13:58
Show Gist options
  • Save stolendata/7b49632b770a948bef2486db734d9ee1 to your computer and use it in GitHub Desktop.
Save stolendata/7b49632b770a948bef2486db734d9ee1 to your computer and use it in GitHub Desktop.
DNSSEC with NSD/BIND and ldns

create your zone-signing key (ZSK) and key-signing key (KSK)

ldns-keygen -a ED25519 example.com > zsk
ldns-keygen -a ED25519 -k example.com > ksk

...alternately, if you or your TLD prefer outdated key algorithms...

ldns-keygen -a RSASHA256 -b 1024 example.com > zsk
ldns-keygen -a RSASHA256 -b 2048 -k example.com > ksk

the delegation signer (DS) and keys end up in the files Kexample.com.+NNN+NNNNN.* while zsk and ksk will merely contain the respective key names for easy referencing. don't lose your keys.

-rw-r--r--  1 root  wheel   113 May 2  12:28 Kexample.com.+015+71339.key
-rw-------  1 root  wheel   106 May 2  12:28 Kexample.com.+015+71339.private
-rw-r--r--  1 root  wheel   103 May 2  12:28 Kexample.com.+015+71339.ds
-rw-r--r--  1 root  wheel   113 May 2  12:28 Kexample.com.+015+80915.key
-rw-------  1 root  wheel   106 May 2  12:28 Kexample.com.+015+80915.private
-rw-r-----  1 root  _nsd   1374 Feb 11 19:41 example.com.zone
-rw-r--r--  1 root  wheel    24 May 2  12:28 ksk
-rw-r--r--  1 root  wheel    24 May 2  12:28 zsk

sign your zone-file

since people can never agree on anything, common recommendations on DNSSEC signature lifetimes are 48 hours, 5 days, a week, 3 weeks, 32 days and god knows what else. in this example we'll set the effective lifetime to about 14 days. the inception and expiry datetime format is YYYYMMDD[hhmmss] (UTC) and if you omit the time it will default to midnight. today is May 2nd 2025 so we'll set the inception to May 1st and expiry to May 17th, for some leeway in case we are close to midnight.

INCDT=20250501
EXPDT=20250517

ldns-signzone -n -s '' -t 0 -i $INCDT -e $EXPDT example.com.zone $(<zsk) $(<ksk)

...alternately, to sign with older NSEC instead of the newer NSEC3 standard...

INCDT=20250501
EXPDT=20250517
SALTLOL=$(openssl rand -hex 8)

ldns-signzone -s $SALTLOL -i $INCDT -e $EXPDT example.com.zone $(<zsk) $(<ksk)

in goes example.com.zone and out comes example.com.zone.signed. reconfigure and restart your name server so that it uses the signed zone-file. remember to re-sign your zone before it expires, as well as every time you make changes to it. you don't need to create a new KSK or ZSK every time you sign your zone.

publish your DS and/or DNSKEY with your domain registrar

some TLDs will carry only the DS, some only the DNSKEY (from which the DS is derived), and some insist that you provide both. the DS and DNSKEY entries are often referred to as dsData and keyData. the details you want to publish are those of your key-signing key (KSK), not your zone-signing key (ZSK).

# cat $(<ksk).ds
example.com. 1800  IN  DS  71339 15 2  25cc670a56b6e4f1...e631f30846e60147

# cat $(<ksk).key
example.com. IN  DNSKEY  257 3 15  lQc7kV/S...WAKz+Io= ;{id = 71339 (ksk), size = 256b}

for the DS in this example 71339 is the key tag/id, 15 is the key algorithm (ED25519), 2 is the digest algorithm (SHA256) and the hexscii string is the digest. for the KSK 257 are the flag bits (indicating a KSK whereas 256 would indicate a ZSK), 3 is the protocol (DNSSEC) and the base64-encoded string is the DNSKEY/pubkey.

addendum

there's no technical requirement to rotate your KSK or ZSK. constantly rotating keys is circus "security posture" if there's a fundamental failure to keep the keys safe in the first place.

if you choose to replace the KSK you should publish the new KSK before unpublishing the old one, to prevent a lapse in service. the ZSK is confined within your zone and can be replaced without involving your registrar. changing either key requires you to re-sign your zone.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment