Tutorial de DomainKeys 0.x y Postfix 2.x

Escrito por coder el 27 de marzo de 2007 en Informática | Hits: 3518

Ahora que, con hoy, son cuatro los días que llevo en la cama debido a un constipado bastante agresivo (con fiebre incluída) que me ha impedido dedicarme a mis labores profesionales y personales, aprovecho para hacer un mini howto de algo que viene siendo necesario ya desde hace algún tiempo: DomainKeys (o dkim -domainkeys identified mail en su versión mejorada-) + Postfix en castellano.

 

Y es que los tutoriales que he encontrado no me han convencido en absoluto, ya que, a mi juicio, obviaban dos temas fundamentales: 1) no perder otras funcionalidades -vease spamd o clamav- y 2) hablar del servicio submission.

 

Al asunto:

 

¿Qué es DomainKeys? Es una tecnología que está siendo desarrollada por Yahoo que utiliza criptografía pública para dar validez al correo saliente y verificar el correo entrante. El draft, si no he leído mal, está ahora mismo en pleno debate por parte de bastantes empresas, entre ellas AOL, Cisco y demás pesos pesados.

 

Configuración en Postfix: Es bastante simple. Tan sólo hay que instalar serie de módulos para Perl que permitan al proxy-SMTP dkfilter funcionar, dejándole a este la tarea de realizar el verificado y firmado de los emails. Vamos a ello:

 

En Gentoo los módulos se pueden instalar usando cualquier sistema de paquetes, ya sea Portage o Paludis:

 

# paludis crypt-rsa Email-Address MIME-Base64 Net-DNS\
List-MoreUtils Mail-DomainKeys -i
# emerge crypt-rsa Email-Address \
MIME-Base64 Net-DNS List-MoreUtils Mail-DomainKeys

 

En otras distros habrá que usar otros comandos (ya sea apt-get en Debian, urpmi en Mandriva, yum/rpm en RedHat o yast2 en SuSE). Para el que use Slackware o quiera hacerlo a manopla, un clásico bastará:

 

perl -MCPAN -e'CPAN::Shell->install("Crypt::OpenSSL::RSA")'
perl -MCPAN -e'CPAN::Shell->install("Mail::Address")'
perl -MCPAN -e'CPAN::Shell->install("MIME::Base64")'
perl -MCPAN -e'CPAN::Shell->install("Net::DNS")'
perl -MCPAN -e'CPAN::Shell->install("Test::More")'
perl -MCPAN -e'CPAN::Shell->install("Text::Wrap")'
perl -MCPAN -e'CPAN::Shell->install("Email::Address")'
perl -MCPAN -e'CPAN::Shell->install("Mail::DomainKeys")'

 

Después nos bajamos y compilamos el proxy-SMTP de la web de Jason (la última versión estable es la 0.11, y parece que será la última, al estar en desarrollo paralelo dkimproxy):

 

$ wget http://jason.long.name/dkfilter/dkfilter-0.11.tar.gz
$ tar xvf dkfilter-0.11.tar.gz
$ cd dkfilter-0.11
$ ./configure --prefix=/usr/local/dkfilter && make install
$ useradd dkfilter

 

 

Una vez compilado e instalado en /usr/local/dkfilter, tenemos que configurar Postfix para que utilice el proxy, ya sea para los emails de entrada o los de salida. En los howtos que yo he visto suelen utilizar el puerto 10025 para entrada al proxy y el 10026 para la salida del mismo. Esto yo lo veo bien, siempre y cuando no estés ya usando esos puertos. Pero, ¿qué pasa? que casualmente tengo el amavisd-new funcionando también como proxy en esos puertos para filtrar el correo basura -spam y virus-. Y, de momento y hasta que tanto DKIM como SPF sean una realidad obligatoria, no puedo prescindir del servicio amavisd-new. Por tanto yo lo cambié a otros puertos no privilegiados, 10055 y 10056 para verificar y 10057 y 10058 para firmar. Sabiendo eso, editamos el fichero /etc/postfix/master.cf y añadimos la nueva configuración:

 

 

# vim /etc/postfix/master.cf
# DKFILTER.IN
# Nada mas llegar un email al sistema, este ha de ser verificado por el proxy
smtp inet n - n - - smtpd
-o smtpd_proxy_filter=127.0.0.1:10055
-o smtpd_client_connection_count_limit=10
# Y se devuelve verificado en el puerto 10056<
127.0.0.1:10056 inet n - n - - smtpd
-o smtpd_authorized_xforward_hosts=127.0.0.0/8
-o smtpd_client_restrictions=
-o smtpd_helo_restrictions=
-o smtpd_sender_restrictions=
-o smtpd_recipient_restrictions=permit_mynetworks,reject
-o smtpd_data_restrictions=
-o mynetworks=127.0.0.0/8
-o receive_override_options=no_unknown_recipient_checks
# DKFILTER.OUT
# modificamos el servicio submission para que sólo los lusers locales y
# los autentificados mediante SASL (en mi caso Dovecot-SASL) puedan
# firmar los emails salientes
submission inet n - n - - smtpd
-o smtpd_etrn_restrictions=reject
-o smtpd_sasl_auth_enable=yes
-o content_filter=dksign:[127.0.0.1]:10057
-o receive_override_options=no_address_mappings
-o smtpd_recipient_restrictions=permit_mynetworks
,permit_sasl_authenticated,reject
#
# creamos el servicio con el nombre dksign y le asignamos un tope de 10
procesos
#
dksign unix - - n - 10 smtp
-o smtp_send_xforward_command=yes
-o smtp_discard_ehlo_keywords=8bitmime
#
# emails de vuelta a Postfix ya firmados
#
127.0.0.1:10058 inet n - n - 10 smtpd
-o content_filter=
-o receive_override_options=no_unknown_recipient_checks,
no_header_body_checks
-o smtpd_helo_restrictions=
-o smtpd_client_restrictions=
-o smtpd_sender_restrictions=
-o smtpd_recipient_restrictions=permit_mynetworks,reject
-o mynetworks=127.0.0.0/8
-o smtpd_authorized_xforward_hosts=127.0.0.0/8

 

Una vez hecho esto, guardamos el fichero y salimos, pero NO reiniciamos Postfix todavía, ya que no hemos ni arrancado el dkfilter ni generado la clave.

 

Generar la clave es muy fácil:

 

# cd /usr/local/dkfilter
# openssl genrsa -out private.key 1024
# openssl rsa -in private.key -pubout -out public.key

 

 

Ahora, para tenerlo todo listo, sólo nos falta publicar la clave pública (valga la rebuznancia) en la zona TXT de nuestro DNS (sí, ya sé, la zona TXT se está llenando de broza cada día más, no era bastante con el SPF ni los srv de w2k3, ahora también esto...):

 

Nos inventamos un selector (dk por ejemplo) y sacamos la clave pública del fichero y la pegamos en la zona TXT:

 

_domainkey.fluzo.org        IN TXT  “t=y; o=-;”
dk._domainkey.fluzo.org IN TXT "g=; k=rsa; p=clave_pública;"


Y a la marcha. Ya está listo. Podemos comprobarlo usando esta URL de test

 

Arrancamos el servicio utilizando este script que encontré en la web de enterux (ahora mismo caída):

 

 

#!/bin/sh
#
# Copyright (c) 2005 Messiah College.

DKFILTERUSER=dkfilter
DKFILTERGROUP=dkfilter
DKFILTERDIR=/usr/local/dkfilter

HOSTNAME=`hostname -f`
DOMAIN="fluzo.org" #`hostname -d`
DKFILTER_IN_ARGS="--hostname=$HOSTNAME 127.0.0.1:10055 127.0.0.1:10056"
DKFILTER_OUT_ARGS="--keyfile=$DKFILTERDIR/private.key --selector=dk
--domain=$DOMAIN --method=nofws --headers 127.0.0.1:10057
 127.0.0.1:10058"

DKFILTER_IN_BIN="$DKFILTERDIR/bin/dkfilter.in"
DKFILTER_OUT_BIN="$DKFILTERDIR/bin/dkfilter.out"
PIDDKFILTER_IN="/var/run/dkfilter.in"
PIDDKFILTER_OUT="/var/run/dkfilter.out"

case "$1" in
        start)
                echo -n "Starting inbound DomainKeys-filter (dkfilter.in)..."
                 start-stop-daemon --start -q -p$PIDDKFILTER_IN -u
$DKFILTERUSER -g $DKFILTERGROUP -x `$DKFILTER_IN_BIN $DKFI
LTER_IN_ARGS` &
                RETVAL=$?
                if [ $RETVAL -eq 0 ]; then
                        echo done.
                else
                        echo failed.
                        exit $RETVAL
                fi
                echo -n "Starting outbound DomainKeys-filter (dkfilter.out)..."
                 start-stop-daemon --start -q -p $PIDDKFILTER_OUT -u
$DKFILTERUSER -g $DKFILTERGROUP -x `$DKFILTER_OUT_BIN $D
KFILTER_OUT_ARGS` &
                RETVAL=$?
                if [ $RETVAL -eq 0 ]; then
                        echo done.
                else
                        echo failed.
                        exit $RETVAL
                fi
                ;;

        stop)
                echo -n "Shutting down inbound DomainKeys-filter (dkfilter.in)..."
                 start-stop-daemon --stop -p $PIDDKFILTER_IN
                RETVAL=$?
                if [ $RETVAL -eq 0 ]; then
                        echo done.
                else
                        echo failed.
                fi
                echo -n "Shutting down outbound DomainKeys-filter (dkfilter.out)..."
                start-stop-daemon --stop -p $PIDDKFILTER_OUT
                RETVAL=$?
                if [ $RETVAL -eq 0 ]; then
                        echo done.
                else
                        echo failed.
                        exit $RETVAL
                fi
                ;;
        restart)
                $0 stop
                $0 start
                ;;
        *)
                echo "Usage: $0 {start|stop|restart}"
                exit 1
                ;;
esac
 

 

Y una vez arrancado, ya podemos reiniciar Postfix:

 

 

# /etc/init.d/dkfilter start
# postfix reload

 

 

El sistema está funcionando. (En Gentoo podemos añadir dkfilter al runlevel default con rc-update, en otras distros o bien con sus utilidades o como toda la vida con un ln al rc.d correspondiente y au). Ahora sólo falta comprobar las cabeceras de los emails que llegan por si algún emisor que no seamos nosotros también está implementando DomainKeys:

 

 

Authentication-Results: fraga from=bugzilla-daemon@gentoo.org;
domainkey=neutral (no signature; no policy for gentoo.org) 

 

 

Y para el envío, configuramos el cliente de correo para usar el puerto submission (587 -grep submission /etc/services-) y firmaremos:

 

 

DomainKey-Signature: a=rsa-sha1; h=Received:Date:From:To:Subject:Message-ID:
Organization:X-Vader:X-Mailer:Mime-Version:Content-Type:
Content-Transfer-Encoding; b=wCSIKygHWje8oa5lSRW7L1Rzwk...S8y9xkFfM+Q=;
c=nofws; d=fluzo.org; q=dns; s=m1 

 

Working!



         

« Test de posicionamiento ideológico

Romario, a un gol de los 1000 »



Comentarios

  • El 2007-03-27 17:30:50, Romel (213.201.88.114) dijo:

    groxo!!
    un dia de estos lo implementare en mi postfix xD
    Aunq yo creo q esto "obligarlo" a usarlo a todo el mundo va a estar bastante jodido

  • El 2007-03-28 00:18:42, pollo (192.168.1.51) dijo:

    Se ha resistido el cabron hasta que no has estado enfermo no ha ido xD

  • El 2007-03-28 09:06:56, presi (19.174.132.168) dijo:

    Correctísimo.

    La única pega es que yo uso exim, no postfix xDDD

    Y en cuanto a todas estas tecnologías yo soy un poco escéptico, mientras los spamers puedan abrir a mano una cuenta de yahoo o gmail y a partir de ahi a través del webmail meter un script que empiece a mandar mierda que se salta los filtros por estar certificada por domainkeys y spf... hasta que esas cuentas son detectadas y eliminadas ya han mandado unos cuantos spams... de poco nos sirve.

  • El 2007-07-04 07:11:25, Edgar (200.27.132.218) dijo:

    Funciono bien, hay algunos detalles en la shell de partida, no reconoce los usuarios y parte con usuario 0, lo otro es que te comiste un espacion luego del primer argumento -p en la parte start, y lo mas raro es que las consultas dns siempre traen un punto adelante lo que hace que los dns no lo reconoscan como registro valido y rechazan la consulta. hay que investigar el porque pasa eso.

    eso por ahora y gracias por este trabajo, me aliviaste un problema con los proveedores de gmail y yahoo, includo M$Hotmail.

    un saludo y abrazo grande a la distancia desde chile

    Edgar

  • El 2007-07-07 16:14:04, coder (86.109.160.34) dijo:

    Coño, Edgar, se me pasó responder tu comentario. Sí, habría que darle un repaso al script, y ten por seguro que para Septiembre u Octubre lo haré.

    NAPALM...

  • El 2007-07-11 05:56:08, Edgar (200.27.132.218) dijo:

    principalmente los cambios que efectue fueron estos.



    DKFILTER_IN_ARGS="
    --hostname=$HOSTNAME 127.0.0.1:10055 127.0.0.1:10056
    --user=$DKFILTERUSER
    --group=$DKFILTERGROUP
    --pidfile=$PIDDKFILTER_IN"

    DKFILTER_OUT_ARGS="
    --keyfile=$DKFILTERDIR/private.key
    --selector=postfix
    --domain=$DOMAIN
    --method=nofws
    --headers 127.0.0.1:10057 127.0.0.1:10058
    --user=$DKFILTERUSER
    --group=$DKFILTERGROUP
    --pidfile=$PIDDKFILTER_OUT"

    si te fijas agregue los usuarios y grupos a los argumentos de entrada del programa, ya que no los estabas pasando, y solo al start-stop-daemon, que sirve para arrancar el programa, pero no asi al demonio mismo, es casi logico, pero muy redundante.

    por otra parte, efectue este cambio.

    (para in)
    start-stop-daemon --start -q --pidfile=$PIDDKFILTER_IN --user=$DKFILTERUSER --group=$DKFILTERGROUP -x `$DKFILTER_IN_BIN $DKFILTER_IN_ARGS` &

    (para out)
    start-stop-daemon --start -q --pidfile=$PIDDKFILTER_OUT --user=$DKFILTERUSER --group=$DKFILTERGROUP -x `$DKFILTER_OUT_BIN $DKFILTER_OUT_ARGS` &


    y ademas tube que modificar el archivo $src-dir/dkfilter-0.11/lib/Mail/DomainKeys/Polocy.pm


    en la linea 39 figura lo siguiente.
    my $host = "._domainkey." . $prms{'Domain'};

    siendo que debería ser

    my $host = "_domainkey." . $prms{'Domain'};


    la diferencia del punto hace que muchos de los servidores dns no comprendan que se refiere al registro A dominio en cuestion, mas bien creen que es un dominio delegado, lo que conyeba a que se caiga la consulta con timeout y tu velocida de salida de correos se transforme en practicamente 1 correo por minuto.


    son todos los detalles que he encontrado hasta el momento y puedo dar fe que funciona de marabillas dkim.

    saludos y un abrazo grande.

    edgar



  • El 2007-07-11 06:03:18, Edgar (200.27.132.218) dijo:

    lo otro, falto escribir que en la zona dns deben poner el nombre del selector y tambien la forma correcta de poner el _domainkey record.

    lo agrego mañana.

    saludos

    edgar

  • El 2008-04-30 22:47:32, LinuxCuba (200.55.142.42) dijo:

    Y Como sería esto último cuando mando un correo a yahoo me sale lo siquiente domainkeys=temperror (cant get key) y los correos salen firmados bien.
    DomainKey-Signature: a=rsa-sha1; h=Received:MIME-Version:From:To:Subject:Date:User-Agent:Content-Type:Message-Id; b=soW8VAHjRrhIhLvhEAtBUaIbuYnwdWnmGtiC7SAmciEqVT5f5/IMZUdb9yeh2ZD15FLZVxxr3jhFBe7DeBeCfgJCofo4FvpNru5r328iX8svQQPUZo5rXxYdHbgVcA4oUPIRGl+QZ87bnMhwRYxY0FXeqLpUgcq8Np7nM+HKwsg=; c=nofws; d=eiefd.co.cu; q=dns; s=dk

    y el test me da OK.

    Testing eiefd.co.cu
    Policy TXT=t=y; o=-;

    This policy record appears valid.

    Tag Value Explanation
    o - Domain signs *ALL* email
    t y Domain is in test mode

    Me pueden explicar que puede estar pasando. Salu2. desde Cuba.

[ Comentar la jugada ]