217 lines
12 KiB
Markdown
217 lines
12 KiB
Markdown
Title: Migrating my DNS server from Bind9 to Knot DNS
|
|
Date: 2021-01-08
|
|
Tags: DNS, DNSSEC, Knot, Ops
|
|
Authors: BlackSponge
|
|
Lang: en
|
|
Category: Tutorials
|
|
Summary: Knot DNS simple configuration break down and migration steps from Bind9.
|
|
Header:
|
|
|
|
|
|
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](https://www.digitalocean.com/community/tutorials/how-to-setup-dnssec-on-an-authoritative-bind-dns-server-2), 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](https://www.powerdns.com/) 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](knot-dns.cz/) to host [their zones](https://mutu-ns.net.eu.org/about/) and being some curious I decided to have a look. So Knot-DNS is developped and used by the [Czech NIC](http://nic.cz/) and, compared to the other softwares mentionned, is rather recent, [Bind](https://en.wikipedia.org/wiki/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.
|
|
|
|
## Knot configuration
|
|
|
|
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.
|
|
|
|
```text
|
|
/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.
|
|
|
|
```yaml
|
|
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](https://en.wikipedia.org/wiki/Domain_Name_System_Security_Extensions) 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](https://appsecco.com/books/subdomain-enumeration/active_techniques/zone_walking.html). 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.
|
|
|
|
```yaml
|
|
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*](https://www.knot-dns.cz/docs/3.0/html/configuration.html#zone-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, `default` and `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](https://www.knot-dns.cz/docs/3.0/html/operation.html#journal-behaviour) 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](https://en.wikipedia.org/wiki/Dynamic_DNS) but I am not currently using that). As stated in [the documentation](https://www.knot-dns.cz/docs/3.0/html/operation.html#example-1):
|
|
|
|
> Some users dislike that the server overwrites their prettily prepared zone file.
|
|
|
|
I am one of those users.
|
|
|
|
Finally `difference-no-serial` means that the serial is automatically updated when reloading the zone file content using the `dateserial` format (`YYYYMMDDNN`).
|
|
|
|
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.
|
|
```yaml
|
|
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](https://www.knot-dns.cz/docs/3.0/html/reference.html#key-section) 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 `primary_acl`.
|
|
|
|
```yaml
|
|
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.
|
|
|
|
```yaml
|
|
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`](https://www.knot-dns.cz/docs/3.0/html/man_knotc.html) tool:
|
|
|
|
```
|
|
$ knotc conf-check
|
|
Configuration is valid
|
|
```
|
|
|
|
## Importing the keys
|
|
The tool to manage keys is [`keymgr`](https://www.knot-dns.cz/docs/3.0/html/man_keymgr.html), 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 `/var/lib/knot/keys/keys/` directory.
|
|
|
|
```
|
|
$ 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.
|
|
|
|
## Next steps
|
|
|
|
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](https://www.knot-dns.cz/docs/3.0/html/operation.html#automatic-ksk-and-zsk-rollovers-example) 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](https://api.ovh.com/console/#/domain/%7BserviceName%7D/dsRecord#POST), but that will probably have to wait ;).
|
|
|
|
---
|
|
|
|
### References
|
|
* [Knot configuration reference](https://www.knot-dns.cz/docs/3.0/html/reference.html)
|
|
* [Knot operation guide](https://www.knot-dns.cz/docs/3.0/html/operation.html)
|
|
* [Knot configuration guide](https://www.knot-dns.cz/docs/3.0/html/configuration.html)
|
|
* [Source code and issue tracker](https://gitlab.nic.cz/knot/knot-dns/)
|
|
* [Knot DNS for Bind users](https://www.knot-dns.cz/docs/3.0/html/migration.html#knot-dns-for-bind-users)
|