Servidor de Correo – Casillas y usuarios virtuales

Este artículo cubre el soporte de múltiples dominios y usuarios virtuales, gestión de alias y correo electrónico mediante interfaces web.

Nombre del Servidor: servidor.midominio.com.ar

Sistema Operativo: Debian 10 “Buster”

Instalar paquetes para postfix, dovecot, mariadb

apt install postfix postfix-mysql dovecot-core dovecot-imapd dovecot-pop3d dovecot-lmtpd dovecot-mysql mariadb-server dovecot-sieve dovecot-managesieved

Si estás agregando un servidor de correo a un sistema existente algunos paquetes pueden ya estar presentes. Dependiendo de la lista de paquetes previamente instalada, puede que veas o no los avisos para configurar mariadb, postfix, etc. Escoge los valores predeterminados siempre que sea posible.

Configuración de Postfix

Esta guía fue creada usando Postfix 3.4.14. Se puede verificar la versión de postfix instalada usando:

postconf mail_version

La configuración de Postfix tiene 2 archivos importantes:

main.cf

y

master.cf

. Vamos a agregar también algunos otros archivos para el sistema virtual de dominio/correo.

Postfix master.cf

Para que smtp ‘escuche’ en el puerto 465 (con SSL) y en el puerto 587 (con TLS), es necesario descomentar las siguientes lineas en

master.cf:

submission inet n - - - - smtpd smtps inet n - - - - smtpd

Se recomienda hacer esto ya que la mayoría de los ISP bloquea el puerto 25 para prevenir spam.

FORZAR la autenticación segura (sobre SSL o TLS)

Esto solo afecta a las conexiones salientes.

Bajo la línea

smtp inet n - - - - smtpd

agregar

 -o smtpd_enforce_tls=yes

y luego reiniciar Postfix.

Diffie – Hellman

El intercambio de claves Diffie-Hellman es un método de intercambio seguro de claves criptográficas a través de un canal público. Su objetivo principal es desarrollar de forma segura secretos compartidos que puedan utilizarse para derivar claves. Estas claves pueden utilizarse con algoritmos de clave simétrica para transmitir información de forma protegida.

Generación de un grupo DH único

Primero hay que generar un nuevo y único grupo Diffie-Hellman, la recomendación es que sea de 2048 bits. La forma más sencilla de hacerlo es utilizar OpenSSL:

openssl dhparam -out dhparams.pem 2048

Esto puede representar una carga significativa en el servidor mientras se generan los parámetros – siempre se puede evitar este problema potencial mediante la generación de los parámetros en otra máquina y el uso de scp o similar para transferirlos al servidor en cuestión para su uso.

Postfix main.cf

Agregar al main.cf las siguientes lineas hacia el final del archivo:

Agregamos y ajustamos los demás parámetros:

# other destination domains should be handled using virtual domains
mydestination = localhost
smtp_host_lookup = dns
smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt
smtpd_tls_dh1024_param_file = /etc/ssl/private/dhparams.pem
smtpd_helo_required=yes
#Secure Client-Initiated Renegotiation
# postfix 3.4 and openssl >1.1.1
tls_ssl_options = NO_RENEGOTIATION
#Enable TLS Encryption when Postfix receives incoming emails
smtpd_tls_cert_file=/etc/apache2/md/domains/midominio.com.ar/pubcert.pem
smtpd_tls_key_file=/etc/apache2/md/domains/midominio.com.ar/privkey.pem
# Enforce encryption during authentication
smtpd_tls_auth_only=yes
smtpd_tls_loglevel = 1
# Add information about the ciphers used during transfer to the
# message headers
smtpd_tls_received_header = yes
# Encryption is optional. Changing this to encrypt will enforce
# the use of TLS but has the side effect that MTAs without TLS
# capability won't be able to deliver mail to our server.
smtpd_tls_security_level = may
# Disallow any methods that do allow anonymous authentication
smtpd_sasl_security_options = noanonymous, noplaintext
smtpd_sasl_tls_security_options = noanonymous
smtpd_tls_loglevel = 1
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
#Enable TLS Encryption when Postfix sends outgoing emails
# Enforce the use of TLS
smtp_tls_security_level = verify
smtp_tls_loglevel = $smtpd_tls_loglevel
smtp_tls_mandatory_protocols = $smtpd_tls_mandatory_protocols
smtp_tls_mandatory_ciphers = $smtpd_tls_mandatory_ciphers
smtp_tls_exclude_ciphers = $smtpd_tls_exclude_ciphers
smtp_tls_mandatory_exclude_ciphers = $smtpd_tls_mandatory_exclude_ciphers
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
# Negotiate the strongest available cipher available with the remote server.
smtpd_tls_protocols = TLSv1.2, !TLSv1.1, !TLSv1, !SSLv2, !SSLv3
smtp_tls_protocols = $smtpd_tls_protocols
smtp_tls_ciphers = high
smtpd_tls_ciphers = high
smtpd_tls_mandatory_protocols = $smtpd_tls_protocols
smtp_tls_mandatory_protocols = $smtpd_tls_protocols
smtp_tls_mandatory_ciphers = high
smtpd_tls_mandatory_ciphers = high
# Exclude some deprecated not so secure ciphers.
smtpd_tls_mandatory_exclude_ciphers = MD5, DES, ADH, RC4, PSD, SRP, 3DES, eNULL, aNULL
smtpd_tls_exclude_ciphers = $smtpd_tls_mandatory_exclude_ciphers
smtp_tls_mandatory_exclude_ciphers = $smtpd_tls_mandatory_exclude_ciphers
smtp_tls_exclude_ciphers = $smtpd_tls_mandatory_exclude_ciphers
# Postfix will select the cipher used for communication.
tls_preempt_cipherlist = yes
# Disable all OpenSSL bug work-arounds on a 64 bit system
tls_disable_workarounds = 0xFFFFFFFFFFFFFFFF
#Handle SMTP authentication using Dovecot
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
# Don't talk to mail systems that don't know their own hostname.
smtpd_recipient_restrictions =
 reject_unknown_sender_domain,
 permit_mynetworks,
 permit_sasl_authenticated,
# DNSBL (DNS Based Blacklist/Blocklist)
 reject_rbl_client zen.spamhaus.org,
 reject_rhsbl_reverse_client dbl.spamhaus.org,
 reject_rhsbl_helo dbl.spamhaus.org,
 reject_rhsbl_sender dbl.spamhaus.org,
# Don't accept mail from domains that don't exist.
smtpd_sender_restrictions =
 reject_unknown_sender_domain
# Allow connections from trusted networks and authenticated users.
smtpd_client_restrictions =
 permit_mynetworks,
 permit_sasl_authenticated
# Relay control: local clients and
# authenticated clients may specify any destination domain.
smtpd_relay_restrictions =
 permit_mynetworks,
 permit_sasl_authenticated,
 reject_unauth_destination
#The size is in Bytes...
mailbox_size_limit = 0 # Ilimitado
message_size_limit = 20971520 # 20 Mb
# using Dovecot's LMTP for mail delivery and giving it path to store mail
virtual_transport = lmtp:unix:private/dovecot-lmtp
# virtual mailbox setups
virtual_alias_maps = mysql:/etc/postfix/mysql/virtual_alias_maps.cf
virtual_mailbox_domains = mysql:/etc/postfix/mysql/virtual_domains_maps.cf
virtual_mailbox_maps = mysql:/etc/postfix/mysql/virtual_mailbox_maps.cf

Deshabilitamos el chroot (predeterminado en Debian) modificando /etc/postfix/master.cf. Debería verse así

# ==========================================================================
# service type private unpriv chroot wakeup maxproc command + args
# (yes) (yes) (yes) (never) (100)
# ==========================================================================
smtp unix - - - - - smtp

Verificar certificados

Ninguna configuración está exenta de eventuales problemas. Llegado el caso, estos comandos pueden resultar de utilidad a la hora de enfrentarlos.

Para los certificados públicos

openssl x509 -in /etc/apache2/md/domains/midominio.com.ar/pubcert.pem -text -noout

Si no está dañado el resultado de este comando debería mostrar, entre otras cosas, los (sub)dominios para los cuales fue creado:

DNS:campus.midominio.com.ar, DNS:eventos.midominio.com.ar, DNS:mapa.midominio.com.ar, DNS:nube.midominio.com.ar, DNS:pad.midominio.com.ar, DNS:reuniones.midominio.com.ar, DNS:www.midominio.com.ar

En tanto que, para los certificados privados verificamos que contengan una llave válida

openssl rsa -in /etc/apache2/md/domains/midominio.com.ar/privkey.pem -text -noout

El resultado de este comando debería mostrar algo así:

RSA key ok

Configuración de Casillas de Correo Virtuales en Postfix

Vamos a utilizar una base de datos mariadb para dominios, usuarios y alias virtuales.

Creamos un directorio separado para almacenar toda la configuración de postfix relacionada con la base de datos:

mkdir /etc/postfix/mysql

Mapeo de Alias Virtuales

Creamos un archivo:

nano

/etc/postfix/mysql/virtual_alias_maps.cf

Y pegamos allí lo siguiente:

user = vimbadmin
password = password
hosts = 127.0.0.1
dbname = vimbadmin
query = SELECT goto FROM alias WHERE address = '%s' AND active = '1'

Mapeo de Dominios Virtuales

Creamos un archivo:

nano

/etc/postfix/mysql/virtual_domains_maps.cf

Y pegamos allí lo siguiente:

user = vimbadmin
password = password
hosts = 127.0.0.1
dbname = vimbadmin
query = SELECT domain FROM domain WHERE domain = '%s' AND backupmx = '0' AND active = '1'

Mapeo de Casillas de Correo (usuario) Virtuales

Creamos un archivo:

nano

/etc/postfix/mysql/virtual_mailbox_maps.cf

Y pegamos allí lo siguiente:

user = vimbadmin
password = password
hosts = 127.0.0.1
dbname = vimbadmin
query = SELECT maildir FROM mailbox WHERE username = '%s' AND active = '1'

El comando postmap crea o consulta las tablas de búsqueda de Postfix, o actualiza alguna existente. Ingresamos el siguiente comando para asegurarnos que Postfix puede consultar la tabla de dominios. Reemplazar midominio.com.ar con el primer valor almacenado. El comando debería devolver 1 si tiene éxito:

postmap -q midominio.com.ar mysql:/etc/postfix/mysql/virtual_domains_maps.cf

Probamos Postfix para verificar que puede obtener la primer dirección de correo de la base de datos. Reemplazar raul@midominio.com.ar con la primer dirección de correo registrada en la tabla. Deberíamos ver un 1 si tiene éxito:

postmap -q raul@midominio.com.ar mysql:/etc/postfix/mysql/virtual_mailbox_maps.cf

Por último verificamos que Postfix puede consultar la tabla de alias. Reemplazar alias-raul@midominio.com.ar con el primer valor de origen creado en la tabla. El comando debería arrojar el valor de destino para la fila:

postmap -q alias-raul@midominio.com.ar mysql:/etc/postfix/mysql/virtual_alias_maps.cf

Configuración de Dovecot

Dovecot es un servidor IMAP y POP. Además implementa seguridad/autenticación para IMAP/POP así como también SMTP (vía Postfix).

Usamos dovecot versión 2.3.4.1. Esto se puede verificar usando el comando:

dovecot –version

Un usuario de linux real – vmail

Los siguientes comandos crean un usuario y un grupo llamado vmail. Se trata de un usuario de linux que será propietario de los correos electrónicos de todo el mundo (No hay que entrar en pánico por este hecho…)

groupadd -g 5000 vmail
useradd -g vmail -u 5000 vmail -d /var/vmail -m

Reiniciamos postfix

service postfix restart

Dovecot está configurado de manera modular con archivos en

/etc/dovecot/conf.d/

que son incluidos desde

/etc/doveco

t

/dovecof.conf

.

A Efectos prácticos es preferible tener un solo archivo de configuración en lugar de varios, así que resguardamos una copia del original. Y creamos unos nuevo copiando la salida de

dovecot -n

a

dovecot.conf

:

# doveconf -n > /etc/dovecot/dovecot.conf.new
# mv /etc/dovecot/dovecot.conf /etc/dovecot/dovecot.conf.orig
# mv /etc/dovecot/dovecot.conf.new /etc/dovecot/dovecot.conf
# nano /etc/dovecot/dovecot.conf

Configurar la ubicación de almacenamiento de correo

mail_location = maildir:/var/vmail/%d/%n

Habilitamos los protocolos necesarios

nano /etc/dovecot/dovecot.conf
# Enable installed protocols
!include_try /usr/share/dovecot/protocols.d/*.protocol
protocols = imap pop3 lmtp sieve

Buscamos la linea

ssl = no

, y la eliminamos. Luego insertamos el siguiente bloque:

service imap-login {
 inet_listener imap {
 port = 0
 }
 inet_listener imaps {
 port = 993
 }
}
ssl = required
ssl_cert = </etc/apache2/md/domains/midominio.com.ar/pubcert.pem
ssl_key = </etc/apache2/md/domains/midominio.com.ar/privkey.pem
ssl_prefer_server_ciphers=yes
### Protocolos
ssl_protocols = !SSLv3 !TLSv1 !TLSv1.1 #Dovecot 2.2.x
ssl_min_protocol=TLSv1.2 #Dovecot 2.3.x o superior

Con esto forzamos el uso de TLS/SSL, especificamos nuestros certificados, deshabilitamos IMAP (definiendo el puerto igual a 0) y configuramos el servicio imap-login en el puerto 993 (IMAPS).

Configurar la autenticación

disable_plaintext_auth = no
auth_mechanisms = plain login

Finalmente agregamos soporte para autenticación basada en mariadb en la parte inferior:

passdb {
 driver = sql
 args = /etc/dovecot/dovecot-sql.conf.ext
}
userdb {
 driver = static
 args = uid=5000 gid=5000 home=/var/vmail/%d/%n allow_all_users=yes
}

El siguiente bloque permite la autenticación vía texto plano únicamente cuando TLS/SSL haya sido usado con anterioridad, además anexa el servicio de autenticación al socket que se encuentra en /private/auth.

service lmtp {
 unix_listener /var/spool/postfix/private/dovecot-lmtp {
 mode = 0600
 user = postfix
 group = postfix
 }
}
protocol lmtp {
 postmaster_address = administrador@midominio.com.ar
}

Configurar los parámetros mariadb en dovecot

nano /etc/dovecot/dovecot-sql.conf.ext

Pegar lo siguiente al final:

default_pass_scheme = SHA512-CRYPT
driver = mysql
connect = host=localhost dbname=vimbadmin user=vimbadmin password=password
password_query = \
 SELECT username AS user, password, \
 homedir AS userdb_home, uid AS userdb_uid, gid AS userdb_gid \
 FROM mailbox WHERE username = '%u'
# iterate_query = SELECT username AS user FROM mailbox

Resulta fundamental para el funcionamiento de nuestro sistema que se defina el esquema utilizado para almacenar las contraseñas en la base de datos, en este caso SHA512-CRYPT.2

Por otro lado, en toda la configuración relacionada al vínculo entre mariadb y dovecot puede ser necesario reemplazar la referencia al localhost por 127.0.0.1

Verificar configuración de dovecot

Nos aseguramos que contenga lo siguiente:

service auth {
 unix_listener /var/spool/postfix/private/auth {
 mode = 0666
 user = postfix
 group = postfix
 }
 unix_listener auth-userdb {
 mode = 0600
 user = vmail
 }
 user = dovecot
}
service auth-worker {
 user = vmail
}

Registro de Errores

Dovecot siempre registra un mensaje detallado del error en caso que algo salga mal. Estos mensajes pueden registrarse en un archivo diferente que los mensajes informativos. Podemos encontrar la ubicación tales archivos con:

doveadm log find

Para más detalles acerca del registro de errores, se recomienda ver los parámetros disponibles en la documentación de dovecot3.

Doveconf

Al hacer tantos cambios resulta fácil perderse. En esos casos se pueden listar los cambios hechos en toda la configuración de dovecot, para ello:

doveconf -n

De manera similar,

doveconf -a

muestra la configuración completa de dovecot (incluyendo los valores predeterminados).

Reiniciar dovecot

systemctl restart dovecot

ViMbAdmin – Administración del Servidor de Correo Virtual

ViMbAdmin tiene una estética agradable y usa PHP.

Instalación Composer

Dependencias necesarias

apt install curl php-cli php-mbstring git unzip

Descarga e instalación de Composer

cd ~
curl -sS https://getcomposer.org/installer -o composer-setup.php

Comprobamos que el instalador coincide con el hash SHA-384 para el último instalador que se encuentra en la página [Claves públicas de composer / Firmas][composer-sigs]. Copiamos el hash de esa página y lo guardamos como una variable de shell:

HASH=48e3236262b34d30969dca3c37281b3b4bbe3221bda826ac6a9a62d6444cdb0dcd0615698a5cbe587c3f0fe57a54d8f5

Ejecutamos el siguiente script PHP para verificar que el script de instalación es seguro de ejecutar:

php -r "if (hash_file('SHA384', 'composer-setup.php') === '$HASH') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"

Verás la siguiente salida:

Installer verified

Si ves que Instaler corrupt, tendrás que descargar el script de instalación de nuevo y comprobar que estás usando el hash correcto. A continuación, ejecuta el comando para verificar el instalador de nuevo. Una vez que tengas un instalador verificado, puedes continuar.

Para instalar composer globalmente, usa el siguiente comando que lo descargará e instalará como un comando para todo el sistema llamado composer, en /usr/local/bin:

php composer-setup.php --install-dir=/usr/local/bin --filename=composer

Verás lo siguiente:

All settings correct for using Composer
Downloading...
Composer (version 1.8.6) successfully installed to: /usr/local/bin/composer
Use it: php /usr/local/bin/composer

Para probar tu instalación, ejecuta:

composer

Y verás la salida que muestra la versión y los argumentos de composer, similar a esto:

 ______
 / ____/___ ____ ___ ____ ____ ________ _____
 / / / __ \/ __ `__ \/ __ \/ __ \/ ___/ _ \/ ___/
/ /___/ /_/ / / / / / / /_/ / /_/ (__ ) __/ /
\____/\____/_/ /_/ /_/ .___/\____/____/\___/_/
 /_/
Composer version 1.8.6 2019-06-11 15:03:05
...

Instalación ViMbAdmin v3

export INSTALL_PATH=/srv/vimbadmin
git clone https://github.com/opensolutions/ViMbAdmin.git $INSTALL_PATH
cd $INSTALL_PATH
composer install --prefer-dist --no-dev
chown -R www-data: $INSTALL_PATH/var

Pese a las recomendaciones, se efectuó la instalación como root y luego se cambió la propiedad del directorio vimbadmin a www-data, también se estableció el setgid

Creamos una base de datos y usuario en mariadb para vimbadmin, para ello ejecutamos lo siguiente en la consola de mariadb

CREATE DATABASE `vimbadmin`;
GRANT ALL ON `vimbadmin`.* TO `vimbadmin`@`localhost` IDENTIFIED BY 'password';
FLUSH PRIVILEGES;

Archivo de configuración de vimbadmin

cp $INSTALL_PATH/application/configs/application.ini.dist $INSTALL_PATH/application/configs/application.ini
nano $INSTALL_PATH/application/configs/application.ini
securitysalt = "superadmin-password"
defaults.mailbox.uid = 5000
defaults.mailbox.gid = 5000
defaults.mailbox.homedir = "/var/vmail/"
resources.doctrine2.connection.options.driver = 'pdo_mysql'
resources.doctrine2.connection.options.dbname = 'vimbadmin'
resources.doctrine2.connection.options.user = 'vimbadmin'
resources.doctrine2.connection.options.password = 'contraseña'
resources.doctrine2.connection.options.host = 'localhost'

Verificamos que los datos de acceso a mariadb sean los correctos en la configuración anterior.

Entorno de aplicación

Como mínimo, debe copiar este archivo .htaccess de ejemplo incluido.

cp $INSTALL_PATH/public/.htaccess.dist $INSTALL_PATH/public/.htaccess

Modificamos el archivo, de modo que la última línea se vea así:

RewriteRule ^.*$ /index.php [NC,L]

Crear las tablas mariadb

Lo siguiente creará las tablas mariadb para lo cual ya hemos configurado postfix y dovecot.

./bin/doctrine2-cli.php orm:schema-tool:create

Configuración de Apache

En este caso vamos a definir un subdominio

 <VirtualHost vma.midominio.com.ar:80>
 ServerAdmin administrador@midominio.com.ar
 ServerName vma.midominio.com.ar
 ServerAlias vma.midominio.com.ar
 DocumentRoot /srv/vimbadmin/public
 <Directory /srv/vimbadmin/public>
 Options FollowSymLinks
 AllowOverride FileInfo
 Require all granted
 </Directory>
 ErrorLog ${APACHE_LOG_DIR}/error_vma.log
 CustomLog ${APACHE_LOG_DIR}/access_vma.log combined
 </VirtualHost>

A partir de aquí se puede visitar vma.midominio.com.ar y crear una cuenta de administrador ViMbAdmin. Por favor, notar que esta cuenta ViMbAdmin no es una cuenta virtual de correo electrónico.

Es posible agregar dominio, usuarios virtuales de correo electrónico luego de ingresar a vma.midominio.com.ar usando la cuenta ViMbAdmin.

Probando la configuración

Local

La herramienta cliente de OpenSSL ofrece una manera de conectar y diagnosticar servidores:

openssl s_client -starttls smtp -connect midominio.com.ar:587
openssl s_client -connect midominio.com.ar:993

ambos comandos deben arrojar

Verify return code: 0 (ok)

como una de las últimas líneas.

Servidor

En una nueva terminal, nos conectamos al servidor

tail -f /var/log/mail.log

para verificar si postfix y dovecot están (re-)arrancando sin inconvenientes:

service postfix restart
service dovecot restart

Luego verificamos los puertos 25, 587 y 993 aparecen en la columna ‘Local Address’:

netstat -ltnp

Configuración de MUA (Mail User Agent) ej. Mozilla Thunderbird

Creamos una nueva cuenta con la siguiente configuración:

Correo entrante IMAP:

Nombre de host: midominio.com.ar
Puerto: 993
SSL: SSL/TLS
Autenticación: Clave normal
Nombre de usuario: administrador@midominio.com.ar

Correo saliente SMTP:

Nombre de host: midominio.com.ar
Puerto: 587
SSL: STARTTLS
Autenticación: Clave normal
Nombre de usuario: administrador@midominio.com.ar

Configuración automática de los clientes de correo para IMAP/SMTP

Algunos clientes de correo emplean un sistema denominado “Autodiscover” para averiguar cuáles son los parámetros de uso imap/smtp.

Puedes configurar esto si quieres, básicamente requiere un subdominio y un registro SRV.

Puedes agregar el registro SRV en cualquier dominio para el que quieras usar esta configuración.

Si tienes un certificado SSL global en dovecot para tu nombre de host, esta sería una buena forma de asegurarte de que los clientes utilizan el valor correcto, para que no obtengan errores de certificado SSL.

Supongamos que vas a tener a tus clientes con

dominio.com.ar

conectados a

correo.dominio.com.ar

tanto para IMAP como para SMTP.

Creamos un subdominio llamado

autodiscover.dominio.com.ar

para almacenar el XML.

Configuramos un registro SRV en la zona DNS de dominio.com.ar:

_autodiscover._tcp.dominio.com.ar. 3600 IN SRV 10 10 443 autodiscover.dominio.com.ar.

Luego, creamos el subdominio autodiscover.dominio.com.ar y añadimos el siguiente código en un archivo llamado autodiscover.php:

<?php
//get raw POST data so we can extract the email address
$data = file_get_contents("php://input");
preg_match("/\<EMailAddress\>(.*?)\<\/EMailAddress\>/", $data, $matches);
//set Content-Type
header("Content-Type: application/xml");
echo '<?xml version="1.0" encoding="utf-8" ?>'; ?>
<Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/responseschema/2006">
 <Response xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a">
 <Account>
 <AccountType>email</AccountType>
 <Action>settings</Action>
 <Protocol>
 <Type>IMAP</Type>
 <Server>correo.dominio.com.ar</Server>
 <Port>993</Port>
 <DomainRequired>off</DomainRequired>
 <LoginName><?php echo $matches[1]; ?></LoginName>
 <SPA>off</SPA>
 <SSL>on</SSL>
 <AuthRequired>on</AuthRequired>
 </Protocol>
 <Protocol>
 <Type>SMTP</Type>
 <Server>correo.dominio.com.ar</Server>
 <Port>587</Port>
 <DomainRequired>off</DomainRequired>
 <LoginName><?php echo $matches[1]; ?></LoginName>
 <SPA>off</SPA>
 <Encryption>TLS</Encryption>
 <AuthRequired>on</AuthRequired>
 <UsePOPAuth>off</UsePOPAuth>
 <SMTPLast>off</SMTPLast>
 </Protocol>
 </Account>
 </Response>
</Autodiscover>

Ten en cuenta que el registro SRV utiliza el puerto 443 para autodiscover.dominio.com.ar, así que asegúrate de tener una configuración de certificado válida para este subdominio.

Puedes probar yendo a https://autodiscover.dominio.com.ar para asegurarte de que tienes un candado verde. El script busca la entrada XML en la etiqueta <EMailAddress> para insertar en el campo de resultado <LoginName>.

Si es necesario, puedes configurar SMTP para usar el puerto 465, pero tendrías que cambiar la <Encriptación> de TLS a SSL, ya que el protocolo es diferente en el 465.

El puerto 587 requiere smtp-auth pero se salta algunas comprobaciones de spam y usa STARTTLS para habilitar SSL. El puerto 465 es SSL completo pero los clientes pueden tener problemas para enviar si su IP/rango está en una RBL.

Por último, necesitaremos configurar un archivo .htaccess para que cualquier petición al subdominio autodiscover.dominio.com.ar resulte en que se llame al autodiscover.php. En el DocumentRoot del subdominio, añade este código:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ autodiscover.php [NC,L]
Thunderbird

A diferencia de la auto-detección de Microsoft, Thunderbird hace un intento directo a

http://autoconfig.dominio.com.ar/mail/config-v1.1.xml?emailaddress=user@dominio.com.ar

Esto puede ser manejado creando un subdominio llamado “autoconfig”, y en el área web de este subdominio, crear una carpeta llamada “mail”, y dentro de este directorio “mail”, crear un archivo llamado config-v1.1.xml. Una ruta de ejemplo podría ser similar a:

/domains/dominio.com.ar/public_html/autoconfig/mail/config-v1.1.xml

Dentro de este archivo, colocamos el código:

<clientConfig version="1.1">
 <emailProvider id="dominio.com.ar">
 <domain>dominio.com.ar</domain>
 <displayName>%EMAILADDRESS%</displayName>
 <incomingServer type="imap">
 <hostname>mail.dominio.com.ar</hostname>
 <port>993</port>
 <socketType>SSL</socketType>
 <username>%EMAILADDRESS%</username>
 <authentication>password-cleartext</authentication>
 </incomingServer>
 <outgoingServer type="smtp">
 <hostname>smtp.dominio.com.ar</hostname>
 <port>587</port>
 <socketType>STARTTLS</socketType>
 <username>%EMAILADDRESS%</username>
 <authentication>password-cleartext</authentication>
 </outgoingServer>
 </emailProvider>
</clientConfig>

Instalación de Roundcube

Creamos un directorio y nos ubicamos allí:

mkdir /srv/roundcube
cd /srv/roundcube

Descargamos y descomprimimos el tar.gz de RoundCube:

wget https://github.com/roundcube/roundcubemail/releases/download/1.4.10/roundcubemail-1.4.10-complete.tar.gz
tar xfz roundcubemail-1.4.10-complete.tar.gz

Los archivos de RoundCube ahora están en la carpeta /srv/roundcube/roundcubemail-1.4.10. El próximo paso es moverlos un nivel hacia arriba a /srv/roundcube.

mv roundcubemail-1.4.10/* .
mv roundcubemail-1.4.10/.htaccess .

El punto al final de ambos comandos es requerida y parte de la sentencia, ¡no lo olvides! Eliminamos el directorio y el archivo tar.gz.

rmdir roundcubemail-1.4.10
rm roundcubemail-1.4.10-complete.tar.gz

Cambiamos la propiedad de todos los archivos al usuario que está utilizando el Apache.

chown -R www-data:www-data /srv/roundcube

Instalamos la base de datos de RoundCube

Roundcube requiere una base de datos para almacenar la configuración de la casilla de correo, contactos, etc. Vamos a crear una base de datos con el nombre “roundcubemail” y un usuario con el mismo nombre “roundcube” en MariaDB.

Ingresamos a la consola de MariaDB con el siguiente comando:

mysql --defaults-file=/etc/mysql/debian.cnf

Luego ejecutamos los siguientes comandos para crear la base de datos y el usuario. Reemplazando “clavesecreta” con la contraseña que prefieras.

CREATE DATABASE roundcubemail;
GRANT ALL PRIVILEGES ON roundcubemail.* TO roundcube@localhost IDENTIFIED BY 'clavesecreta';
FLUSH PRIVILEGES;
QUIT

Ahora importaremos las tablas de RoundCube desde el archivo mysql.initial.sql en nuestra nueva base de datos. Para ello ejecutamos el comando en la consola de Linux:

mysql --defaults-file=/etc/mysql/debian.cnf roundcubemail < /srv/roundcube/SQL/mysql.initial.sql

Configure RoundCube and Apache

En este paso, vamos a configurar los detalles de la base de datos en RoundCube y también a agregar un archivo de configuración en Apache.

Ejecutamos el siguiente comando para crear un nuevo archivo config.inc.php basado en la configuración de ejemplo y lo abrimos.

cd /srv/roundcube/config
cp -pf config.inc.php.sample config.inc.php
nano config.inc.php

Hallar la linea de configuración de la base de datos que comienza con $config[‘db_dsnw’] y reemplazarla con lo siguiente:

$config['db_dsnw'] = 'mysql://roundcube:clavesecreta@localhost/roundcubemail';

Luego modificamos la configuración predeterminada.

// The IMAP host chosen to perform the log-in.
$config['default_host'] = 'ssl://correo.midominio.com.ar';
// TCP port used for IMAP connections
$config['default_port'] = 993;
$config['imap_auth_type'] = PLAIN;
// IMAP socket context options
$config['imap_conn_options'] = array(
 'ssl' => array(
 'peer_name' => 'correo.midominio.com.ar',
 'verify_peer_name' => true,
 'capath' => '/usr/lib/ssl/certs/',
 'local_cert' => '/etc/letsencrypt/live/correo.midominio.com.ar/fullchain.pem',
 'verify_peer' => true,
 ),
);
// SMTP server host (for sending mails).
$config['smtp_server'] = 'tls://correo.midominio.com.ar';
// SMTP port (default is 25; use 587 for STARTTLS or 465 for the
// deprecated SSL over SMTP (aka SMTPS))
$config['smtp_port'] = 587;
// SMTP socket context options
$config['smtp_conn_options'] = array(
 'ssl' => array(
 'peer_name' => 'correo.midominio.com.ar',
 'verify_peer_name' => true,
 'capath' => '/usr/lib/ssl/certs/',
 'local_cert' => '/etc/letsencrypt/live/correo.midominio.com.ar/fullchain.pem',
 'verify_peer' => true,
 ),
);
// Name your service. This is displayed on the login screen and in the window t$
$config['product_name'] = 'Correo de Mi Dominio';
// List of active plugins (in plugins/ directory)
$config['plugins'] = array(
 'password',
 ...
);

Dado que agregamos el plugin para cambiar la contraseña, también es necesario configurarlo. Lo hacemos en plugins/password/config.inc.php

/plugins/password/config.inc.php
$config['password_algorithm'] = 'sha512-crypt';
$config['password_dovecotpw'] = '/usr/local/sbin/doveadm pw'; // for dovecot-2.x
$config['password_dovecotpw_method'] = 'SHA512-CRYPT';
$config['password_db_dsn'] = 'mysql://vimbadmin:contraseña@localhost/vimbadmin';
$config['password_query'] = 'UPDATE mailbox SET password=%c,modified=NOW() WHERE username=%u ';
$config['password_crypt_hash'] = 'sha512';

Ahora es necesario configurar Apache. Creamos un nuevo archivo de configuración roundcube.conf en /etc/apache2/sites-available/.

nano /etc/apache2/sites-available/roundcube.conf

Agregamos las siguientes lineas y lo guardamos.

<VirtualHost correo.dominio.com.ar:80>
 ServerAdmin administrador@midominio.com.ar
 ServerName correo.midominio.com.ar
 ServerAlias correo.midominio.com.ar
 DocumentRoot /srv/roundcube
 <Directory />
 Options FollowSymLinks
 AllowOverride None
 </Directory>
 <Directory /srv/roundcube>
 Options +FollowSymLinks
 # AddDefaultCharset UTF-8
 AddType text/x-component .htc
 <IfModule mod_php5.c>
 AddType application/x-httpd-php .php
 php_flag display_errors Off
 php_flag log_errors On
 # php_value error_log logs/errors
 php_value upload_max_filesize 10M
 php_value post_max_size 12M
 php_value memory_limit 64M
 php_flag zlib.output_compression Off
 php_flag magic_quotes_gpc Off
 php_flag magic_quotes_runtime Off
 php_flag zend.ze1_compatibility_mode Off
 php_flag suhosin.session.encrypt Off
 #php_value session.cookie_path /
 php_flag session.auto_start Off
 php_value session.gc_maxlifetime 21600
 php_value session.gc_divisor 500
 php_value session.gc_probability 1
 </IfModule>
 <IfModule mod_rewrite.c>
 RewriteEngine On
 RewriteRule ^favicon\.ico$ skins/larry/images/favicon.ico
 # security rules:
 # - deny access to files not containing a dot or starting with a dot
 # in all locations except installer directory
 RewriteRule ^(?!installer)(\.?[^\.]+)$ - [F]
 # - deny access to some locations
 RewriteRule ^/?(\.git|\.tx|SQL|bin|config|logs|temp|tests|program\/(include|lib|localization|steps)) - [F]
 # - deny access to some documentation files
 RewriteRule /?(README\.md|composer\.json-dist|composer\.json|package\.xml)$ - [F]
 </IfModule>
 <IfModule mod_deflate.c>
 SetOutputFilter DEFLATE
 </IfModule>
 <IfModule mod_expires.c>
 ExpiresActive On
 ExpiresDefault "access plus 1 month"
 </IfModule>
 FileETag MTime Size
 <IfModule mod_autoindex.c>
 Options -Indexes
 </ifModule>
 AllowOverride None
 Require all granted
 </Directory>
 <Directory /srv/roundcube/plugins/enigma/home>
 Options -FollowSymLinks
 AllowOverride None
 Require all denied
 </Directory>
 <Directory /srv/roundcube/config>
 Options -FollowSymLinks
 AllowOverride None
 Require all denied
 </Directory>
 <Directory /srv/roundcube/temp>
 Options -FollowSymLinks
 AllowOverride None
 Require all denied
 </Directory>
 <Directory /srv/roundcube/logs>
 Options -FollowSymLinks
 AllowOverride None
 Require all denied
 </Directory>
</VirtualHost>

Habilitamos la configuración y recargamos apache:

a2site roundcube
systemctl reload apache2

RoundCube estará disponible desde correo.midominio.com.ar.

DKIM, SPF y DMARC

DKIM, SPF y DMARC son estándares que habilitan diferentes aspectos de la autenticación de correo electrónico. Abordan cuestiones complementarias.

  • SPF permite a los remitentes definir qué direcciones IP pueden enviar correo para un dominio determinado.
  • DKIM proporciona una clave de cifrado y una firma digital que verifica que un mensaje de correo electrónico no fue falsificado o alterado.
  • DMARC unifica los mecanismos de autenticación de SPF y DKIM en un marco común y permite a los propietarios de los dominios declarar cómo desean que se maneje el correo electrónico de ese dominio si no pasa una prueba de autorización.

Instalación Básica

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

Agregar el usuario

postfix

al grupo

opendkim

de modo que Postfix pueda acceder al socket de OpenDKIM cuando lo necesite:

adduser postfix opendkim

Configurar SPF

Agregar registros SPF al DNS

midominio.com.ar.IN TXT "v=spf1 mx a ip4:170.210.45.130 ip6:2800:110:44:6260::130 a:correo.midominio.com.ar -all"
  • La etiqueta v=spf1 es necesaria y tiene que ser la primera.
  • La última etiqueta, -all, indica que el correo de nuestro dominio solo debería proceder de los servidores identificados en la cadena SPF.
  • mx señala a todos los hosts listados en los registros MX de nuestro dominio.
  • La etiqueta a permite identificar un host específico por nombre o dirección IP, con esto podemos definir que hosts están autorizados.

Agregar el agente de directivas SPF a Postfix

El agente de directivas SPF basado en Python agrega la verificación de directivas SPF a Postfix. El registro SPF para el dominio del remitente del correo entrante será verificado y, si existe, el correo será manejado en consecuencia.

  1. Al usar SpamAssassin, puede que querramos editar/etc/postfix-policyd-spf-python/policyd-spf.confpara cambiar la configuración deHELO_reject

    y

    Mail_From_reject

    a

    False

    . Esto hará que el agente de directivas SPF ejecute sus pruebas y agregue un mensaje al encabezado con los resultados y no rechace ningún mensaje. Esto también resulta útil si queremos ver los resultados del procesamiento de no aplicarlos al procesamiento de coreo. De otro modo, basta continuar con la configuración estándar.

  2. Editamos/etc/postfix/master.cfy agregamos lo siguiente al final:
    policyd-spf unix - n n - 0 spawn user=policyd-spf argv=/usr/bin/policyd-spf
  3. Abrir/etc/postfix/main.cfy agregar esta entrada para incrementar el timeout del agente de directivas de Postfix, con lo cual evitaremos que Postfix aborte al agente si las transacciones se enlentecen:
policyd-spf_time_limit = 3600
  1. Editar la entradasmtpd_recipient_restrictionspara agregar check_policy_service:
    smtpd_recipient_restrictions =
     ...
     reject_unauth_destination,
     check_policy_service unix:private/policyd-spf,
     ...

    Debemos asegurarnos de agregar la entrada

    check_policy_service

    después de

    reject_unauth_destination

    para evitar que nuestro sistema se convierta en un relay abierto. Si

    reject_unauth_destination

    es la última entrada en nuestra lista de restricciones, es necesario agregar una coma a continuación de ella y omitir la coma al final de

    check_policy_service

    .

  2. Reiniciar Postfix
    systemctl restart postfix

Podemos verificar el funcionamiento del agente de directivas buscando en los encabezados originales en del correo entrante el encabezado de resultados SPF. El encabezado que el agente de directivas agrega a los mensajes debería ser similar a este:

Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=127.0.0.1; helo=mail.midominio.com.ar; envelope-from=text@midominio.com.ar; receiver=tknarr@silverglass.org

Esto indica una verificación exitosa contra las directivas SPF del dominio remitente. Si cambiamos las directivas definidas en el paso 1 para que no rechace el correo que no pasa la validación SPF, podriamos ver resultados fallidos en este encabezado. Este encabezado no aparecerá en correo saliente o local.

El agente de directivas SPF también registra su actividad en

/var/log/mail.log

. Allí veremos mensajes como este:

Jan 7 06:24:44 arachnae policyd-spf[21065]: None; identity=helo; client-ip=127.0.0.1; helo=mail.midominio.com.ar; envelope-from=test@midominio.com.ar; receiver=tknarr@silverglass.org
Jan 7 06:24:44 arachnae policyd-spf[21065]: Pass; identity=mailfrom; client-ip=127.0.0.1; helo=mail.midominio.com.ar; envelope-from=test@midominio.com.ar; receiver=tknarr@silverglass.org

El primer mensaje es una verificación del comando HELO, en este caso indicando que no existe información SPF alguna que coincida con el HELO (lo cual está perfectamente bien). El segundo mensaje es una verificación contra la dirección From, e indica que pasó la verificación y procede de uno de los servidores de envío que el servidor del dominio remitente ha informado que se encuentra habilitado a enviar correo para ese dominio.

Consideraciones:

Existe un bug en las versiones de Bind9 incluidas en Debian por el cual es posible que tengamos mensajes como este en el log:

found SPF/TXT record but no SPF/SPF record found, add matching type SPF record

A partir de 2014 los registros SPF fueron ‘deprecados’ y fueron reemplazados por registros TXT con la información inherente a SPF.

No obstante, habiendo seguido los pasos para configurar el registro SPF en nuestro DNS, el servidor de correo pasará las validaciones.

Configurar OpenDkim

Esto implica configurar el paquete OpenDKIM, anexarlo a Postfix, y agregar un registro al DNS.

El archivo principal de configuración de OpenDKIM

/etc/opendkim.conf

debe verse así:

# Log to syslog
Syslogyes
# Required to use local socket with MTAs that access the socket as a non-
# privileged user (e.g. Postfix)
UMask002
# OpenDKIM user
# Remember to add user postfix to group opendkim
UserIDopendkim
# Socket smtp://localhost
Socketinet:12301@localhost
# Map domains in From addresses to keys used to sign messages
KeyTable/etc/opendkim/keytable
SigningTablerefile:/etc/opendkim/signingtable
# Hosts to ignore when verifying signatures
ExternalIgnoreListrefile:/etc/opendkim/trustedhosts
InternalHostsrefile:/etc/opendkim/trustedhosts
Selectorcorreo
Canonicalizationrelaxed/simple
Modesv
SubDomainsno
AutoRestartyes
AutoRestartRate10/1M
Backgroundyes
DNSTimeout5
SignatureAlgorithmrsa-sha256
OversignHeadersFrom

Aquí el dato clave es el valor que asignemos al

Selector

Debemos asegurarnos que los permisos del archivo se definieron correctamente:

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

Creamos los directorios donde se alojarán los archivos de datos de OpenDKIM, asignamos la propiedad al usuario opendkim, y restringimos los permisos de archivo:

mkdir /etc/opendkim
mkdir /etc/opendkim/keys
chown -R opendkim:opendkim /etc/opendkim
chmod go-rw /etc/opendkim/keys

Creamos la tabla de firmas

/etc/

open

dkim/signingtable

. Debe contener una línea por cada dominio para el cual gestionamos correo. Y cada una de ellas debería verse así:

*@midominio.com.ar correo._domainkey.midominio.com.ar

El archivo signingtable le indica a OpenDKIM como usar tus llaves, que remitentes deberían usar cuales selectores para sus firmas. En el ejemplo anterior, estamos señalando que todos (*) quienes envían correo desde “midominio.com.ar” deberían usar el selector llamado “correo.” Es importante notar que el comodín * solamente funcionará si la opción SigningTable usa el prefijo refile: antes del nombre de archivo.

Creamos la tabla de llaves

/etc/

open

dkim/keytable

. Debe tener una línea por cada dominio en la tabla de firmas. Cada linea debería verse así:

correo._domainkey.midominio.com.ar midominio.com.ar:correo:/etc/opendkim/keys/correo.private

El primer campo conecta las tablas

signing

y

key

. Vale aclarar que tanto la tabla

signing

como la tabla

key

pueden estar tranquilamente en el

/etc/opendkim

, solo es cuestión de preferencias.

El segundo campo está dividido en 3 secciones separadas por ‘:’.

    • La primera sección es el nombre de dominio para el cual la llave es usada.
    • La segunda sección es el selector usado al buscar registros en el DNS. Fue definido en/etc/opendkim.conf
    • La tercera sección identifica al archivo que contiene la llave para el dominio.

Creamos el archivo de hosts de confianza

/etc/

open

dkim/trustedhosts

. Al igual que las tablas, también podría estar en

/etc/opendkim

. Su contenido debe ser:

127.0.0.1
localhost
170.210.45.130
2800:110:44:6260::130
*.midominio.com.ar

Generamos las llaves para cada dominio:

opendkim-genkey -b 2048 -h sha256 -r -s correo -d midominio.com.ar -v

Esto generará dos archivos, correo.private con la llave y correo.txt con el registro TXT que tendremos que agregar al DNS

Debemos asegurarnos que el directorio

/etc/opendkim/

keys

solamente sea accesible por el propietario:

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

Conectamos el milter a Postfix:

nano /etc/default/opendkim

Añadimos la siguiente línea, editamos el número de puerto sólo si se utiliza uno personalizado:

SOCKET="inet:12301@localhost"

Verificamos que OpenDKIM se inicia correctamente:

systemctl restart opendkim

No debería haber mensajes de error, pero si los hay, así comienza la diversión:

systemctl status -l opendkim

Configurar el DNS

Al igual que SPF, DKIM emplea registros TXT para mantener la información acerca de la llave para cada dominio. Es necesario crear un registro TXT para el host correo._domainkey para cada dominio por el que gestione correo. Su valor puede ser encontrado en el archivo correo.txt para cada dominio. Estos archivos se ven así:

correo._domainkey IN TXT ( "v=DKIM1; k=rsa; "
 "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu5oIUrFDWZK7F4thFxpZa2or6jBEX3cSL6b2TJdPkO5iNn9vHNXhNX31nOefN8FksX94YbLJ8NHcFPbaZTW8R2HthYxRaCyqodxlLHibg8aHdfa+bxKeiI/xABRuAM0WG0JEDSyakMFqIO40ghj/h7DUc/4OXNdeQhrKDTlgf2bd+FjpJ3bNAFcMYa3Oeju33b2Tp+PdtqIwXRZksfuXh7m30kuyavp3Uaso145DRBaJZA55lNxmHWMgMjO+YjNeuR6j4oQqyGwz"
 "PaVcSdOG8Js2mXt+J3Hr+nNmJGxZUUW4Uw5ws08wT9opRgSpn+ThX2d1AgQePpGrWOamC3PdcwIDAQAB" ) ; ----- DKIM key correo for midominio.com.ar

Copiamos todo y pegamos ese valor en nuestro archivo de zona de Bind. Luego de algunos retoques, debería verse así:

correo._domainkey.midominio.com.ar. IN TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu5oIUrFDWZK7F4thFxpZa2or6jBEX3cSL6b2TJdPkO5iNn9vHNXhNX31nOefN8FksX94YbLJ8NHcFPbaZTW8R2HthYxRaCyqodxlLHibg8aHdfa+bxKeiI/xABRuAM0WG0JEDSyakMFqIO40ghj/h7DUc/4OXNdeQhrKDTlgf2bd+FjpJ3bNAFcMYa3Oeju33b2Tp+PdtqIwXRZksfuXh7m30kuyavp3Uaso145DRBaJZA55lNxmHWMgMjO+YjNeuR6j4oQqyGwzPaVcSdOG8Js2mXt+J3Hr+nNmJGxZUUW4Uw5ws08wT9opRgSpn+ThX2d1AgQePpGrWOamC3PdcwIDAQAB"

Es necesario repetir esto para cada dominio para el cual gestionemos correo, usando la información del archivo

.txt

para ese dominio.

Probamos la configuración

Para probar las el correcto firmado y verificación de las llaves usamos:

opendkim-testkey -d midominio.com.ar -s correo

Si todo está bien no deberíamos ver ninguna salida. Para tener más información, agregamos

-vvv

al final del comando. Eso produce una salida detallada. El último mensaje debería ser “key OK”. Justo antes de eso podríamos ver un mensaje “key not secure”. Eso es normal y no es señal de error, se debe a que la DNSSEC no está habilitada en su nombre de dominio. Se trata de un estándar de seguridad para la consulta segura del DNS. La mayoría de los nombres de dominio no tienen habilitada la DNSSEC.

Vinculamos OpenDKIM a Postfix

Definimos el socket correcto para Postfix en

/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=""
#
# Uncomment to specify an alternate socket
# Note that setting this will override any Socket value in opendkim.conf
#SOCKET="local:/var/run/opendkim/opendkim.sock" # default
#SOCKET="inet:54321" # listen on all interfaces on port 54321
#SOCKET="inet:12345@localhost" # listen on loopback on port 12345
#SOCKET="inet:12345@192.0.2.1" # listen on 192.0.2.1 on port 12345
SOCKET="inet:8891@localhost"

Editamos

/etc/postfix/main.cf

y agregamos una sección para activar el procesamiento de correo a través del demonio OpenDKIM:

# OpenDKIM
milter_default_action = accept
milter_protocol = 6
smtpd_milters = inet:localhost:8891
non_smtpd_milters = $smtpd_milters

Consideraciones:

El formato del smtpd:milter (inet:localhost:8891) difiere de la configuración de OpenDKIM (inet:8891@localhost). Invertir el orden host / puerto en uno u otro puede acarrear varias horas de diversión.

La línea lógica que define la configuración de OpenDKIM en Postfix no puede estar identada, es decir que cada línea de configuración debe comenzar en la columna cero.

Si bien podemos colocar la configuración relativa a postfix en cualquier lugar del archivo. Lo usual es hacerlo a continuación de la entrada

smtpd_recipient_restrictions

.

Reiniciamos el demonio OpenDKIM de modo que defina el socket correcto para Postfix:

systemctl restart opendkim

Reiniciamos Postfix para que comience a utilizar OpenDKIM al procesar correo:

systemctl restart postfix

Verificando que todo funciona

Existen varios servicios en línea para verificar la configuración de nuestro sistema de correo, pero una de las maneras más sencillas de hacerlo es enviar un mensaje a una dirección @gmail.com. En esa cuenta de GMail abrimos el correo enviado y le indicamos “Mostrar original”, veremos algo como esto:

 

ID del mensaje <af03eed8efab9c95ab3fc22fbff9d1d9@midominio.com.ar>
Creado el: 8 de septiembre de 2017, 15:07 (Entregado después de 5 segundos)
De: drodriguez@midominio.com.ar
Para: drodriguez@unau.edu.ar
Asunto: isso é só uma prova
SPF: PASS con el IP 170.210.45.130 Más información
DKIM: PASS con el dominio midominio.com.ar Más información
DMARC: PASS Más información

 

Configurar OpenDKIM para múltiples dominios

Para hacerlo debes añadir los demás dominios en los archivos signingtable, keytable y trustedhosts.

A continuación, genera las claves DKIM privada/pública y añade la clave pública DKIM en el DNS para los otros dominios. Reinicia OpenDKIM y ya está.

Opcional: Configurar ADSP (Set up Author Domain Signing Practices)

Como ítem final, podemos agregar una política ADSP a nuestro dominio indicando que todos los correos deben contar con una firma DKIM. Como siempre, lo hacemos agregando un registro TXT:

_adsp._domainkey.midominio.com.ar.IN TXT "dkim=all;"

Esto no es necesario, pero hacerlo dificulta que cualquiera pueda hacer pasar un correo como de nuestro dominio porque los servidores de destino verán la ausencia de la firma DKIM y rechazarán el mensaje.

Configurar DMARC (Domain Message Authentication, Reporting & Conformance)

El registro DNS DMARC puede ser agregado para indicar a los servidores de correo que pensamos deben hacer cuando mensajes, alegando ser de nuestro dominio, fallan la validación con SPF y/o DKIM. DMARC solo debería ser definido si tenemos SPF y DKIM configurados y funcionando adecuadamente. Si agregamos el registro DMARC sin tener SPF y DKIM en su lugar, los mensajes de nuestro dominio fallarán la validación lo cual causará que sean descartados o relegados a la carpeta de spam.

El registro DMARC es un registro TXT para el host

_dmarc

en nuestro dominio conteniendo los siguientes valores recomendados:

v=DMARC1;p=reject;sp=none;adkim=r;aspf=r

Esto solicita a los servidores de correo que coloquen en cuarentena cualquier mensaje que falle las verificaciones SPF o DKIM. No se solicita informe. Si bien muy pocos servidores implementan el software para generar informes sobren mensajes fallidos, podría ser innecesario solicitarlos. Pero como nunca sabemos lo que nos puede deparar el futuro, agregamos los parámetros necesarios:

_dmarc.midominio.com.ar.IN TXT "v=DMARC1;p=reject;sp=none;pct=100;ruf=mailto:administrador@midominio.com.ar;rua=mailto:administrador@midominio.com.ar"

Control de SPAM

El filtro de spam se hace en dos etapas:

  1. El spam es identificado al ingreso al sistema.
  2. El spam es entregado en una carpeta dedicada en la cuenta del usuario.

Estas etapas son cosas separadas. Spamassassin identifica y etiqueta al spam mientras que el plugin Sieve de Dovecot permite colocarlo automáticamente en la carpeta spam del usuario. Primero identificaremos el spam.

Verificar la aceptación de correo

Agregamos un nuevo conjunto de verificaciones a

/etc/postfix/main.cf

para reducir la cantidad de correo que acepta el sistema

### Para descartar correo mal formado
smtpd_helo_required = yes
strict_rfc821_envelopes = yes
disable_vrfy_command = yes
unknown_address_reject_code = 554
unknown_hostname_reject_code = 554
unknown_client_reject_code = 554
smtpd_helo_restrictions =
 permit_mynetworks,
 reject_invalid_hostname,
## Al modificar sender_checks, el archivo debe ser regenerado
## usando postmap <archivo>, para generar una Berkeley DB
 regexp:/etc/postfix/helo.regexp,
 permit
smtpd_recipient_restrictions =
 check_client_access hash:/etc/postfix/helo_client_exceptions,
 check_sender_access hash:/etc/postfix/sender_checks,
 reject_invalid_hostname,
## Puede provocar problemas con Auth SMTP
 reject_non_fqdn_hostname,
##################################
 reject_non_fqdn_sender,
 reject_non_fqdn_recipient,
 reject_unknown_sender_domain,
 reject_unknown_recipient_domain,
 permit_mynetworks,
 reject_unauth_destination,
## Agregamos excepciones RBL, al hacer cambios el archivo debe ser regenerado usando
## postmap <archivo>, para generar una Berkeley DB
 check_client_access hash:/etc/postfix/rbl_client_exceptions,
 reject_rbl_client cbl.abuseat.org,
 reject_rbl_client sbl-xbl.spamhaus.org,
 reject_rbl_client bl.spamcop.net,
 reject_rhsbl_sender dsn.rfc-ignorant.org
 permit

Ahora necesitamos crear dos archivos:

El primero

/etc/postfix/helo.regexp

que contendrá:

/^subdomain\.host\.com$/ 550 No uses mi nombre de host
/^xxx\.yyy\.zzz\.xxx$/ 550 No uses mi dirección IP
/^\[xxx\.yyy\.zzz\.xxx\]$/ 550 No uses mi dirección IP
/^[0-9.]+$/ 550 Tu software no cumple con RFC 2821
/^[0-9]+(\.[0-9]+){3}$/ 550 Tu software no cumple con RFC 2821

Esto por sí solo hará que los spammers que intentan enviar el comando helo y hacerse pasar por el servidor que recibe el correo por IP o por nombre de host, así como rechazar algunos de los correos que no cumplen con la RFC 2821.

Luego necesitamos crear

/etc/postfix/helo_client_exceptions

:

# Estas direcciones IP pueden evitar los controles fqdn
# Algún comentario para identificar el IP de abajo
www.xxx.yyy.zzz OK

Este archivo es necesario en caso un servidor de correo que se comporta mal no puede enviar el helo correcto y tienes que permitir que se acepte el correo de esa fuente. Cosas como dispositivos independientes, cámaras de CCTV son pobres en el cumplimiento de las normas, por lo que podría tener que hacer una excepción para esto.

Antes de que cualquier cambio en este archivo sea utilizable, hay que ejecutar

postmap /etc/postfix/helo_client_exceptions

Esto creará un archivo llamado

/etc/postfix/helo_client_exceptions.db

Más adelante tenemos

/etc/postfix/sender_checks

que permite evitar varios controles FQDN y habilitar un remitente determinado. Esto resulta particularmente útil cuando si una empresa tiene un dominio.com.ar para trabajar pero el correo funcionar en interno.dominio.com.ar y no hay configuración DNS para interno.dominio.com.ar, estos es genial para la seguridad pero los DNS externos desconocen la existencia de tal estructura interna y, a consecuencia de ello, postfix rechazará interno.dominio.com.ar.

usuario@dominio.com.ar REJECT
usuario@interno.dominio.com.ar OK

Una vez modificado el archivo es necesario crear una Berkely DB usando:

postmap /etc/postfix/sender_checks

Luego tenemos las verificaciones RBL. Existen muchos sitios dedicados a ello (en el ejemplo hay 4) que brindan listas actualizadas constantemente con IPs y nombres de host que los spammers utilizan para enviar correo. Cada IP que intenta enviar correo a nuestro servidor de correo será verificado contra esas listas y si la IP no está listada en las RBLs, el servidor aceptará el correo. Eventualmente los servidores pueden aparecer listados y removerlos puede demorar 24 horas luego de un brote de spam de modo que siempre es bueno contar con una manera de evitar los controles.

Para hacerlo creamos un archivo llamado

/etc/postfix/rbl_client_exceptions

:

## Algún comentario
www.xxx.yyy.zzz OK

Una vez más será necesario generar la Berkeley DB

postmap /etc/postfix/rbl_client_exceptions

Postgrey

Se podría agregar postgrey como capa adicional de filtrado, lo cual no es para nada complejo. Solo se instala el servicio

apt -y install postgrey

y agregamos a smtpd_recipient_restrictions

check_policy_service inet:127.0.0.1:10023

La configuración de postgrey se almacena en /etc/default/postgrey. Allí se puede modificar, por ejemplo, el retraso impuesto a la entrega de los correos.

check_policy_service inet:127.0.0.1:10023 --delay=60

Reduciría la demora a un minuto. El valor predeterminado es de cinco.

Las restricciones smtpd son fáciles de comprender, mientras no surja un NO de manera explícita a un mensaje determinado, éste seguirá avanzando en la lista de verificaciones.

Instalar Spamassassin

# apt-get install spamassassin spamc

Creamos un usuario para spamc. Se trata de la mitad cliente de la pareja spamc/spamd. Debería ser usado en lugar de “spamassassin” en scripts para procesar el correo. Leerá el correo desde STDIN, y lo pondrá en la cola de su conexión a spamd, luego leer el resultado y lo imprime a STDOUT. Spamc tiene un impacto muy bajo en el rendimiento, por lo que debería ser mucho más rápida su carga comparado con el programa spamassassin completo.”

# adduser spamd --disabled-login

Basta con presionar enter ante cada pregunta.

Habilitamos el inicio de Spamassassin en cada arranque:

# systemctl enable spamassassin.service

Editamos

/etc/default/spamassassin

:

OPTIONS="--create-prefs --max-children 5 --username spamd --helper-home-dir /home/spamd/ -s /home/spamd/spamd.log"
# Habilita la actualización automática de las reglas de Spamassassin cada noche.
CRON=1

Luego editamos

/etc/spamassassin/local.cf

para establecer las reglas de SPAM:

rewrite_header Subject ***** SPAM _SCORE_ *****
# Muestra el mensaje spam original en lugar de un mensaje
# que contenga al correo con spam como adjunto.
report_safe 0
required_score 5.0
use_bayes 1
bayes_auto_learn 1
skip_rbl_checks 0
use_dcc 0
use_pyzor 0

Iniciamos el filtro de spam:

# systemctl start spamassassin

Le indicamos a Postfix que tenemos activo un filtro de contenido. En

/etc/postfix/master.cf

encontrar la linea

smtp inet n - - - - smtpd

y directamente debajo agregamos:

 -o content_filter=spamassassin

En este caso la linea que comienza con -o debe tener uno o más espacios en blanco al comienzo. De no ser así, al recargar la configuración Postfix ‘dirá’: “/usr/sbin/postconf: fatal: invalid type field”. Nuevamente, incontables horas de diversión.

Ya que postfix enviará el recipiente a spamc, necesitamos indicarle a postfix que entregue el correo a cada usuario de separadamente. Agregamos la siguiente linea a /etc/postfix/main.cf

spamassassin_destination_recipient_limit = 1

Necesitamos indicar a Postfix que encamine el correo a spamd. Para ello, al final de

/etc/postfix/master.cf

agregamos:

spamassassin unix - n n - - pipe
 user=spamd argv=/usr/bin/spamc -f -e /usr/sbin/sendmail -oi -f ${sender} ${recipient}

Nuevamente hay que tener en cuenta el espacio al comienzo de la segunda linea.

# systemctl restart spamassassin
# postfix reload

En este punto es necesario enviar un correo de prueba hacia y desde nuestra cuenta en Roundcube para cerciorarnos que aún funciona.

Si no fuera así, removemos las últimas entradas de

/etc/postfix/master.cf

, reiniciamos Postfix e intentamos nuevamente. Verificamos no haber ingresado algo mal y que al reiniciar Postfix no arroja ningún error. Solamente vamos a continuar si el envío y la recepción funcionan.

Probando el filtro de spam

Enviamos un correo a nuestro recipiente con el GTUBE. Es el EICAR para los filtros de spam: es una cadena especial de caracteres que los filtros de spam reconocen como tal para propósito de pruebas. Más en: http://spamassassin.apache.org/gtube/

Así que enviamos un correo con esta cadena en el cuerpo del mensaje:

XJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X

Al ingresar a Roundcube el mensaje debería estar etiquetado como *****SPAM*****. Un mensaje sin esta cadena no debería contener esa alerta.

Abrimos el mensaje etiquetado como *****SPAM***** y vamos a “Mostrar código”.

Deberíamos ver algo así:

X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on servidor
X-Spam-Flag: YES
X-Spam-Level: **************************************************
X-Spam-Status: Yes, score=1001.9 required=5.0 tests=DKIM_SIGNED,DKIM_VALID,
DKIM_VALID_AU,FREEMAIL_FROM,GTUBE,PYZOR_CHECK,RCVD_IN_MSPIKE_H2,
SPF_PASS autolearn=no autolearn_force=no version=3.4.2
X-Spam-Report:
* 1000 GTUBE BODY: Generic Test for Unsolicited Bulk Email

Mover automáticamente el spam a la carpeta Basura

Esto es en realidad parte de algo más grande, llamado sistema de filtrado de correo. Usando filtros (también llamados reglas) podemos aplicar acciones a correo usando lógica, por ejemplo mover correo que está etiquetado como spam a la carpeta Basura.

Suscribir automáticamente usuarios a las carpetas especiales IMAP

En primer lugar necesitamos asegurarnos que el cliente IMAP está subscripto a la carpeta a la que el spam será movido.

Al abrir Roundcube vemos que solo existen dos carpetas: Entrada y Enviados. Apuntamos a subscribir automáticamente los usuarios a varias carpetas IMAP especiales de modo que siempre estén allí. En

/etc/dovecot/dovecot.conf

agregamos:

namespace inbox {
 mailbox Drafts {
 special_use = \Drafts
 auto = subscribe
 }
 mailbox Junk {
 special_use = \Junk
 auto = subscribe
 }
 mailbox Trash {
 special_use = \Trash
 auto = subscribe
 }
 #mailbox Archive {
 # special_use = \Archive
 # auto = subscribe
 }
 mailbox Sent {
 special_use = \Sent
 auto = subscribe
 }
 #mailbox "Sent Messages" {
 # special_use = \Sent
 #}
}

A las carpetas comentadas Roundcube no las reconoce, pero puede ser que algún otro MUA sí lo haga.

Luego

# dovecot reload

y volvemos a entrar a Roundcube ya que las carpetas especiales son creadas al ingresar.

Sieve

Dovecot cuenta con un plugin llamado Managesieve que permite definir reglas de filtrado en el servidor IMAP, de modo que todos los clientes veran lo mismo independientemente de la plataforma.

Para habilitarlo, en

/etc/dovecot/dovecot.conf

agregamos:

protocol lmtp {
 mail_plugins = $mail_plugins sieve
 postmaster_address = administrador@midominio.com.ar
}
plugin {
 sieve = file:~/sieve;active=~/.dovecot.sieve
}

Luego reiniciamos dovecot

# systemctl restart dovecot

En teoría, para probar

# telnet localhost 4190

y obtendríamos

Connected to localhost.
Escape character is '^]'.
"IMPLEMENTATION" "Dovecot Pigeonhole"
"SIEVE" "fileinto reject envelope encoded-character vacation subaddress comparator-i;ascii-numeric relational regex imap4flags copy include variables body enotify environment mailbox date ihave"
"NOTIFY" "mailto"
"SASL" "PLAIN LOGIN"
"VERSION" "1.0"
OK "Dovecot ready."

lo cual significa que Sieve está funcionando. Hay que presionar Enter tres veces para salir.

Si surgen inconvenientes, es necesario verificar la configuración, reiniciar Dovecot y volver a intentar.

doveconf -n

puede ayudar a comprobar errores de tipeo y cosas por el estilo.

Es posible crear reglas sieve predeterminadas. Esto tiene una enorme contra: tan pronto como el usuario crea sus propias reglas (por ejemplo, define una respuesta automática para cuando no está en la oficina) las reglas predeterminadas ya no son tenidas en cuenta aún luego de eliminar la regla personal.

Definir regla de spam de manera global

Vamos a definir una regla de spam global que moverá el spam automáticamente a la carpeta Basura del usuario.

sieve_default = /etc/dovecot/sieve/spamfilter.sieve

Esta carpeta y archivo son arbitrarios pero me parecieron lógicos.

Creamos la carpeta:

mkdir /etc/dovecot/sieve

Cambiamos permisos ya que de no hacerlo dovecot se va a quejar.

chown vmail:vmail /etc/dovecot/sieve/ -R

En

/etc/dovecot/sieve/spamfilter.sieve

:

require ["fileinto"];
if header :contains "X-Spam-Flag" "YES" {
 fileinto "Junk";
}

Esta regla verifica un encabezado llamado ‘X-Spam-Flag’. Si contiene YES el mensaje es almacenado en la carpeta Basura.

Recargamos Dovecot y enviamos un mensaje con la cadena GTUBE para verificar si funciona.

Eliminar spam automáticamente luego de 30 días

Usando doveadm podemos eliminar automáticamente todo el correo en la carpeta Basura más antiguo que cierto tiempo, por ejemplo 30 días.

Doveadm es es la utilidad de administración de Dovecot. Con man doveadm se puede consulta por mayor información sobre la utilidad. Otra lectura relevante para este caso: man doveadm-search y man doveadm-search-query.

Digamos que queremos buscar todos los documentos en todas las bandejas de entrada de más de cuatro horas de antigüedad:

# doveadm search -A mailbox Inbox savedbefore 4h
administrador@midominio.com.ar 74b4db2757f9f05661350000595b2a1f 1
administrador@midominio.com.ar 74b4db2757f9f05661350000595b2a1f 2

-A significa revisar todas las casillas, no solo la especificada.

No queremos buscar solo la Bandeja de entrada y queremos correo de más de 30 días:

# doveadm search -A mailbox Junk savedbefore 30d
administrador@midominio.com.ar 4adeeb2ca5c1ca565c3b000038e0142a 1
administrador@midominio.com.ar 4adeeb2ca5c1ca565c3b000038e0142a 2
administrador@midominio.com.ar 4adeeb2ca5c1ca565c3b000038e0142a 3

Para más información sobre el formato de consulta.

$ man doveadm-search-query

Pero no queremos buscar solamente sino eliminar esos correos. (Usamos search primero para verificar que obtenemos los resultados que estábamos esperando.)

# doveadm expunge -A mailbox Junk savedbefore 30d

Como seguramente no vamos a querer correr esto manualmente todos los días. Lo programamos:

# crontab -e

Agregamos esta línea:

@hourly /usr/bin/doveadm expunge -A mailbox Junk savedbefore 30d

En caso que no querramos recibir un aviso por correo sobre la salida de esta programación la cambiamos a

@hourly /usr/bin/doveadm expunge -A mailbox Junk savedbefore 30d > /dev/null 2>&1

Lo anterior ejecutará el comando cada hora. Cambiarlo a

@daily /usr/bin/doveadm expunge -A mailbox Junk savedbefore 30d > /dev/null 2>&1

hará que se ejecute cada día

Revisar la cola de correo de Postfix

Cuando un correo electrónico no se envía, termina en una de las dos colas dentro de Postfix: pending (pendiente) y deferred (diferido).

La cola de pendientes incluye todos los mensajes que has enviado a Postfix que aún no han sido enviados y entregados al servidor del destinatario. La cola de correo diferido contiene todos los mensajes que han fallado y se necesita reintentar enviarlos (fallo temporal).

Postfix intentará reenviar los mensajes de la cola diferida a intervalos establecidos. Esto está configurado a 5 minutos de manera predeterminada, pero este proceso es totalmente configurable.

Introduciendo cualquiera de los siguientes comandos, puedes inspeccionar y gestionar tus colas de mensajes de Postfix con facilidad.

Cómo revisar las colas de mensajes de Postfix

1) Visualizar las colas de correo: diferido y pendiente

mailq

o

postqueue -p

Alternativamente, para guardar la salida en un archivo de texto, ejecuta

mailq > mailqueue.txt

o

postqueue -p > mailqueue.txt

Cualquiera de estos comandos mostrará el remitente, los destinatarios y el ID, pero no el mensaje en sí. Aunque el ID ayudará a localizar los mensajes individuales.

2) Ver el mensaje (contenido, cabecera y cuerpo) en la cola de Postfix
Los ID de los mensajes están disponibles en la cola de mensajes. Así que, para ver un mensaje con el ID XXXXXXX, ingresar

postcat -vq XXXXXXXXXX

O, para guardarlo en un archivo, introducí

postcat -vq XXXXXXXXXX > emailXXXXXXXX.txt

Una característica útil para los servidores web es habilitar mail.add_x_header = on en la configuración de Postfix.

Esto añadirá una cabecera a todos los mensajes de correo electrónico salientes mostrando el script y el usuario que generó cada mensaje. Una vez habilitado esto añadirá la siguiente cabecera extra al mensaje:

X-PHP-Originating-Script: 1001:spamEmailer.php

En este ejemplo, 1001 es el ID del usuario y spamEmailer.php es el script que envía el mensaje. Esto permite rastrear rápidamente el origen de cualquier mensaje de spam enviado desde nuestro servidor.

Cómo eliminar el correo en cola de espera

1) Indicar a Postfix que procese la cola ahora

postqueue -f

o

postfix flush

2) Eliminar el correo en cola

Un comando similar le permitirá eliminar todos los mensajes en cola en Postfix. Esto incluye los mensajes de las colas pendientes y diferidas:

postsuper -d ALL

Por lo tanto, si necesitás eliminar todos los mensajes en cola hacia o desde el dominio llamado spamers.com, ingresarías:

./postfix-delete.pl spamers.com

Del mismo modo, si querés eliminar todos los mensajes en cola que contengan la palabra “spam” en la dirección de correo electrónico, tendrías que utilizar el siguiente comando

./postfix-delete.pl spam

Para borrar específicamente todos los mensajes de la cola diferida (es decir, sólo los que el sistema pretende reintentar más tarde), introducí

postsuper -d ALL deferred

3) Eliminar selectivamente el correo de la cola

También se pueden eliminar mensajes específicos de la cola de correo. Esto no es algo que esté incluido de forma nativa con las herramientas estándar de Postfix, pero puede hacerse con un script Perl.

Nota: No fue posible encontrar el origen de este script de Perl, está por todo Internet. En cualquier caso, le damos las gracias.

#########################################

/usr/bin/perl

$REGEXP = shift || die "no se ha indicado ninguna dirección de correo electrónico(regexp-style, ej. bl.*\@gmail.com)!";

@datos = qx;

for (@data) {

if (/^(\w+)(\*|\!)?\s/) {

$queue_id = $1;

}

if($queue_id) {

if (/$REGEXP/i) {

$Q{$queue_id} = 1;

$queue_id = "";

}

}

}

#open(POSTSUPER,"|cat") | die "no se pudo iniciar postsuper" ;

open(POSTSUPER,"|postsuper -d -") | die "no se pudo iniciar postsuper" ;

foreach (keys %Q) {

print POSTSUPER "$_\n";

};

close(POSTSUPER);

#########################################

Herramientas de Análisis