Servidor de correo – Instalación y configuración SPF, DKIM y DMARC (parte 9)

Esta es una entrada dentro de la serie para la instalación de un servidor de correo completo. Índice completo de contenidos pincha aquí.


Vamos a instalar las medidas de seguridad para verificar que el mensaje proviene de los orígenes indicados en los registros DNS que mostraremos a continuación. Estas configuraciones se hacen a nivel de dominio, siendo necesaria una configuración independiente por cada dominio, tanto en el servidor de correo y DNS para el caso de DKIM y de DNS para el SPF DMARC (previa config del DKIM).

Es recomendable actualizar los registros DKIM mensualmente, o al menos no más allá de 6 meses, siguiendo los pasos anteriores. Solo es necesario dejar un par de semanas los dos registros DNS para DKIM, periodo tras el cual podemos proceder a borrar los registros antiguos.


Instalación de paquetes

Instalamos los paquetes para DKIM:

apt-get install opendkim opendkim-tools postfix-policyd-spf-python postfix-pcre

Agregamos el usuario postfix al grupo opendkim de tal forma que Postfix puede acceder al socket OpenDkim cuando lo necesite:

adduser postfix opendkim

SPF

Configuración DNS

Agregamos el registro SPF al dominio, en mi caso a tiraquelibras.com, indicando la IP estática desde la cual se enviarán los mensajes. Recuerda indicar la IP de tu servidor de correo:

tiraquelibras.com IN TXT “v=spf1 ip4:X.X.X.X/32 -all”

Recuerda que esto es necesario para cada dominio que vayas a configurar en tu servidor de correo.

El parámetro -all (hard fail) indica que si falla el chequeo SPF se rechace el mensaje. De lo contrario tendríamos que indicar el parámetro ~all (softfail), para que de escriba la cabecera de error en el mensaje pero no rechace el mensaje.

Configuración Postfix

Agregamos el agente para la política SPF a Postfix editando el archivo /etc/postfix/master.cf con la siguiente línea al final del documento:

policyd-spf  unix  -       n       n       -       0       spawn
    user=policyd-spf argv=/usr/bin/policyd-spf

Ahora indicamos el timeout a la configuración de Postfix para incrementar el timeout del agente, el cual previene a Postfix de un fallo si las transacciones se ejecutan un poco lentas:

policyd-spf_time_limit = 3600

Y también agregamos la siguiente línea en smtpd_recipient_restrictions para el argumento check_policy_service, aunque OJOOOOO ha de ir después del argumento reject_unauth_destination para evitar transformar el sistema en un OpenRelay:

smtpd_recipient_restrictions =
    ...
    reject_unauth_destination,
    check_policy_service unix:private/policyd-spf,
    ...

Reiniciamos Postfix

systemctl restart postfix

Ahora si enviamos un mensaje entrante podemos ver el chequeo SPF en nuestros logs:

policyd-spf[19080]: prepend Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=…

DKIM

Configuración

Ahora editamos el fichero para DKIM /etc/opendkim.conf, primero hacemos un backup del fichero original cp /etc/opendkim.conf /etc/opendkim.conf.orig y borramos el contenido para sustituirlo por el siguiente:

# This is a basic configuration that can easily be adapted to suit a standard
# installation. For more advanced options, see opendkim.conf(5) and/or
# /usr/share/doc/opendkim/examples/opendkim.conf.sample.

# Log to syslog
Syslog                  yes
# Required to use local socket with MTAs that access the socket as a non-
# privileged user (e.g. Postfix)
UMask                   002

# Sign for example.com with key in /etc/dkimkeys/dkim.key using
# selector '2007' (e.g. 2007._domainkey.example.com)
#Domain                 example.com
#KeyFile                /etc/dkimkeys/dkim.key
#Selector               2007

# Commonly-used options; the commented-out versions show the defaults.
#Canonicalization       simple
#Mode                   sv
#SubDomains             no

# Socket smtp://localhost
#
# ##  Socket socketspec
# ##
# ##  Names the socket where this filter should listen for milter connections
# ##  from the MTA.  Required.  Should be in one of these forms:
# ##
# ##  inet:port@address           to listen on a specific interface
# ##  inet:port                   to listen on all interfaces
# ##  local:/path/to/socket       to listen on a UNIX domain socket
#
#Socket                  inet:8892@localhost
###Socket                  local:/var/run/opendkim/opendkim.sock
Socket                    local:/var/spool/postfix/opendkim/opendkim.sock

##  PidFile filename
###      default (none)
###
###  Name of the file where the filter should write its pid before beginning
###  normal operations.
#
PidFile               /var/run/opendkim/opendkim.pid


# Always oversign From (sign using actual From and a null From to prevent
# malicious signatures header fields (From and/or others) between the signer
# and the verifier.  From is oversigned by default in the Debian pacakge
# because it is often the identity key used by reputation systems and thus
# somewhat security sensitive.
OversignHeaders         From

##  ResolverConfiguration filename
##      default (none)
##
##  Specifies a configuration file to be passed to the Unbound library that
##  performs DNS queries applying the DNSSEC protocol.  See the Unbound
##  documentation at http://unbound.net for the expected content of this file.
##  The results of using this and the TrustAnchorFile setting at the same
##  time are undefined.
##  In Debian, /etc/unbound/unbound.conf is shipped as part of the Suggested
##  unbound package

# ResolverConfiguration     /etc/unbound/unbound.conf

##  TrustAnchorFile filename
##      default (none)
##
## Specifies a file from which trust anchor data should be read when doing
## DNS queries and applying the DNSSEC protocol.  See the Unbound documentation
## at http://unbound.net for the expected format of this file.

TrustAnchorFile       /usr/share/dns/root.key

##  Userid userid
###      default (none)
###
###  Change to user "userid" before starting normal operation?  May include
###  a group ID as well, separated from the userid by a colon.
#
UserID                opendkim


# Map domains in From addresses to keys used to sign messages
KeyTable        /etc/opendkim/key.table
SigningTable        refile:/etc/opendkim/signing.table

# Hosts to ignore when verifying signatures
ExternalIgnoreList  /etc/opendkim/trusted.hosts
InternalHosts       /etc/opendkim/trusted.hosts

# Commonly-used options; the commented-out versions show the defaults.
Canonicalization    relaxed/simple
Mode            sv
SubDomains      no
#ADSPAction     continue
AutoRestart     yes
AutoRestartRate     10/1M
Background      yes
DNSTimeout      5
SignatureAlgorithm  rsa-sha256

SyslogSuccess yes
SoftwareHeader yes
MinimumKeyBits 1024
LogWhy yes
###On-BadSignature reject

En el archivo anterior vamos a comentar la opción de rechazo ante un fallo en el chequeo DKIM de un mensaje, ya que muchos servidores de correo no lo tienen implementado, y por tanto podría dar lugar a bloqueos de mensajes legítimos.

Confirmamos los permisos del fichero:

chmod u=rw,go=r /etc/opendkim.conf

Creamos los directorios para guardar los ficheros de datos de OpenDKIM, asignando el propietario para el usuario opendkim y restringir el resto de permisos:

mkdir -p /etc/opendkim/keys

chown -R opendkim:opendkim /etc/opendkim

chmod go-rw /etc/opendkim/keys

Alta dominio

Creamos la tabla de firmas /etc/opendkim/signing.table y agregamos una línea por dominio que queremos manejar por el servidor de correo. Cada línea debería de tener el siguiente aspecto:

*@tiraquelibras.com   prueba

El primer campo corresponde al patrón que identifica las direcciones e email y el segundo es el nombre para la entrada de la tabla de llaves se deberá de ser usado para firmar los emails para esas direcciones de email. Por simplicidad vamos a instalar una llave para todas las direcciones en el dominio.

Creamos la tabla de llaves /etc/opendkim/key.table que necesita tener una línea por nombre de dominio corto incluido en la tabla de firmas. Cada línea debería de ser como la siguiente:

prueba     tiraquelibras.com:YYYYMM:/etc/opendkim/keys/prueba.private

El primer parámetro es el nombre corto para el dominio que indicamos en la tabla de firmas, que coincide al final con la extensión .private

Reemplazamos los valores YYYYMM por año y mes, el cual indica el selector para el dominio. Aquí podemos indicar un nombre, como dkimIDmail por ejemplo.

El primer parámetro conecta la tabla de firmas con la de llaves.

Las partes de esta línea son:

  • La primera es el nombre de dominio por el cual la llave es usada.
  • La segunda sección es un selector usado cuando se resuelve los registros de la llave en el DNS.
  • La tercer sección nombra el archivo que contiene la llave de la firma para el dominio.

Creamos el archivo de host de confianza /etc/opendkim/trusted.hosts con el siguiente contenido:

127.0.0.1
::1
localhost
myhostname
myhostname.tiraquelibras.com
tiraquelibras.com

Sustituir myhostname por el nombre de host del servidor. Estamos identificando los hosts que los usuarios usarán para el envío de emails y deben tener el envío firmado.

Cambiar los permisos y propietarios en /etc/opendkim y su contenido para el usuario opendkim con los siguientes comandos:

chown -R opendkim:opendkim /etc/opendkim

chmod -R go-rwx /etc/opendkim/keys

Generamos las claves para cada dominio en el directorio /etc/opendkim/keys/ con el comando, cambiando YYYYMM por el identificador del dominio que indicamos en el archivo /etc/opendkim/key.table, recomendando indicar añomes:

opendkim-genkey -b 2048 -h rsa-sha256 -r -s YYYYMM -d example.com -v

Ojo que para que mi proveedor DNS acepte la longitud de para el registro DKIM voy a usar una longitud de 1024 en lugar de 2048 bits. El comando quedaría de la siguiente forma:

opendkim-genkey -b 1024 -h rsa-sha256 -r -s 201908 -d prueba.yeloquehay.com -v

El comando muestra las siguientes líneas:

opendkim-genkey: generating private key

opendkim-genkey: private key written to 201908.private

opendkim-genkey: extracting public key

opendkim-genkey: DNS TXT record written to 201908.txt

Se crean en el directorio actual los archivos 201908.private con la clave privada y 201908.txt con el registro DNS que debemos de crear con una entrada TXT.

Renombramos los ficheros con un nombre que haga referencia al fichero que indicamos en el fichero key.table

mv 201908.private prueba.private

mv 201908.txt prueba.txt

Repetir esto con cada dominio en la tabla de llaves. El parámetro -b 2048 indica el número de bits para el par de llaves RSA para firma y verificación. 1024 es el valor mínimo, pero los con hardware modernos 2048 es más seguro (incluso es posible que 4096 sea requerido en alguna ocasión).

Nos aseguramos que el propietario, permisos y contenidos en /etc/opendkim son correctos ejecutando los siguientes comandos:

cd /etc

chown -R opendkim:opendkim /etc/opendkim

chmod -R go-rw /etc/opendkim/keys

Chequeamos que OpenDKIM se inicia correctamente

systemctl restart opendkim

y si hubiera errores ejecutar para obtener el estado y los mensajes de error:

systemctl status -l opendkim

Registro DNS

Generamos el registro en el DNS de nuestro dominio contenido en el archivo renombrado como prueba.txt, no se muestra el código completo por seguridad

YYYYMM._domainkey       IN      TXT     ( "v=DKIM1; h=rsa-sha256; k=rsa; s=email; "
          "p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDcl79Vak66R3dxO..." )  ; ----- DKIM key 201908 for tiraquelibras.com

siendo YYYYMM el identificador que le indicamos en el comando ejecutado antes.

Debemos de tener en cuenta que el primer valor es el subdominio a crear y el valor del registro es el que hay entre los paréntesis, entre las dobles comillas NO INCLUIDAS, siendo el origen v=DKIM1. Luego borramos el resto de comillas dobles y los espacios en blanco entre estas. También cambiamos h=rsa-sha256  por h=sha256. El resultado sería, no se muestra el código completo por seguridad:

v=DKIM1; h=sha256; k=rsa; s=email; p=MIGfMA0GCSqGSIb3DQEBAQ…

Este paso hay que realizarlo por cada dominio que vayamos a configurar en nuestro servidor de correo.

Comprobar DKIM creado

Hacemos un test para comprobar la configuración DKIM para el dominio creado con el comando

opendkim-testkey -d tiraquelibras.com -s 201908

Si todo ha ido bien no deberíamos de obtener respuesta alguna. Si necesitamos más información agregamos -vvv al final del comando.

opendkim-testkey: using default configfile /etc/opendkim.conf
opendkim-testkey: checking key '201909._domainkey.tiraquelibras.com'
opendkim-testkey: key not secure
opendkim-testkey: key OK

Al final se indica key OK. Justamente antes se indica key not secure debido a que el domnio no tiene configurado aún DNSSEC.

Configurar DKIM en Postfix

Configuramos DKIM en Postfix.

Creamos el directorio para el socket OpenDKIM en el área de trabajo de Postfix y nos aseguramos que los permisos son los correctos:

mkdir /var/spool/postfix/opendkim

chown opendkim:postfix /var/spool/postfix/opendkim

Ahora indicamos el socket correcto para Postfix en el fichero defaults de OpenDKIM dentro del archivo /etc/default/opendkim:

# Command-line options specified here will override the contents of
# /etc/opendkim.conf. See opendkim(8) for a complete list of options.
#DAEMON_OPTS=""
# Change to /var/spool/postfix/var/run/opendkim to use a Unix socket with
# postfix in a chroot:
#RUNDIR=/var/spool/postfix/var/run/opendkim
RUNDIR=/var/run/opendkim
#
# Uncomment to specify an alternate socket
# Note that setting this will override any Socket value in opendkim.conf
# default:
###SOCKET=local:$RUNDIR/opendkim.sock

######SOCKET="inet:8891@localhost"
SOCKET="local:/var/spool/postfix/opendkim/opendkim.sock"

# listen on all interfaces on port 54321:
#SOCKET=inet:54321
# listen on loopback on port 12345:
#SOCKET=inet:12345@localhost
# listen on 192.0.2.1 on port 12345:
#SOCKET=inet:12345@192.0.2.1
USER=opendkim
GROUP=opendkim
PIDFILE=$RUNDIR/$NAME.pid
EXTRAAFTER=

La ruta al socket es diferente al de por defecto porque en DEBIAN el proceso Postfix que maneja los emails se ejecuta en un chroot jail y no puede acceder a la localización normal.

Editamos el archivo de Postfix /etc/postfix/main.cf y agregamos las líneas:

# Milter configuration
# OpenDKIM
milter_default_action = accept
# Postfix ≥ 2.6 milter_protocol = 6, Postfix ≤ 2.5 milter_protocol = 2
milter_protocol = 6
smtpd_milters = local:opendkim/opendkim.sock
non_smtpd_milters = local:opendkim/opendkim.sock

Se puede poner en cualquier lugar del fichero, pero la práctica habitual es hacerlo después de la entrada smtpd_recipient_restrictions. La ruta es distinta a la del archivo /etc/defaults/opendkim debido al chroot jail de Postfix, cuya ruta aquí es la ruta con la vista restringida del filesystem en lugar de el actual filesystem.

Reiniciamos el servicio OpenDKIM

systemctl restart opendkim

Reiniciamos Postfix

systemctl restart postfix

Check DKIM

Confirmamos nuestra configuración DKIM enviando un email a la dirección check-auth@verifier.port25.com desde donde nos enviarán un informe completo de los chequeos de seguridad pertinentes, incluido el SPF y SpamAssassin flagging en el dominio origen. También si detecta problemas o errores.

Opcional

agregar a nivel DNS la entrada para ADSP (Author Domain Signing Practices), info pinchando aquí, en donde indicamos que todos los emails para este dominio deben de ser firmados con DKIM. Para ello creamos una entrada TXT para el host _adsp._domainkey con el valor dkim=all.

Resumen para crear un nuevo dominio

Resumiendo, para agregar un nuevo dominio una vez instalado DKIM en nuestro sistema, debemos de realizar las siguientes tareas:

  • Creamos la entrada para la nueva firma en el fichero /etc/opendkim/signing.table en donde indicamos el dominio y el identificador del dominio.
  • Creamos la entrada para la nueva llave en el fichero /etc/opendkim/key.table en donde indicamos el identificador anterior, el dominio, el identificador para DKIM y el fichero con la clave privada.
  • Generamos la clave privada en un directorio de pruebas (por ejemplo /root) y lo renombramos como lo indicado en el fichero anterior para la llave privada. Comando opendkim-genkey -b 1024 -h rsa-sha256 -r -s 201908 -d prueba.yeloquehay.com -v, renombramos los ficheros generados como acabamos de decir y los movemos al directorio /etc/opendkim/keys/.
  • Paramos OpenDKIM y Postfix con el comando systemctl stop postfix opendkim.
  • Confirmamos los permisos de los directorios con los comados:
cp *.private /etc/opendkim/keys/

chown opendkim:opendkim /etc/opendkim/keys/*

chmod go-rw /etc/opendkim/keys/*
  • Arrancamos OpenDKIM y Postfix con:
systemctl start opendkim

systemctl start postfix
  • Generamos los registros DNS pertinentes para DKIM/ADSP (con la clave y con el forzado a que todos los mensajes vayan firmados) y DMARC.

DMARC

La entrada DMARC se realiza a nivel de DNS e informa a los servidores de correo que piensas que deberían de hacer con los emails que dicen ser de tu dominio cuya validación fallara con el SPF y/o DKIM. Además permite recibir reportes sobre emails que fallan al pasar una o más validaciones. SOLO debería de activarse si tenemos SPF y DKIM correctamente, de lo contrario irán al SPAM del destino.

Existen múltiples configuraciones posibles, pudiendo consultarlas en su web oficial pinchando aquí, pero yo voy a mostrar un ejemplo de lo que decidí configurar para mis dominios. Recuerda que esta configuración se debe de realizar por cada dominio que tenemos configurado en nuestro servidor de correo.

La entrada DMARC es de tipo TXT para el host _dmarc con los siguientes valores recomendados:

v=DMARC1;p=quarantine;sp=quarantine;adkim=r;aspf=r

Esto indica a los servidores de correo que de fallar los chequeos SPF y DKIM no descarten el mensaje pero lo metan en cuarentena. No existe ningún reporte. Muchos servidores de correo implementan software que generan reportes cuando fallan los mensajes, por lo que para recibirlos mejor agregar la siguiente línea, por ejemplo:

v=DMARC1;p=quarantine;sp=quarantine;adkim=r;aspf=r;fo=1;rf=afrf;rua=mailto:user@example.com

En donde mailto: indica el email en donde recibir estos informes.


Índice general pincha aquí.