Ir al contenido principal

Configurar DANE/TLSA con Postfix, Bind y Let's Encrypt

Por CaptainDNS
Publicado el 22 de febrero de 2026

Esquema de arquitectura mostrando Postfix, Bind9 y Let's Encrypt conectados mediante DANE/TLSA
TL;DR
  • DANE/TLSA vincula el certificado TLS de tu servidor de correo a un registro DNS firmado por DNSSEC, eliminando la dependencia de las autoridades de certificación
  • La combinación recomendada es 3 1 1 (DANE-EE, SPKI, SHA-256): el hash TLSA sobrevive a las renovaciones de Let's Encrypt mientras la clave privada no cambie
  • Postfix soporta nativamente la verificación DANE saliente con smtp_dns_support_level = dnssec y smtp_tls_security_level = dane
  • La automatización se basa en un deploy-hook de Certbot que regenera el hash TLSA y recarga la zona Bind9 en cada renovación
  • Verifica tu despliegue con dig TLSA, openssl s_client y el inspector DANE/TLSA CaptainDNS

¿Gestionas un servidor de correo Postfix y quieres proteger tus conexiones SMTP contra ataques de tipo downgrade o man-in-the-middle? DANE (DNS-based Authentication of Named Entities) es la respuesta. Al publicar un registro TLSA en tu zona DNS firmada por DNSSEC, indicas a los servidores remotos qué certificado TLS debe presentar tu servidor. Sin intermediarios, sin autoridades de certificación en las que confiar.

El reto con Let's Encrypt es la renovación automática cada 90 días. Si el hash TLSA ya no coincide con el certificado, los servidores que verifican DANE rechazarán la conexión. Este tutorial cubre la configuración completa del stack Postfix + Bind9 + Let's Encrypt + DANE, incluyendo la automatización de la renovación para evitar cualquier interrupción.

Esta guía está dirigida a administradores de sistemas Linux que gestionan un servidor de correo self-hosted. Presupone un conocimiento básico de Postfix, DNS y de la línea de comandos. Para los fundamentos de DANE y TLSA, consulta nuestra guía completa DANE/TLSA (primer artículo de esta serie).

Requisitos previos

Antes de empezar, verifica que cuentas con:

ComponenteVersión mínimaVerificación
Debian/Ubuntu12+ / 22.04+cat /etc/os-release
Postfix3.4+ (soporte DANE nativo)postconf mail_version
Bind99.18+ (DNSSEC inline-signing)named -v
Certbot2.0+certbot --version
DNSSEC activoZona firmada + DS en el registrardig +dnssec captaindns.com SOA

Si DNSSEC aún no está activo en tu zona, es el paso previo obligatorio. Bind9 9.18+ soporta inline-signing, lo que simplifica la gestión. Actívalo antes de continuar.

Puertos y acceso de red

Postfix utiliza el puerto 25 (SMTP) y opcionalmente el 587 (submission). Let's Encrypt necesita el puerto 80 o 443 para el challenge HTTP-01 (o un challenge DNS-01 si el puerto 80 no está disponible en el servidor de correo). Asegúrate de que estos puertos estén abiertos en tu cortafuegos.

Arquitectura del stack Postfix, Bind9 y Let's Encrypt con DANE/TLSA

Configurar DNSSEC con Bind9

Si tu zona ya está firmada por DNSSEC, pasa a la siguiente sección. Si no, aquí tienes la configuración mínima con Bind9 e inline-signing.

Activar inline-signing

En tu archivo de configuración de zona (/etc/bind/named.conf.local o equivalente):

zone "captaindns.com" {
    type primary;
    file "/var/lib/bind/captaindns.com.zone";
    dnssec-policy default;
    inline-signing yes;
    key-directory "/var/lib/bind/keys";
};

La directiva dnssec-policy default genera y gestiona automáticamente las claves ZSK y KSK. El inline-signing firma la zona sobre la marcha sin modificar el archivo fuente.

Publicar el DS en el registrar

Tras la primera carga de la zona, Bind9 genera las claves. Recupera el registro DS:

# Listar las claves generadas
ls /var/lib/bind/keys/

# Extraer el registro DS (adaptar el nombre del archivo KSK)
dnssec-dsfromkey /var/lib/bind/keys/Kcaptaindns.com.+013+xxxxx.key

Transmite el registro DS a tu registrar (interfaz web o API). La propagación tarda de unos minutos a 48 horas dependiendo del registrar.

Verificar la cadena DNSSEC

dig +dnssec +short captaindns.com SOA
# Debe devolver el SOA con el flag "ad" (Authenticated Data)

dig +dnssec captaindns.com DNSKEY
# Debe devolver las DNSKEY con las firmas RRSIG

Generar el certificado Let's Encrypt

Obtener el certificado

# Instalación de Certbot (si no está instalado)
apt install certbot

# Obtener un certificado para el hostname del servidor de correo
certbot certonly --standalone -d mail.captaindns.com

Si el puerto 80 ya está ocupado por otro servicio, usa el plugin webroot o el challenge DNS-01:

# Alternativa con webroot (si Apache/Nginx se ejecuta en el servidor)
certbot certonly --webroot -w /var/www/html -d mail.captaindns.com

# Alternativa con challenge DNS (si el puerto 80 no está disponible)
certbot certonly --manual --preferred-challenges dns -d mail.captaindns.com

Configurar Postfix para usar el certificado

Edita /etc/postfix/main.cf:

# Certificado TLS (recepción - smtpd)
smtpd_tls_cert_file = /etc/letsencrypt/live/mail.captaindns.com/fullchain.pem
smtpd_tls_key_file = /etc/letsencrypt/live/mail.captaindns.com/privkey.pem
smtpd_tls_security_level = may
smtpd_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1

# Verificación DANE saliente (smtp)
smtp_dns_support_level = dnssec
smtp_tls_security_level = dane
smtp_tls_loglevel = 1

Los dos bloques cumplen funciones distintas: smtpd_tls_* configura el TLS para las conexiones entrantes (tu servidor presenta su certificado), mientras que smtp_tls_* configura el TLS para las conexiones salientes (Postfix verifica el TLSA del destinatario).

Recarga Postfix:

postfix reload

Crear el registro TLSA

Elegir los parámetros TLSA

La combinación recomendada por la RFC 7672 para SMTP es 3 1 1:

CampoValorSignificado
Usage3 (DANE-EE)Verificación directa del certificado del servidor
Selector1 (SPKI)Hash de la clave pública (no del certificado entero)
Matching type1 (SHA-256)Hash SHA-256

La ventaja del selector SPKI (1): el hash no cambia cuando renuevas el certificado Let's Encrypt mientras la clave privada siga siendo la misma. Esto es esencial para evitar tener que actualizar el TLSA en cada renovación.

Generar el hash TLSA

# Extraer el hash SPKI SHA-256 del certificado
openssl x509 -in /etc/letsencrypt/live/mail.captaindns.com/cert.pem \
  -pubkey -noout | \
  openssl pkey -pubin -outform DER | \
  openssl dgst -sha256 -binary | \
  xxd -p -c 64

El resultado es una cadena hexadecimal de 64 caracteres, por ejemplo:

a1b2c3d4e5f67890a1b2c3d4e5f67890a1b2c3d4e5f67890a1b2c3d4e5f67890

También puedes usar el generador DANE/TLSA CaptainDNS para generar el registro sin necesidad de comandos.

Añadir el TLSA en la zona Bind9

El nombre del registro TLSA sigue el formato _port._protocol.hostname. Para el puerto 25 (SMTP):

_25._tcp.mail.captaindns.com. IN TLSA 3 1 1 a1b2c3d4e5f67890a1b2c3d4e5f67890a1b2c3d4e5f67890a1b2c3d4e5f67890

Añade esta línea a tu archivo de zona, incrementa el serial del SOA y recarga:

# Recargar la zona (Bind9 firma automáticamente con inline-signing)
rndc reload captaindns.com

Verificar la publicación

# Verificar que el TLSA está publicado y firmado
dig +dnssec _25._tcp.mail.captaindns.com TLSA

# Resultado esperado: el TLSA con las RRSIG

Automatizar la renovación

Esta es la parte crítica. Let's Encrypt renueva el certificado cada 90 días. Si usas DANE-EE con SPKI (3 1 1), el hash no cambia mientras Certbot reutilice la misma clave privada. Pero hay que asegurarse y prever el caso en que la clave cambie.

Estrategia de conservación de la clave

Por defecto, Certbot genera una nueva clave en cada renovación. Para conservar la misma clave (y por tanto el mismo hash TLSA), añade la opción --reuse-key:

# Forzar la reutilización de la clave privada
certbot certonly --standalone -d mail.captaindns.com --reuse-key

O añade en /etc/letsencrypt/renewal/mail.captaindns.com.conf:

[renewalparams]
reuse_key = True

Deploy-hook para la actualización automática

Incluso con --reuse-key, es prudente implementar un deploy-hook que verifique el hash y actualice el TLSA si es necesario. Crea el script /etc/letsencrypt/renewal-hooks/deploy/update-tlsa.sh:

#!/bin/bash
# Deploy-hook Certbot: actualización TLSA si el hash SPKI cambia

DOMAIN="mail.captaindns.com"
ZONE="captaindns.com"
ZONE_FILE="/var/lib/bind/captaindns.com.zone"
CERT="/etc/letsencrypt/live/$DOMAIN/cert.pem"

# Calcular el nuevo hash SPKI SHA-256
NEW_HASH=$(openssl x509 -in "$CERT" -pubkey -noout | \
  openssl pkey -pubin -outform DER | \
  openssl dgst -sha256 -binary | \
  xxd -p -c 64)

# Recuperar el hash actual del DNS
CURRENT_HASH=$(dig +short _25._tcp.$DOMAIN TLSA | awk '{print $4}')

if [ "$NEW_HASH" != "$CURRENT_HASH" ]; then
  echo "TLSA hash changed, updating zone..."

  # Reemplazar el hash en el archivo de zona
  sed -i "s/\(IN TLSA 3 1 1 \)[a-f0-9]\{64\}/\1$NEW_HASH/" "$ZONE_FILE"

  # Incrementar el serial (formato YYYYMMDDNN)
  CURRENT_SERIAL=$(grep -oP '\d{10}' "$ZONE_FILE" | head -1)
  NEW_SERIAL=$((CURRENT_SERIAL + 1))
  sed -i "s/$CURRENT_SERIAL/$NEW_SERIAL/" "$ZONE_FILE"

  # Recargar la zona
  rndc reload "$ZONE"

  echo "TLSA updated: $NEW_HASH"
else
  echo "TLSA hash unchanged, no update needed."
fi

# Recargar Postfix para usar el nuevo certificado
postfix reload

Haz el script ejecutable:

chmod +x /etc/letsencrypt/renewal-hooks/deploy/update-tlsa.sh

Probar la renovación

# Simular una renovación (dry-run)
certbot renew --dry-run

# Forzar una renovación real (para probar el hook)
certbot renew --force-renewal

Flujo de renovación automática: Certbot renueva el certificado, el deploy-hook verifica el hash SPKI y actualiza el TLSA en Bind9 si es necesario

Estrategia de rollover SPKI (cambio de clave)

Si necesitas regenerar la clave privada (compromiso, migración), publica el nuevo TLSA antes de desplegar el nuevo certificado. La RFC 7671 recomienda un periodo de doble publicación:

  1. Generar la nueva clave y calcular su hash SPKI
  2. Publicar los dos TLSA en la zona (antiguo + nuevo)
  3. Esperar la propagación DNS (2x TTL como mínimo)
  4. Desplegar el nuevo certificado
  5. Retirar el TLSA antiguo tras la propagación
; Doble TLSA durante la transición
_25._tcp.mail.captaindns.com. IN TLSA 3 1 1 <hash-antiguo>
_25._tcp.mail.captaindns.com. IN TLSA 3 1 1 <hash-nuevo>

Verificar la configuración

Verificación DNS

# Verificar el TLSA
dig +short _25._tcp.mail.captaindns.com TLSA
# Esperado: 3 1 1 <hash-64-chars>

# Verificar DNSSEC
dig +dnssec _25._tcp.mail.captaindns.com TLSA | grep -c "RRSIG"
# Esperado: >= 1

Verificación TLS

# Probar la conexión TLS con verificación TLSA
openssl s_client -connect mail.captaindns.com:25 -starttls smtp \
  -dane_tlsa_domain mail.captaindns.com \
  -dane_tlsa_rrdata "3 1 1 $(dig +short _25._tcp.mail.captaindns.com TLSA | awk '{print $4}')"

El resultado debe mostrar Verification: OK y DANE TLSA 3 1 1 matched EE certificate.

Verificación del Postfix saliente

Verifica que Postfix comprueba DANE para los correos salientes:

# Enviar un correo de prueba y verificar los logs
echo "Test DANE" | mail -s "DANE test" test@gmail.com
grep "Verified TLS connection" /var/log/mail.log | tail -5

Los logs deben mencionar dane en el nivel de seguridad.

Verificación en línea

Usa el verificador de sintaxis DANE/TLSA CaptainDNS para validar la sintaxis de tu registro, y luego el inspector DANE/TLSA para una verificación completa incluyendo la cadena DNSSEC.

Plan de acción recomendado

Despliegue DANE completo en un servidor de correo self-hosted en 6 pasos
  1. Configurar dnssec-policy default e inline-signing yes en la zona Bind9. Publicar el registro DS en el registrar. Verificar la cadena de confianza con dig +dnssec.

  2. Ejecutar certbot certonly --standalone -d mail.captaindns.com --reuse-key para obtener el certificado con conservación de la clave privada.

  3. Editar main.cf con las rutas del certificado (smtpd_tls_*), activar la verificación DANE saliente (smtp_dns_support_level = dnssec, smtp_tls_security_level = dane).

  4. Generar el hash SPKI SHA-256 con openssl, añadir el registro _25._tcp.mail.captaindns.com. IN TLSA 3 1 1 &lt;hash&gt; en la zona, recargar con rndc reload.

  5. Crear el deploy-hook /etc/letsencrypt/renewal-hooks/deploy/update-tlsa.sh que compara los hash SPKI y actualiza el TLSA si es necesario. Probar con certbot renew --force-renewal.

  6. Validar con dig TLSA, openssl s_client -dane_tlsa_domain, los logs de Postfix y el inspector DANE/TLSA CaptainDNS.

FAQ

¿Cómo generar un registro TLSA para Let's Encrypt?

Usa el comando openssl x509 -in cert.pem -pubkey -noout | openssl pkey -pubin -outform DER | openssl dgst -sha256 -binary | xxd -p -c 64 para extraer el hash SPKI SHA-256. El resultado de 64 caracteres hexadecimales forma el dato del TLSA con los parámetros 3 1 1.

¿Hay que actualizar el TLSA en cada renovación de Let's Encrypt?

No, si usas --reuse-key con Certbot y la combinación DANE-EE/SPKI (3 1 1). El hash SPKI depende de la clave pública, no del certificado. Mientras la clave privada siga siendo la misma, el hash no cambia. Implementa un deploy-hook de verificación como medida de seguridad.

¿Cómo activar la verificación DANE en Postfix?

Añade smtp_dns_support_level = dnssec y smtp_tls_security_level = dane en /etc/postfix/main.cf. Postfix verificará automáticamente los TLSA de los dominios destinatarios mediante DNSSEC. Si el TLSA está ausente o es inválido, Postfix vuelve al TLS oportunista.

¿DANE funciona con certificados autofirmados?

Sí. Con DANE-EE (usage 3), el certificado se valida mediante el TLSA en el DNS, no por una autoridad de certificación. Un certificado autofirmado con un TLSA correcto y una zona DNSSEC válida es aceptado por los servidores que verifican DANE.

¿Cómo comprobar que DANE está correctamente configurado?

Tres niveles de verificación: 1) dig +dnssec _25._tcp.mail.captaindns.com TLSA para el DNS, 2) openssl s_client -connect mail.captaindns.com:25 -starttls smtp -dane_tlsa_domain para la correspondencia certificado/TLSA, 3) el inspector DANE/TLSA CaptainDNS para un informe completo incluyendo la cadena DNSSEC.

¿Bind es obligatorio o se puede usar otro servidor DNS?

Bind9 no es obligatorio. Cualquier servidor DNS que soporte DNSSEC funciona: NSD, Knot DNS, PowerDNS. Los principios son idénticos, solo cambia la sintaxis de configuración. En este tutorial se usa Bind9 porque es el más extendido en servidores Linux y su inline-signing simplifica la gestión DNSSEC.

¿Qué pasa si el TLSA ya no coincide con el certificado?

Los servidores que verifican DANE (como Postfix con dane o Gmail) rechazarán establecer la conexión TLS y volverán al modo no cifrado o rechazarán el mensaje según su política. Por eso la doble publicación TLSA durante las rotaciones de clave es esencial. Si tu TLSA está desincronizado, retíralo temporalmente para volver al TLS oportunista mientras corriges la situación.

📚 Guías de DANE/TLSA relacionadas

Fuentes

Artículos relacionados