"Key Rollover" y reconfiguración de mis DNSSEC para eliminar SHA-1

Mi configuración actual DNSSEC utiliza SHA-1, que es un algoritmo de hash al que se le han ido encontrando vulnerabilidades. Lo he mantenido porque un ataque a mi DNS parece poco rentable y porque lo consideraba el más compatible [1], pero la puntilla ha sido un nuevo ataque en enero de 2020. La situación es ya insostenible y mantener SHA-1 resulta injustificable.

[1] (1, 2)

Si durante la verificación DNSSEC un resolver encuentra algoritmos desconocidos, simplemente se comportará como si ese registro DNS no existiese.

En particular, si el registro de anclaje DS que activa DNSSEC en un subdominio no es reconocido, el resolver considerará que el registro no existe y, por tanto, el dominio no tiene DNSSEC.

Incluyo algunos enlaces relevantes en la bibliografía del final.

Las claves públicas DNSSEC actuales de mi dominio jcea.es son:

jcea@jcea:~$ dig DNSKEY jcea.es

; <<>> DiG 9.16.1-Ubuntu <<>> DNSKEY jcea.es
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 30207
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 65494
;; QUESTION SECTION:
;jcea.es.                       IN      DNSKEY

;; ANSWER SECTION:
jcea.es.                86400   IN      DNSKEY  256 3 7 AwEAAdvqYNIq+kT+BeN+EZLr2oygteIWy1McKv9pt3PEXnSmoIUT+puP p6fVbqf5bbPQxp7FD6k2d5U8VpF7c1clcvlqhihgZK59jF1sWe2vM51k QW+ZeyAY5hcWF/DRij7jUa3QcWBJLnOSseV8VEOFfD53FSiIdGpDdVbf OH2Mwi1l
jcea.es.                86400   IN      DNSKEY  257 3 7 AwEAAbBRJkUetAndznEpQm8SI1UFxwy+/ZWyj/CK0MT13Cjx0Yd/Kmah WfFC9G9cpJU3aPw/5w8TOC0Cpa9BluYfBboKu60i1OXlgDvQevevk8Av foqLm213nttALCFfeCTd5iBxJohNQUjreopxcV+FgCG1TKCZQqbDUh5L DaCMDeeHPZJKzIp+Jysif9etSwLnsShUem75X9wv0DLc6i6fdKDsz61j vitl420eDET98LCxRraIgPPjW4yYDoUIEeagtd5VSbgbDXLKVK0nAHlv G4p19cTtZz+Ct928l072FIZ4w3XIDYB7TkWZ5AU/+pXIHfglXwurLtUo gDuHWD2mcgs=

;; Query time: 96 msec
;; SERVER: 127.0.0.53#53(127.0.0.53)
;; WHEN: jue jul 16 15:41:19 CEST 2020
;; MSG SIZE  rcvd: 460

Ambas claves, la KSK y la ZSK, utilizan el algoritmo 7 que, según el RFC8624, es RSASHA1-NSEC3-SHA1. Está marcado como NOT RECOMMENDED. Toca cambiar.

¿Cambiar a qué? Las dos opciones evidentes en esa tabla son RSASHA256 y ECDSAP256SHA256. La segunda es técnicamente mejor, más ligera de cálculo y con respuestas DNS más cortas. Pero es un algoritmo moderno y no me queda claro qué soporte tendrá entre los resolvers DNS que hagan verificación DNSSEC [1]. Revisando qué algoritmo utiliza el servicio DNS español, vemos que es RSASHA256:

jcea@jcea:~$ dig DNSKEY es.

; <<>> DiG 9.16.1-Ubuntu <<>> DNSKEY es.
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 58859
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 65494
;; QUESTION SECTION:
;es.                            IN      DNSKEY

;; ANSWER SECTION:
es.                     5986    IN      DNSKEY  257 3 8 [...]
es.                     5986    IN      DNSKEY  256 3 8 [...]

;; Query time: 0 msec
;; SERVER: 127.0.0.53#53(127.0.0.53)
;; WHEN: jue jul 16 17:53:14 CEST 2020
;; MSG SIZE  rcvd: 455

El servicio DNS español utiliza el algoritmo 8, RSASHA256. Hagamos lo mismo.

Lo más importante para no romper el DNSSEC durante un Key Rollover es entender el ciclo de vida de las claves:

+---+---------+---+---...
| 1 |    2    | 3 | 4    CLAVE VIEJA
+---+----+---++---+--+---+---...
         | 1 |   2   | 3 | 4    CLAVE NUEVA
         +---+-------+---+---...

1: Publicación de la clave en el DNS.
2: Activa. La clave está firmando.
3: Inactiva. La clave ya no firma, pero sigue disponible en el
   DNS.
4. Clave retirada. Ya no está accesible.

Los principios básicos son los siguientes:

  1. En todo momento debemos tener al menos una clave firmando DNS. Es decir, en fase dos. Si hay varias claves en fase dos, su solapamiento debe ser corto, por una pura cuestión de eficiencia y tamaño de las peticiones DNS.

  2. Debemos seguir firmando con la clave antigua hasta que los resolvers DNS puedan tener la oportunidad de detectar que hay una clave DNSSEC nueva. Es decir, cuando la clave nueva empieza a firmar, la clave antigua debe seguir firmando mientras no haya caducado el TTL máximo de los registros DNSKEY.

    En mi caso, como puede verse más arriba, mi TTL para los registros DNSKEY es de 86400 segundos. Es decir, 24 horas.

    Esto es así para asegurarnos de que la versión en la caché de los resolvers ha caducado, hará nueva una consulta DNS y recibirá la versión actualizada.

Romper cualquiera de estas reglas supone romper la verificación DNSSEC con consecuencias potencialmente catastróficas, porque los resolvers DNS rechazarán nuestras respuestas DNS y, por tanto, quedaríamos inaccesibles.

Voy a hacer Key Rollover de las claves KSK y ZSK simultáneamente.

Advertencia

A partir de aquí suponemos que estamos usando una versión reciente de BIND. Si usas otro software, tendrás que hacer las adaptaciones necesarias.

El estado actual es el siguiente:

[root@DNS /home/named/primarios]# dnssec-verify -I raw -o jcea.es db.jcea.es.signed
Loading zone 'jcea.es' from file 'db.jcea.es.signed'
Verifying the zone using the following algorithms: NSEC3RSASHA1.
Zone fully signed:
Algorithm: NSEC3RSASHA1: KSKs: 1 active, 0 stand-by, 0 revoked
                         ZSKs: 1 active, 0 stand-by, 0 revoked

Vamos a generar claves nuevas con los algoritmos apropiados. Las publicamos y empezamos a firmar con ellas inmediatamente. A partir de ese momento los registros DNS irán firmados por dos claves, la antigua y la nueva. Obsérvese que la clave KSK medirá 2048 bits y la ZSK medirá 1024 bits.

[root@DNS /home/named/keys]# dnssec-keygen -a RSASHA256 -3 -b 2048 -f KSK jcea.es
Generating key pair.............................+++++ ....+++++
Kjcea.es.+008+42347
[root@DNS /home/named/keys]# dnssec-keygen -a RSASHA256 -3 -b 1024 jcea.es
Generating key pair......................................................................+++++ ............+++++
Kjcea.es.+008+63570
[root@DNS /home/named/keys]# chgrp named Kjcea.es.+008+42347.* Kjcea.es.+008+63570.*

Como ahora vamos a utilizar una clave KSK nueva, debemos notificar a nuestro dominio DNS padre que debe cambiar el registro DS. Comprobemos el TTL de esos registros DNS para ver cuánto tiempo pueden permanecer en la caché de los resolvers:

[root@DNS /home/named/primarios]# dig @g.nic.es DS jcea.es

; <<>> DiG 9.16.1-Ubuntu <<>> @g.nic.es DS jcea.es
; (2 servers found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 56883
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: 52640d575cfe94d4072bc21d62a22360b4c6bbc3cca21afb (good)
;; QUESTION SECTION:
;jcea.es.                       IN      DS

;; ANSWER SECTION:
jcea.es.                86400   IN      DS      129 7 2 C1DEDF058EAF620160C31E8C12A23B2AC1D0FB583513106F15FBFDA0 7C881021

;; Query time: 11 msec
;; SERVER: 2001:500:14:7001:ad::1#53(2001:500:14:7001:ad::1)
;; WHEN: jue. jul. 16 18:44:16 CEST 2020
;; MSG SIZE  rcvd: 112

Vemos que el tiempo de propagación es de 24 horas. Es decir, debemos seguir firmando con la clave antigua durante al menos 24 horas.

Configuramos la clave KSK vieja para que siga firmando durante 36 horas (pasar a estado inactivo) y, de paso, le indicamos ya en qué momento debe pasar a fase cuatro (retirarla del DNS).

También configuramos la clave ZSK vieja de forma similar, pero le indicamos que pase a estado inactivo en 24 horas para que BIND gestione la transición. Son 24 horas porque es el TTL de los registros DNSKEY y queremos que un resolver que haya capturado el DNSKEY de jcea.es justo antes de añadir la clave nueva pueda validar las firmas DNSSEC:

[root@DNS /home/named/keys]# dnssec-settime -I +36h -D +72h Kjcea.es.+007+00129.key
Kjcea.es.+007+00129.key
Kjcea.es.+007+00129.private

[root@DNS /home/named/keys]# dnssec-settime -I +24h -D +72h Kjcea.es.+007+00722.key
./Kjcea.es.+007+00722.key
./Kjcea.es.+007+00722.private

Mi BIND revisa las claves cada hora, pero podemos forzar una revisión ahora mismo:

[root@DNS /home/named/primarios]# rndc loadkeys jcea.es
[.. esperamos cinco segundos ..]
[root@DNS /home/named/primarios]# rndc sync jcea.es; dnssec-verify -I raw -o jcea.es db.jcea.es.signed
Loading zone 'jcea.es' from file 'db.jcea.es.signed'
Verifying the zone using the following algorithms: NSEC3RSASHA1 RSASHA256.
Zone fully signed:
Algorithm: NSEC3RSASHA1: KSKs: 1 active, 0 stand-by, 0 revoked
                         ZSKs: 1 active, 0 stand-by, 0 revoked
Algorithm: RSASHA256: KSKs: 1 active, 0 stand-by, 0 revoked
                      ZSKs: 1 active, 0 stand-by, 0 revoked

Aquí vemos que el DNS jcea.es está firmado con dos algoritmos distintos. Dentro de 24 horas la cosa cambiará, cuando la clave ZSK vieja quede inactiva y deje de firmar. A medida que las firmas realizadas con dicha clave vayan caducando, en los pŕoximos 30 días, ya no se regenerarán. Solo se refrescarán las firmas que corresponden a la nueva clave ZSK.

Los detalles del proceso de Key Rollover en BIND están explicados con detalle en Automatic DNSSEC Zone Signing Key rollover explained. La única diferencia respecto al proceso que he seguido yo es que en el documento se indica que la nueva ZSK debe publicarse en el DNS antes de activarla (con una antelación de al menos el TTL de los registros DNSKEY), empezar a firmar registros y desactivar la ZSK antigua. Yo solapo la actividad de firma de las dos claves ZSK durante el TTL de los registros DNSKEY. Es el proceso de doble firma indicado en el RFC 7583: DNSSEC Key Rollover Timing Considerations.