DNSSEC con nsd y ldns
Por admin el 14 de Noviembre de 2022
DNSSEC es una extensión de seguridad sobre el sistema de nombres de dominio diseñada para evitar que el usuario reciba datos alterados al consultar una zona DNS. Queda definida en los siguientes RFCs:
Estos RFCs son de especial interés a la hora de configurar DNSSEC:
- RFC 4641: Prácticas operacionales para DNSSEC
- RFC 7583: Consideraciones para sincronizar la renovación de llaves DNSSEC
Voy a configurar DNSSEC para mi dominio que denominaré example.com en este artículo. Esta no pretende ser una guía exhaustiva sobre implementación de DNSSEC sino unas breves notas que sirvan de referencia. Me he basado en el artículo DNSSEC with NLnetLabs' LDNS and NSD.
Utilizaré la herramienta ldns-signzone que se encuentra en el paquete ldns-utils
para firmar la zona y nsd (parte del sistema base) para servirla.
Configuración de DNSSEC para un nombre de dominio
Estos son los pasos que he dado para configurar DNSSEC. Parto del dominio example.com registrado en Porkbun con su zona configurada y servida por un servidor OpenBSD con nsd y con el paquete ldns-utils para firmar la zona y al menos un servidor secundario.
- Generar llave para el dominio example.com
- Firmar y verificar la zona
-
Configurar y recargar
nsd
para la nueva zona firmada - Añadir el registro DS en el registrador
- Añadir el registro DNSKEY en el registrador
- Comprobar que funciona
Generar llave para el dominio example.com
A día de hoy el algoritmo recomendado es ECDSA Curve P-256 con SHA-256 definido en el RFC 6605, el cual corresponde al número 13 en ldns. El parámetro -k
indica que el registro DNSKEY contiene la llave KSK.
$ ldns-keygen -a13 -k example.com
Kexample.com.+013+14834
Se han creado tres archivos:
- .ds contiene el registro de recurso DS definido en la sección 5 del RFC 4034.
- .key contiene la clave pública que más tarde se podrá consultar a través del registro DNSKEY
- .private contiene la clave privada que hay que proteger bien
Firmar y verificar la zona
Para firmar la zona se especifica solamente la primera parte del nombre de los archivos generados, sin la parte de la extensión correspondiente a .ds, .key o .private. Usaré esta configuración:
- -n para usar registros NSEC3 en vez de NSEC (diferencias entre ambos)
- -u para usar el serial de la zona como segundos desde el 1 de Enero de 1970
- -o example.com para especificar el origen de la zona
$ ldns-signzone -n -u -o example.com example.com Kexample.com.+013+14834
Una vez hecho esto verifico la zona firmada:
$ ldns-verify-zone -V4 example.com.signed
Por defecto las claves expiran a los 30 días, aunque se puede especificar más duración con el parámetro -e
. Antes de que caduquen es necesario actualizar la zona incrementando el serial, firmarla de nuevo y recargarla.
Configurar y recargar nsd para la zona firmada
Si no hay ningún problema cambio la configuración de nsd.conf para especificar el archivo firmado, que quedaría algo así:
[...]
zone:
name: "example.com"
zonefile: "master/example.com.signed"
[...]
Una vez hecho el cambio recargo la configuración de nsd. En OpenBSD sería así:
$ doas rcctl reload nsd
Añadir el registro DS en el registrador
Ahora toca subir al registrador los datos del registro DS mencionado anteriormente. Los datos se encuentran en el archivo con extensión .ds
que generado anteriormente:
example.com. IN DS 14834 13 2 8b6c6df9335d3d41bedb294e125a57d1457bae532f2b854e12a9297d7994fcae
Este proceso depende del registrador y del registro. Para los dominios .com
y .org
en Porkbun funciona simplemente añadiendo el registro DS a la configuración DNSSEC:
- Key Tag: 14834
- DS Data Algorithm: 13
- Digest Type: 2
- Digest: 8b6c6df9335d3d41bedb294e125a57d1457bae532f2b854e12a9297d7994fcae
Añadir el registro DNSKEY al registrador
Para dominios .me es necesario subir tanto el registro DS como el DNSKEY de una misma vez. Los datos están en el fichero .key
(ojo, nunca la clave privada de extensión .private
).
example.com. IN DNSKEY 257 3 13 vF9wHxJYN57Lr+CCPfCHLCpuJBUCaFkBSyF/hySHnphcizIKjFrp1oXl4jA1pVwc0m9A1nPDsJugreVu/4wfGw== ;{id = 1553 (ksk), size = 256b}
Estos serían los campos para el registro DNSKEY o keyData:
- Flags: 257
- Protocol: 3
- Key Data Algorithm: 13
- Public Key (lo muestro acortado): vF9wHxJY...cizIKjFrp1oXfGw==
Comprobar que funciona
Una vez añadido el registro compruebo que el dominio resuelve:
$ dig +short +dnssec example.com
203.0.113.1
A 13 2 3600 20221212180833 20221114180833 14834 example.com. O9xZhZ8C7qLsW9jfWqpeLHeMv39XFKKCDLUffrVK3EPuWuuIBS5QqbvD p8CIsP+9RaFbEq57V6crNJYYaX7YQw==
Al hacer whois
se reflejará que el dominio usa DNSSEC:
DNSSEC: signedDelegation
DNSSEC DS Data: 14834 13 2 8B6C6DF9335D3D41BEDB294E125A57D1457BAE532F2B854E12A9297D7994FCAE
Para comprobar la configuración puedes usar dnsviz.net.
Mantenimiento de las zonas
Cada zona firmada tiene asignadas dos fechas que aparecen en el registro RRSIG:
- Una de comienzo referida como inception
- Una de vencimiento referida como expiration
El resultado de la consulta será válido si ésta se realiza en una fecha entre ambas. Para evitar problemas de resolución desde sistemas con reloj inexacto el programa ldns-signzone
por defecto establece la fecha de comienzo una hora antes de la hora actual.
Para mantener las zonas hay que incrementar el número de serie o serial de la zona sin firmar para a continuación firmarla antes de su fecha de caducidad. Este intervalo de validez es de un mes aunque se puede cambiar con el parámetro -e
.