Tutorial de DomainKeys 0.x y Postfix 2.x

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

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!



         

« Micro chulla SVN

Romario, a un gol de los 1000 »



Comentarios

  • El 2007-03-27 17:30:50, Romel (213.201.88) 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) 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) 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) 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) 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) 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) 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) 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.

  • El 2009-11-12 15:49:18, Erik (200.125.104) dijo:

    cuando configuro eso me tira ese error ademas los puertos 1002x no me responde ninguno al telnet



    Out: 250-8BITMIME
    Out: 250 DSN
    In: MAIL FROM:
    Out: 250 2.1.0 Ok
    In: RCPT TO:
    Out: 451 4.3.0 Error: queue file write error
    In: QUIT
    Out: 221 2.0.0 Bye

    #
    # Postfix master process configuration file. For details on the format
    # of the file, see the master(5) manual page (command: "man 5 master").
    #
    # Do not forget to execute "postfix reload" after editing this file.
    #
    # ==========================================================================
    # service type private unpriv chroot wakeup maxproc command + args
    # (yes) (yes) (yes) (never) (100)
    # ==========================================================================


    smtp inet n - - - - smtpd
    fragile unix - - n - 20 smtp
    hotmail unix - - n - 20 smtp


    #smtp-amavis unix - - y - 2 smtp
    # -o smtp_data_done_timeout=1200
    # -o disable_dns_lookups=yes
    #127.0.0.1:10025 inet n - y - - smtpd
    # -o content_filter=
    # -o local_recipient_maps=
    # -o relay_recipient_maps=
    # -o smtpd_restriction_classes=
    # -o smtpd_client_restrictions=
    # -o smtpd_helo_restrictions=
    # -o smtpd_sender_restrictions=
    # -o smtpd_recipient_restrictions=permit_mynetworks,reject
    # -o mynetworks=127.0.0.0/8
    # -o strict_rfc821_envelopes=yes

    #submission inet n - - - - smtpd
    # -o smtpd_tls_security_level=encrypt
    # -o smtpd_sasl_auth_enable=yes
    # -o smtpd_client_restrictions=permit_sasl_authenticated,reject
    # -o milter_macro_daemon_name=ORIGINATING
    #smtps inet n - - - - smtpd
    # -o smtpd_tls_wrappermode=yes
    # -o smtpd_sasl_auth_enable=yes
    # -o smtpd_client_restrictions=permit_sasl_authenticated,reject
    # -o milter_macro_daemon_name=ORIGINATING
    #628 inet n - - - - qmqpd
    pickup fifo n - - 60 1 pickup
    cleanup unix n - - - 0 cleanup
    qmgr fifo n - n 300 1 qmgr
    #qmgr fifo n - - 300 1 oqmgr
    tlsmgr unix - - - 1000? 1 tlsmgr
    rewrite unix - - - - - trivial-rewrite
    bounce unix - - - - 0 bounce
    defer unix - - - - 0 bounce
    trace unix - - - - 0 bounce
    verify unix - - - - 1 verify
    flush unix n - - 1000? 0 flush
    proxymap unix - - n - - proxymap
    proxywrite unix - - n - 1 proxymap
    smtp unix - - - - - smtp
    # When relaying mail as backup MX, disable fallback_relay to avoid MX loops
    relay unix - - - - - smtp
    -o smtp_fallback_relay=
    # -o smtp_helo_timeout=5 -o smtp_connect_timeout=5
    showq unix n - - - - showq
    error unix - - - - - error
    retry unix - - - - - error
    discard unix - - - - - discard
    local unix - n n - - local
    virtual unix - n n - - virtual
    lmtp unix - - - - - lmtp
    anvil unix - - - - 1 anvil
    scache unix - - - - 1 scache
    #
    # ====================================================================
    # Interfaces to non-Postfix software. Be sure to examine the manual
    # pages of the non-Postfix software to find out what options it wants.
    #
    # Many of the following services use the Postfix pipe(8) delivery
    # agent. See the pipe(8) man page for information about ${recipient}
    # and other message envelope options.
    # ====================================================================
    #
    # maildrop. See the Postfix MAILDROP_README file for details.
    # Also specify in main.cf: maildrop_destination_recipient_limit=1
    #
    maildrop unix - n n - - pipe
    flags=DRhu user=vmail argv=/usr/bin/maildrop -d ${recipient}
    #
    # See the Postfix UUCP_README file for configuration details.
    #
    uucp unix - n n - - pipe
    flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
    #
    # Other external delivery methods.
    #
    ifmail unix - n n - - pipe
    flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient)
    bsmtp unix - n n - - pipe
    flags=Fq. user=bsmtp argv=/usr/lib/bsmtp/bsmtp -t$nexthop -f$sender $recipient
    scalemail-backend unix - n n - 2 pipe
    flags=R user=scalemail argv=/usr/lib/scalemail/bin/scalemail-store ${nexthop} ${user} ${extension}
    mailman unix - n n - - pipe
    flags=FR user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py
    ${nexthop} ${user}


    # 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 slos 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

  • El 2009-11-12 15:52:38, Erik (200.125.104) dijo:

    los puertos son 1005x pero no responden
    cuando saco la configuracion nueva el postfix recibe normalmente.
    hizo algo parecido cuando intente instalar el avant-new (o similar)
    saludos

[ Comentar la jugada ]


NOTA: los comentarios están moderados gracias a los spammers. Ten paciencia si tardo en aprobar el tuyo.