I own and manage a few domain names, including the
bksp.space zone containing the domain of this blog, and run and host their nameservers myself. Since the beginning I have always been using Bind9 as this is the tool I learnt first and then I have not really looked into others. First because I didn't really care, I mean it worked already, why would I changed? And then after spending some time configuring DNSSEC, including signature rotation and such, using bash scripts I did not wanted to go through the same burden again.
Even though, for a while I came upond other authoritative DNS software but none of the really catched my eyes, I mean PowerDNS seams nice feature wise but does not look that much simpler to configure and operate. But recently I come accross people on the Fediverse using Knot DNS to host their zones and being some curious I decided to have a look. So Knot-DNS is developped and used by the Czech NIC and, compared to the other softwares mentionned, is rather recent, Bind and PowerDNS came out in 1986 and 1999 respectvely while Knot-DNS has been initially released in 2011. What I really liked though is the simplicity of the configuration and the possibility to have the keys and zone signature management fully automated, without too much hassle.
I you want to know more about it I recommned you to visit the documentation and guides, now I will simply describe what I have done to migrate the zone.
To install knot simply fetch it from you distribution repositories, I am running Archlinux so in my case it would be
pacman -Sy knot. In my previous setup I had a directory
my.zone.tld.d for each zone containing the keys and the zone file, for
bksp.space it looked like this.
/var/named/bksp.space.d/ ├── Kbksp.space.+007+05001.key ├── Kbksp.space.+007+05001.private ├── Kbksp.space.+007+15557.key ├── Kbksp.space.+007+15557.private ├── bksp.space.zone ├── bksp.space.zone.signed └── dsset-bksp.space.
While the keys will not be living their anymore but in Knot keystore I could go back to having a single file per zone but I will stick to that structure in case I want to do some includes in the future. So to migrate the zone I simply copy the folder to what will be Knot storage directory.
$ mkdir -p /var/lib/knot/zones $ cp -r /var/named/bksp.space.d /var/lib/knot/zones $ chown -R knot:knot /var/lib/knot/zones
Then it's time for the configuration, while it may look like YAML, experience has taught that it is not really, the first new blocks are quite simple, I configure the server to use the
knot user, default, to listen on my public IPs and then configure logging to use the syslog and change server log level to waring to avoid unnessary notices about TCP client disconnection. Finally as mentionned before the base storage directory will be
/var/lib/knot, again the default on my distribution.
server: rundir: "/run/knot" user: knot:knot listen: [ 198.51.100.1@53, 2001:db8:cafe:bc68::1@53 ] log: - target: syslog zone: info control: info server: warning database: storage: "/var/lib/knot"
Then I created a default policy for DNSSEC management. I am using
rsasha1-nsec3-sha1 algorithm as this is what my keys have been generated with, change that to your will if that is not what you have been using. I like me your not sure what algorithm you used, it's been two years since I have done, you can check the content of you private key, in Bind9 format, the second line indicates the algorithm.
$ cat /var/lib/knot/zones/bksp.space.d/Kbksp.space.+007+05001.private Private-key-format: v1.3 Algorithm: 7 (NSEC3RSASHA1) ....
The next configuration items is related to the signature and keys lifetime, I am neither a security nor DNS expert but rotating the signatures every week and the zone signing key every month looked like sane values. Next I enabled NSEC3 records to prevent zone walking. Finally I temporarily set the key management to manual as I will manually import the keys later and I wanted to test the zone as early as possible.
policy: - id: default algorithm: rsasha1-nsec3-sha1 rrsig-lifetime: 14d rrsig-refresh: 7d zsk-lifetime: 30d dnskey-ttl: 24h nsec3: on nsec3-iterations: 10 nsec3-opt-out: on nsec3-salt-lifetime: 14d nsec3-salt-length: 40 manual: on
A nice feature about Knot DNS is the configuration templates that allows to define template of configuration that you will apply to zones to quickly configure zones with similar configurations.
I defined two templates for primary, or master, zones,
signed the only difference between the two begin the last to additional lines of the
signed template. The first enable automatic DNSSEC signing and the second one refer to the DNSSEC policy previously created.
Now for the remaining fields, I indicate again the storage directory and then the zone file path,
%s will be replaced by the zone name. The journal here refers to an database backed changelog to persist changes between restarts if they have not been flushed to the zone file. Here the value is
all and the automatic flush to file is disabled by setting a value of -1 to
zonefile-sync period. Means that the whole zone is stored in the journal and the original zone file is never altered by dynamic update like zone signing (or DDNS but I am not currently using that). As stated in the documentation:
Some users dislike that the server overwrites their prettily prepared zone file.
I am one of those users.
difference-no-serial means that the serial is automatically updated when reloading the zone file content using the
dateserial format (
I haved also prepared a
secondary template for secondary or slave zone. In that case no file is used and the content of the zone is exclusively stored in the journal.
template: - id: default storage: "/var/lib/knot" file: "zones/%s.d/%s.zone" journal-content: all zonefile-load: difference-no-serial zonefile-sync: -1 serial-policy: dateserial - id: signed storage: "/var/lib/knot" file: "zones/%s.d/%s.zone" journal-content: all zonefile-load: difference-no-serial zonefile-sync: -1 serial-policy: dateserial dnssec-signing: on dnssec-policy: default - id: secondary journal-content: all zonefile-load: none zonefile-sync: -1
It is almost time to define the zone but I still need to do one thing before, defining remotes and ACLs to allow transfer to secondary name servers.
It might looks a bit confusing but here I have two dns servers acting both as primary and secondary servers for each other. So the remotes define the servers and the ACL the permission, I am using IP based ACL, I could of course be using shared key based ACL.
So I authorized the transfer of the zone to the ACL
bksp_secondary_acl and authorized the zone to be transfer to me for the ACL
remote: - id: bksp_secondary address: [ 198.51.100.2, 2001:db8:cafe:bc68::2 ] - id: primary address: [ 198.51.100.2, 2001:db8:cafe:bc68::2 ] acl: - id: bksp_secondary_acl address: [ 198.51.100.2, 2001:db8:cafe:bc68::2 ] action: transfer - id: primary_acl address: [ 198.51.100.2, 2001:db8:cafe:bc68::2 ] action: notify
Then the zone configuration block looks like this, using the defined templates, remotes and ACLs.
zone: # Primary zones - domain: bksp.space notify: bksp_secondary acl: bksp_secondary_acl template: signed # Secondary zones - domain: example.com master: primary acl: primary_acl template: secondary
You can check you configuration using the
$ knotc conf-check Configuration is valid
Importing the keys
The tool to manage keys is
keymgr, to import the key run
keymgr <zone> import-bind on both the KSK and the ZSK. Be sure that the files are owned by the
knot user, if not it might not work. By default once imported the keys are stored in pem format in the
$ keymgr bksp.space import-bind /var/lib/knot/bksp.space.d/Kbksp.space.+007+05001 $ keymgr bksp.space import-bind /var/lib/knot/bksp.space.d/Kbksp.space.+007+15557
If you want to be sure you can list the keys owned by a zone with:
$ keymgr bksp.space list <long hash> ksk=yes zsk=no tag=05001 algorithm=7 size=4096 public-only=no pre-active=0 publish=1564190151 ready=0 active=1564190151 retire-active=0 retire=0 post-active=0 revoke=0 remove=0 <long hash> ksk=no zsk=yes tag=05528 algorithm=7 size=2048 public-only=no pre-active=0 publish=1610134471 ready=0 active=0 retire-active=0 retire=0 post-active=0 revoke=0 remove=0 <long hash> ksk=no zsk=yes tag=15557 algorithm=7 size=2048 public-only=no pre-active=0 publish=1564190124 ready=0 active=1564190124 retire-active=0 retire=0 post-active=0 revoke=0 remove=0
Here I have three keys because I have rotated the ZSK.
You can now reload Knot to take you changes in account and don't forget to check for potential errors by checking the service status. I everythin went well you should see logs telling that you zone has been signed.
$ knotc reload Reloaded $ systemctl status knotc
Finally you can turn off the
manual configuration entry to let Knot rotate the KSZ for you.
Now that the ZSK rollover has been automated the final step for me would be to rotate the KSK in a similar manner. This one is more complex as the new DS record needs to be pushed in the parent zone. Fortunately, according to documentation the key submission event is logged in a way that allow automation.
If systemd is available, the KSK submission event is logged into journald in a structured way. The intended use case is to trigger a user-created script.
So now the *only thing* that needs to be done is to write a script that update the DS using my registrar API, but that will probably have to wait ;).