DNSSEC. Asegurando las respuestas de nuestro dominio. La práctica (I)

Ingredientes

Para ofrecer DNSSEC en las respuestas de nuestro dominio, garantizando a los usuarios/aplicaciones la validez de éstas, necesitamos:

– Acceso al panel de control del registrador del dominio. Donde informaremos el registro DS (Delegation Signer) que indicará cual es nuestra clave (KSK) en la zona padre de nuestro dominio (normalmente .com.net.org, etc…). Aunque en los dominios .es ya hay soporte para DNSSEC, en el registrador que yo uso en la actualidad (abril 2015) no hay posibilidad de informar el DS, y por tanto no hay DNSSEC para mis .es.

– Control de tu DNS primario. Supongo que los que usen su registrador, o su empresa de hosting, para gestionar su dominio tendrán la posibilidad de usar DNSSEC. Este artículo está dirigido a aquellos que administran su servidor DNS (bajo GNU/Linux claro, y usando Bind).

Pasos a seguir

Aunque existen utilidades (dnssec-tools) que facilitan todos los pasos que seguiremos, he optado (como suelo hacer) por usar las herramientas más “básicas”, ya que mi objetivo siempre es aprender como funcionan todas las piezas y no depender de “mágia” que lo haga todo por mi. Así que lo único que necesitaremos es tener instalado Bind en nuestro servidor DNS, lo que posiblemente ya tenemos salvo que usemos otro software. En ese caso este tutorial sólo será orientativo.

Antes de nada, deberemos asegurarnos que nuestro Bind está configurado para soportar y validar DNSSEC.

Después crearemos las claves KSK y ZSK. Compuestas, respectivamente, de una clave privada que usaremos para firmar la clave ZSK y la zona, y de una clave pública que irá informada en el fichero de zona de nuestro dominio.

Posteriormente firmaremos la zona de nuestro dominio con las claves creadas y publicaremos, mediante el panel de control de nuestro registrador, el registro DS correspondiente a nuestra KSK. Ésto permitirá a otros servidores DNS validar la información proveniente de nuestros servidores DNS.

En el siguiente post veremos como comprobar que todo está correcto y nuestra zona está siendo servida con DNSSEC además de establecer un mecanismo de firmado periódico de la zona, ya que ésta sólo se firma con una validez finita (normalmente un mes).

Configuración de Bind para soportar DNSSEC

Dos son las opciones principales que controlan el soporte DNSSEC en Bind:

// dnssec-enable, indica soporte DNSSEC como servidor autoritativo
// de un dominio (en los DNS primario/secundario)
dnssec-enable yes;
// dnssec-validation, que activará la validación de respuestas DNSSEC
// como servidor recursivo (en el DNS que usan nuestras máquinas como resolver)
dnssec-validation yes;

Si bien se supone que el valor por defecto de estas opciones es “yes” desde la versión 9.5 de Bind, en versiones 9.7, como la que viene en Debian Squeeze, he tenido que añadir explicitamente dichas opciones a la sección “options” en /etc/bind/named.conf.options, junto con un “include” del fichero /etc/bind/bind.keys. Resultando en un named.conf.options como el siguiente:

options {
          // opciones que vienen de serie...
          .....
          // añadido lo siguiente:
          dnssec-enable yes;
          dnssec-validation yes;
};
// fuera de "options" también añadido:
include "/etc/bind/bind.keys";

En Debian Wheezy y posteriores no es necesario tocar nada de la configuración de Bind, funciona “out-of-the-box”.

Para comprobar que nuestro servidor DNS recursivo (el que usa nuestro portátil/servidor/… para resolver nombres) tiene soporte DNSSEC podemos hacer alguna de las siguientes pruebas:

  •  Usar dig para obtener una respuesta clara y sencilla:
$ dig +short test.dnssec-or-not.net TXT | tail -1
"No, you are not using DNSSEC"
## ^^ En este caso no tenemos soporte DNSSEC
  • Usar dig para comprobar los flags en la respuesta del DNS recursivo:
## La opción +dnssec hace que dig incluya en la query el flag
## 'do' (DNSSEC OK)
## El flag 'ad' (Authenticated Answer) debe estar presente en la respuesta
$ dig +dnssec . SOA | grep flags
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 13, ADDITIONAL: 25
##        ^^^^^^^^^ En este caso no hay soporte DNSSEC

## En el siguiente si lo hay:
$ dig +dnssec . SOA | grep flags
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 13, ADDITIONAL: 1
  •  Preguntar por el dominio www.dnssec-failed.org. Que es un dominio con una configuración DNSSEC inválida. Este es un ejemplo interesante, ya que con un DNS con soporte DNSSEC correcto, no deberíamos obtener una respuesta válida, y por tanto no ser capaces de ver la web. Mientras que si nuestro DNS no está validando correctamente, obtendremos una IP y podremos ver la web.
# Si nuestro DNS recursivo no usa (correctamente) DNSSEC:
$ host www.dnssec-failed.org
www.dnssec-failed.org has address 69.252.193.191
www.dnssec-failed.org has address 68.87.109.242

# Si nuestro DNS usa correctamente DNSSEC:
$ host www.dnssec-failed.org
Host www.dnssec-failed.org not found: 2(SERVFAIL)
  • Existen plugins/add-ons/extensiones/como-lo-quieran-llamar-este-año para los navegadores que te indican si las webs a las que llegas están “verificadas” desde el punto de vista DNSSEC. Por ejemplo DNSSEC/TLSA Validator para Firefox.

Una vez estamos seguros de que tenemos soporte DNSSEC en nuestro DNS recursivo, y habiendo activado la opción ‘dnssec-enable‘ en los servidores autoritativos de nuestros dominios si son más antiguos que la versión 9.5 de Bind, podemos continuar.

Creación de las claves de firmado

Antes de crear las claves, vamos a poner unos permisos en el directorio /etc/bind que permitan que el propio demonio firme las zonas en caso de necesidad (por actualización dinámica de la zona, o caducidad de la misma), y a crear un directorio para guardar las claves:

# chmod 2775 /etc/bind
# mkdir /etc/bind/keys
# chmod 2770 /etc/bind/keys

Como ya comenté en el post anterior, crearemos dos claves. La primera, KSK (Key Signing Key), será usada para firmar la ZSK (Zone Signing Key), permitiendo cambiar esta última de forma periódica de forma sencilla y sin realizar cambios en el registrador del dominio:

$ dnssec-keygen -K /etc/bind/keys/ -a RSASHA256 -b 4096 \
              -n ZONE -3 -f KSK inittab.net

Este comando creará un par de claves en el directorio (-K/etc/bind/keys. El nombre de los ficheros será algo como Kinittab.net.+008+51772.private o .key. Donde el fichero .private contiene la clave privada y el .key la pública. El “+008” indica el algoritmo elegido (-a RSASHA256) y el “+51772” el identificador de la clave (lo usaremos luego en el registrador). Con “-b 4096” elegimos el tamaño de la clave a generar, 4096 es una buena opción para la KSK. “-n ZONE” indica que la clave será usada para trabajar con zonas DNSSEC, “-3” que usaremos NSEC3 (hablaré de ello más adelante) y por último “-f KSK” indica el tipo de clave. Lo único que podríamos querer variar:

  • Añadir “-r /dev/urandom” para que use este dispositivo para la obtención de números pseudo-aleatorios, en vez de /dev/random. Esto hará que la generación de la clave sea mucho más rápida, pero más débil desde el punto de vista criptográfico (mucho que explicar para un sólo post). Para pruebas podéis usar /dev/urandom, para algo “serio” mejor no usarlo.
  • Cambiar el algoritmo “-a“. En la página de manual de dnssec-keygen (8), tenéis las posibilidades. En la wikipedia también. Mi consejo es que no vayáis a lo último, porque podría suceder que algún servidor DNS no tenga implementado el algoritmo (por ejemplo yo elegí ECDSAP384SHA384 para pruebas y preparar este post, en abril de 2015, y me he dado con versiones anteriores de Bind que no lo digieren. Fail!). Mejor evitar MD5 y SHA1.
  • Cambiar el tamaño de la clave “-b“. En la actualizad (2015) 4096 bits para la KSK y 2048 bits para la ZSK son  tamaños recomendables.

Si nos fijamos en el fichero .key, veremos una entrada de zona DNS (DNSKEY en este caso) con la siguiente información:

inittab.net. IN DNSKEY 257 3 8 AwEA......
# 257 indica que se trata de una KSK
# 3 es el protocolo, y siempre tiene ese valor [RFC4034]
# 8 es el algoritmo elegido [lista en la wikipedia]. En este caso RSA/SHA-256
# AwEA.....Y el resto será la clave pública
# La única diferencia con el .key de la ZSK es que el primer campo tendrá
# un valor de 256 (en vez de 257)

Después crearemos la ZSK, con un comando prácticamente igual al anterior, en este caso con un tamaño de clave algo menor (2048 bits) y sin “marcar” como KSK:

$ dnssec-keygen -K /etc/bind/keys/ -a RSASHA256 -b 2048 \
              -n ZONE inittab.net

Una vez más obtendremos dos ficheros (un .private y un .key) del tipo Kinittab.net.+008+50946. Donde, 008 es el algoritmo y 50946 el identificador/etiqueta de la clave.

Firmando el fichero de zona

Ahora ya podemos firmar nuestra zona DNS. En mi caso el fichero se llama inittab.net y se encuentra en /etc/bind. Ese fichero es el que seguiré modificando cuando quiera hacer cambios en mi zona, sólo que después de los cambios habrá que volver a firmar y recargar la zona.

$ dnssec-signzone -d /etc/bind/ -K /etc/bind/keys/ -N "increment" -S \
   -3 $( dd if=/dev/random bs=16 count=1 2>/dev/null | hexdump -e \"%08x\" ) \
   -o inittab.net /etc/bind/inittab.net

El resultado de este comando será un fichero /etc/bind/inittab.net.signed. Veamos el por qué de las opciones que he usado:

  • -d directorio de trabajo, donde dejar la zona firmada
  • -K directorio con las claves generadas anteriormente
  • -N “increment”, esta opción indica que debe aumentarse el número de serie de la zona además de firmarla. Es decir, el fichero .signed tendrá un número de serie (en el SOA) mayor al del fichero original. Yo no soy amigo de esta opción. Como hay que seguir editando el fichero original para realizar los cambios en la zona, es allí donde aumento el número de serie. Así que os podéis ahorrar esta opción.
  • -S, mi opción favorita. Se trata de “Smart“, es decir, que él busca las claves (en el directorio indicado), sabe (por el 257/256 que vimos antes) cual es la KSK y la ZSK, las usa correctamente (firmando los RR tipo DNSKEY con la KSK y el resto con la ZSK), las incluye en el nuevo fichero generado, limpia y abrillanta. En el caso de que las claves se generen con periodos de validez (eso para otro post), se encargaría de gestionar la rotación por caducidad de las mismas. ¡Una maravilla, oiga!
  • -3 SALT. Genera los registros NSEC3 de los que hablaré en el próximo post. Éstos son necesarios para que no se pueda enumerar por completo la zona. Como están basados en un hash, la “salt” varía el valor del hash para que no pueda inferirse su valor original, por ejemplo con diccionarios. En este comando uso /dev/random y hexdump para generar una “salt” completamente aleatoria. Si no queremos usar “salt“, podemos especificar un guión (-3 –) o incluso poner una fija (en hexadecimal, 32 carácteres…)
  • -o inittab.net. Indica el ORIGIN de la zona, es decir el dominio (para que no lo tenga que deducir del nombre del fichero de zona, aunque en este ejemplo sea obvio). Así que se trata de una opción importante.
  • /etc/bind/inittab.net. El fichero original de la zona. El destino tendrá el mismo nombre, con la extensión .signed (duh!).

Es importante notar que la firma de los registros tiene caducidad. Por defecto 30 días desde su creación. Este dato es vital, ya que pasados 30 días nuestro dominio dejará de validar correctamente y los DNS que tengan soporte para DNSSEC (hoy casi todos) dejarán de aceptar como válidas nuestras respuestas DNS, es decir, desapareceremos de Internet… LOL! En el próximo post (ahí, creando tensión) explicaré alguna de las posibilidades para mantener nuestras zonas firmadas al día. Si queremos modificar el periodo de validez de la firma, podemos usar la opción -e. Por ejemplo, el valor por defecto es: -e now+30D (30 Días desde ahora). Valga, por ahora, decir que basta ejecutar el mismo comando de firma de zona otra vez para generar las firmas (con su validez de 30 días) una vez más.

Una vez tenemos la zona firmada, lo único que nos queda en el servidor es servir la zona firmada en vez de la original. Es decir, en la configuración del DNS cambiar:

zone "inittab.net" {
 type master;
 file "/etc/bind/inittab.net";
 .....
};

Por:

zone "inittab.net" {
 type master;
 file "/etc/bind/inittab.net.signed";
 .....
};

Y recargarla con: rndc reload inittab.net

Informando la KSK en el registrador

Una vez nuestro servidor DNS está sirviendo la zona firmada, nos queda el último paso. Añadir el “enlace” entre la zona padre (.net en este ejemplo) y la nuestra. Es decir, informar (en el registrador) de cual es nuestra KSK, para que las respuestas de nuestros DNS puedan ser validadas correctamente.

Para ello iremos al panel de control de nuestro dominio y rellenaremos los datos del registro DS (Delegation Signer). En mi caso mi registrador es Joker.com y el formulario correspondiente tiene esta pinta:

En la entrada DS pondremos el hash de nuestra KSK

En la entrada DS pondremos los hash de nuestra KSK

¿De dónde sacamos la información para el registro DS? Si nos fijamos, después del comando de firmado que vimos anteriormente (dnssec-signzone), en nuestro directorio /etc/bind, tendremos un fichero llamado dsset-inittab.net, cuyo contenido es:

inittab.net. IN DS 51772 8 1 6397....5B
inittab.net. IN DS 51772 8 2 581E....D8....

Donde 51772 es el identificador/etiqueta de la clave (campo keytag), el 8 el el algoritmo (alg) correspondiente a la clave (recordad que en este ejemplo era RSA/SHA-256) y el 1 y 2 las funciones hash usadas (digest type) para crear cada resumen de la clave (digest), que es el chorro hexadecimal del final. Es decir, para una misma clave (KSK en este caso) se generan dos registros DS, con diferentes funciones de resumen (1 es SHA-1 y 2 es SHA-256). En el registrador podemos informar sólo una, aunque lo ideal es tener las dos. Si por algún motivo el fichero dsset-dominio.foo no se ha creado, podemos hacerlo partiendo del componente público de la clave KSK con el comando dnssec-dsfromkey:

$ ddnssec-dsfromkey Kinittab.net.+008+51772.key

Espero que, a estas alturas de la (larga) lectura, tengas tu dominio funcionando correctamente con DNSSEC. En el próximo post veremos como comprobarlo, hablaré de NSEC3 y de como automatizar el firmado de las zonas antes de que las firmas caduquen.

$ exit

2 pensamientos en “DNSSEC. Asegurando las respuestas de nuestro dominio. La práctica (I)

  1. javier

    que tal amigo excelente post precisamentando estoy tratando de implemente algo similar, pero estoy algo atorado tengo N numero de zonas, crees que sea posible firmar estas N numero de zonas con las misma llaves KSK y ZSK. o bien de deberan crear las llaves KSK y ZSK para cada N numero de zonas tanto directas como inversas para poder firmarlas? alguna sugerencia amigo saludos

    Responder

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *