Uno de los servicios más importantes de Internet es sin duda el correo electrónico, y al igual que con muchos otros servicios, no hay nada que gestione mejor el correo que GNU/Linux.

Hay muchos proyectos conocidísimos y de gran importancia en el mundo de GNU/Linux, como por ejemplo el servidor web Apache, las bases de datos MySQL y PostgreSQL, el servidor de nombres Bind y muchísimos más... pero hay 2 de estos grandísimos proyectos que no suelen ser tan conocidos para el ciudadano de a pié, y sin embargo son una parte fundamental de Internet. Me estoy refiriendo a Postfix y a Courier, la pareja perfecta para hacerse cargo de algo tan importante hoy en dìa como es el correo electrónico.

Y es que la combinación de estos 2 sistemas no solo funciona, sino que además lo hace increíblemente bien.

Viendo que este artículo puede resultar bastante extenso, voy a dividirlo un poco y a crear un pequeño índice:

  1. Un poco de historia antes de empezar
  2. Configuración del DNS del dominio para recibir emails
  3. Creación de la base de datos de usuarios
  4. Instalación de Postfix como servidor SMTP
  5. Configuración de SASL para autenticación de Postfix
  6. Instalación de Courier como servidor POP/IMAP
  7. Instalación de antivirus y antispam
  8. Estadísticas y monitorización
  9. Referencias

Vamos con el primero de los puntos...

Un poco de historia antes de empezar

Si de verdad tienes muchísima prisa en montar tu servidor de correo, puedes saltarte ésta parte e ir directamente al capítulo 2, pero es importante saber qué vas a instalar, porqué lo vas a hacer y cómo funciona realmente el mundo del correo electrónico.

Hay 2 procesos completamente diferenciados en el tema del correo electrónico:

  • El envío del mensaje: realizado mediante el protocolo SMTP por programas llamados MTA.
  • La lectura del mensaje: realizada mediante los protocolos POP o IMAP.

Estos procesos no tiene nada que ver uno con otro, y como el uso del correo electrónico es totalmente transparente para el usuario, la mayoría de ellos ni los entiende ni los diferencia (y no me refiero solo a tus abuelos o a los míos, sino incluso a gente del gremio de la informática), ni falta que les hace... pero tranquilo, que si estás leyendo éste artículo significa que gracias a los Dioses, tu no formas parte de esa mayoría de usuarios zombis, lamers y catetos varios.

Todo el sistema de correo electrónico se puede entender fácilmente siguiendo la analogía que tiene con el sistema de correo postal de toda la vida, en el que hay oficinas de correos, carteros, buzones, etc.

Cuando tú quieres escribir una carta postal a alguien (olvídate del email o el móvil, haz un esfuerzo e imagínatelo, hombre!), una vez redactada la metes en un sobre indicando el remitente y el destinatario, y la metes en el buzón. Un cartero recoge esa carta, y la lleva a la oficina de correos de tu barrio, donde si la carta es válida (lleva la dirección del destinatario, el sobre está cerrado, etc) es clasificada según sea su destino, momento en el cual un transportista (o cartero) la recoge de esa oficina y la entrega en la oficina de correos del barrio de dicho destinatario. En esa oficina, otros carteros recogen las cartas recién llegadas y las llevan al buzón del destinatario, el cuál a partir de ese momento ya puede abrir su buzón cuando lo desee y coger las cartas (y leerlas en ese momento o cuando él prefiera).

Éste es exactamente el mismo proceso que sigue el correo electrónico.

Cuando tu quieres escribir un email a alguien, una vez escrito en tu cliente de correo favorito (Thunderbird/Icedove, Evolution, ~~Outlook~~, ~~GMail~~, etc), estos lo envían a tu servidor de correo saliente (la oficina de correos de tu barrio). Allí, si el email es valido (hay un remitente y un destinatario cuyo dominio existe, su servidor de correo responde, etc) se mira en el DNS del dominio al que va dirigido el correo cuál es el servidor SMTP de dicho dominio, y se le reenvía el mensaje a dicho servidor (la oficina de correos del barrio del destinatario). Allí, si el destinatario existe, se deja el email en su buzón (mailbox) a la espera de que éste se conecte a éste servidor (mediante un cliente de correo) y se descargue los mensajes que en él pudiera haber (y ya los leerá cuando él quiera).

Ves la analogía, verdad? Es prácticamente lo mismo (voy a tratar de ilustrar el ejemplo con una gráfica utilizando el genial Graphviz, del cual ya hablé en éste otro artículo):

Por lo tanto el primer paso necesario en ésta cadena es el envío de correo, es decir, el MTA.

Hay muchos programas en GNU/Linux que actúan de MTA. El más famoso de todos seguramente sea Sendmail, que fue uno de los primeros MTA que existieron, y fue utilizado durante mucho tiempo en prácticamente todos los servidores SMTP de Internet. No obstante siempre se le ha considerado difícil de configurar, lo que unido a los numerosos problemas de seguridad que ha tenido en su historia, hoy en día podríamos decir que ha sido reemplazado por otros MTAs como por ejemplo Qmail, Exim o Postfix.

Éste último es sin duda mi preferido, y es el que voy a explicar en este artículo.

Una vez tengamos el SMTP funcionando, necesitaremos otros sistemas que accedan a los emails que el MTA nos haya dejado. Para esto también tenemos diferentes y buenas opciones, como por ejemplo Dovecot o Courier.

He probado ambos, y aunque Dovecot funciona muy bien, siempre me ha gustado mucho más Courier... por lo tanto, es el que voy a explicar en este artículo.

Montar cualquiera de estos servicios basándose en los usuarios locales del servidor no tiene ningún misterio, aparte de ser algo muy poco recomendable ya que supondría que tendríamos que crear un usuario en el servidor por cada usuario de correo que fuéramos a utilizar (solo el imaginarlo ya me da urticaria!). Por lo tanto, los usuarios de nuestro servidor de correo van a ser usuarios virtuales cuyos datos van a estar almacenados en una base de datos (que podría ser MySQL, PostgreSQL o incluso OpenLDAP).

Y tal y como indica el título del artículo, vamos a explicar como montar el servidor COMPLETO, y no sería verdaderamente un servidor de correo completo si no tuviera también detección de SPAM, antivirus, filtros de correo, SSL en todos estos servicios e incluso estadísticas y gráficas para la monitorización de todo el sistema.

Ahora que hemos visto un poco los fundamentos básicos del sistema de correo electrónico, vamos a entrar en materia...

Configuración del DNS del dominio para recibir emails

Hay una parte fundamental para entender cómo funciona el correo electrónico en Internet, y aunque es sumamente obvia y básica para los que conocemos el tema, voy a explicarla simplemente para asegurarme de que entiendes lo que estamos haciendo, no sea que después de todo el rollo que estoy contando en este artículo, todavía no tengas claros algunos conceptos básicos sobre el funcionamiento de los servidores de correo (y si los conoces, pues te aguantas y lo lees de nuevo, que seguro que te va a costar a ti mucho menos leerlo que a mi escribirlo xDDDD).

Supongamos que ya tenemos nuestro flamante servidor de correo listo y funcionando, preparado para recibir el correo de las direcciones de email de (por ejemplo) pornohardware.com (me refiero a direcciones del tipo usuario@pornohardware.com y similares).

Puede que el servidor esté funcionando, pero... ¿cómo sabe la gente que éste servidor que acabo de configurar es a donde tienen que enviar los emails que vayan a la dirección usuario@pornohardware.com, por ejemplo?

La respuesta está, como casi todo lo relativo a los nombres de los dominios, en el DNS.

Doy por sentado que conoces el servicio de DNS de un dominio, y que sabes perfectamente que éste DNS se encarga de decirle a tu navegador (por ejemplo) que la dirección IP del servidor de pornoharware.com es la 188.165.118.8, verdad?

El DNS se configura a base de registros, y los hay de varios tipos. Uno de los más utilizados es el registro de tipo A, que se encarga precisamente de esto último que acabo de decir: traducir el nombre de un dominio a una dirección IP.

Sin embargo, hay otros tipos de registros en un DNS que son igual de importantes que el A, como por ejemplo el que atañe al correo de dicho dominio, llamado registro de tipo MX.

Si un registro de tipo A del dominio de pornohardware.com diría que "la dirección www.pornohardware.com es en realidad la IP 188.165.118.8", un registro de tipo MX del dominio de pornohardware.com diría que "el servidor que se encarga del correo de las direcciones acabadas en @pornoharware.com es la IP 141.8.224.25 (por ejemplo)".

Por eso, cuando enviamos un email a una dirección, nuestro servidor hace una consulta al DNS del dominio del destinatario para saber cuál es la IP del servidor de correo de dicho destinatario... y una vez obtenida, se intenta conectar a esa dirección para pasarle el email.

Éste tipo de registros DNS tienen además una particularidad que no tienen los demás, y es que es posible asignar más de 1 servidor de correo a cada dominio, definiendo diferentes prioridades a cada uno de ellos... es decir, que podemos configurar 2 servidores de correo diferentes para que se hagan cargo del correo de un dominio determinado, y decirle al DNS que el servidor de correo habitual será el 1... pero que en aquellos casos en los que el servidor 1 esté caído por cualquier motivo, puede enviar el email también al servidor 2.

También podemos configurar 2 servidores de correo diferentes para el mismo dominio, y asignarles la misma prioridad. En éste se iría utilizando un servidor u otro indistintamente, siendo esto muy útil para balancear la carga entre ambos.

Un ejemplo práctico

En cualquier distribución de GNU/Linux tenemos disponible el comando nslookup, que sirve para conectarse a un servidor DNS y hacerle consultas.

No entraré a explicar su sintaxis, únicamente tenéis que ver que con el siguiente comando le estoy pidiendo al servidor DNS 208.67.222.222 (uno de los servidores DNS públicos de OpenDNS) que me diga cuál es la IP del servidor de pornohardware.com:

bhean@vader:~$ nslookup pornohardware.com 208.67.222.222
Server:     208.67.222.222
Address:    208.67.222.222#53

Non-authoritative answer:
Name:   pornohardware.com
Address: 188.165.118.8

Como veis, primero nos dice a qué servidor DNS le estamos haciendo la consulta (en éste caso: 208.67.222.222) y a través de qué puerto (208.67.222.222#53), y luego nos da lo que le hemos pedido: Address: 188.165.118.8.

Si en lugar de pedirle la IP de la dirección web, le pedimos las IPs de su servidor/servidores de correo, el comando sería:

bhean@vader:~$ nslookup -type=mx pornohardware.com 208.67.222.222
Server:     208.67.222.222
Address:    208.67.222.222#53

Non-authoritative answer:
pornohardware.com   mail exchanger = 5 mail.pornohardware.com.

En éste caso, nos dice que el servidor de correo de pornohardware.com es mail.pornohardware.com.

Si hacemos la misma prueba pero con un dominio que tenga configurados varios servidores de correo, por ejemplo debian.org, veremos esto:

bhean@vader:~$ nslookup -type=mx debian.org 208.67.222.222
Server:     208.67.222.222
Address:    208.67.222.222#53

Non-authoritative answer:
debian.org  mail exchanger = 5 mailly.debian.org.
debian.org  mail exchanger = 10 muffat.debian.org.

Vemos que los servidores de correo del dominio debian.org son 2:

  • mailly.debian.org: con prioridad 5
  • muffat.debian.org: con prioridad 10

Como uno tiene una establecida una prioridad de 5 y el otro de 10, el que tenga el valor más bajo es el que se considera servidor principal, y en caso de estar caído, se utilizaría el otro.

Es decir, a MENOR valor, MÁS prioridad tendrá ese servidor con respecto a los demás.

Ahora que ya tenemos claro cómo anunciar a todo Internet que nuestro servidor va a ser el encargado de manejar el correo de determinado dominio, vamos al turrón...

Creación de la base de datos de usuarios

Como ya he dicho antes, que los usuarios del sistema de correo sean los usuarios locales que haya en el servidor (que es el funcionamiento por defecto) es algo completamente desaconsejable, y da igual que penséis que para un par de usuarios que vais a usar no merece la pena una base de datos, o que solo es una prueba y si va bien ya lo montaréis con base de datos más adelante o cualquier otra excusa que se os ocurra.

Mi experiencia como sysadmin me ha demostrado una y otra vez que éstas cosas, al cabo de no mucho tiempo, nunca son como eran cuando se pensaron y montaron inicialmente. Es decir, que si ahora piensas que solo vas a usar 2 usuarios, cuando te quieras dar cuenta tendrás una docena de ellos... y si algo molesta sobremanera a un sysadmin bofh es trabajar 2 veces para lo mismo, así que vamos a hacer las cosas bien desde el principio, que no cuesta nada! xDD

Lo primero es elegir si vas a utilizar base de datos o LDAP para almacenar los usuarios, ya que son métodos MUY diferentes.

Yo recomiendo base de datos (y más concretamente PostgreSQL), pero si vas a implementar el servidor de correo en un entorno en el que ya dispones de un directorio activo u OpenLDAP, también puedes hacerlo.

Para éste artículo usaré base de datos, concretamente PostgreSQL (aunque si hubiera alguna diferencias en alguna parte con respecto a MySQL, intentaré explicarla). Llegados a éste punto doy por hecho que ya tenéis vuestro servidor de base de datos instalado y funcionando, por lo que si no es así, instala y configura el servidor de base de datos antes de continuar.

Si quieres hacer que prácticamente toda la información del sistema se almacene y gestione en la base de datos, puedes hacerlo. Yo normalmente solo uso la base de datos para la información de los usuarios y para la de sus alias de correo.

Para almacenar ésta información tenemos que crear una tabla para cada cosa, y que contenga la información necesaria tanto para Postfix como para Courier. Un ejemplo completamente válido y que llevo utilizando muchísimos años en diferentes servidores de correo que administro es el siguiente:

Tabla para usuarios

Nombre columna Tipo columna Valor por defecto Nulos?
user_id integer nextval('user_id_seq') NO
name character varying(64) NULL SI
surname character varying(128) NULL SI
login character varying(32) NULL NO
password_crypt character varying(64) NULL NO
email_local character varying(255) NULL NO
insert_date timestamp without time zone now() NO
description character varying(255) NULL SI
imap_access character(1) 0 NO
smtp_access character(1) 0 NO
path_maildir character varying(255) '/' NO
user_active character(1) 0 NO

Tabla para alias de correo

Nombre columna Tipo columna Valor por defecto Nulos?
email_local character varying(255) NULL NO
email_alias character varying(255) NULL NO

Ahora veremos las querys necesarias para crear esas tablas... primer tómate unos segundos para examinar los campos de dichas tablas y hacerte una idea aproximada de los datos que vamos a guardar en ellas: todos los campos son más o menos auto explicativos, pero por si acaso comentaré para qué se van a usar:

Tabla para usuarios

  • user_id: Ésta será la clave primaria de la tabla, por eso su valor por defecto en PostgreSQL es la secuencia user_id_seq, y en MySQL será un campo AUTOINCREMENT.
  • name: En éste campo se almacenará el nombre del usuario (me refiero a su nombre de pila, que es necesario para algunas cosas, no el nick).
  • surname: En éste campo se almacenarán los apellidos del usuario.
  • login: Nick del usuario
  • password_crypt: La contraseña del usuario (utilizando el algoritmo de cifrado crypt basado en DES).
  • email_local: La dirección de email que vamos a crear para el usuario.
  • insert_date: Fecha de creación del usuario
  • description: Como su nombre indica, es la descripción que queramos hacer de la cuenta de éste usuario.
  • imap_access: Usaremos este campo para permitir o no permitir que el usuario se conecte al servidor IMAP para leer correo.
  • smtp_access: Usaremos este campo para permitir o no permitir que el usuario se conecte al servidor SMTP para enviar correo.
  • path_maildir: Aquí indicaremos la ruta física en el disco duro del servidor del mailbox del usuario.
  • user_active: Con este campo habilitaremos o no la cuenta del usuario.

Tabla para alias de correo

  • email_local: La dirección de correo del usuario al que vamos a crear un alias.
  • email_alias: El alias de correo que vamos a crear.

Una vez explicados los campos de ambas tablas, el código SQL necesario para crearlas sería el siguiente:

Para la tabla de usuarios en PostgreSQL:

CREATE DATABASE email;
\\c email

CREATE TABLE users (
    "user_id" integer DEFAULT nextval(('user_id_seq'::text)::regclass) NOT NULL,
    "name" character varying(64) DEFAULT NULL::character varying,
    "surname" character varying(128) DEFAULT NULL::character varying,
    "login" character varying(32) NOT NULL,
    "password_crypt" character varying(64) NOT NULL,
    "email_local" character varying(255) NOT NULL,
    "insert_date" timestamp without time zone DEFAULT now() NOT NULL,
    "description" character varying(255) DEFAULT NULL::character varying,
    "imap_access" character(1) DEFAULT 0 NOT NULL,
    "smtp_access" character(1) DEFAULT 0 NOT NULL,
    "path_maildir" character varying(255) DEFAULT '/'::character varying NOT NULL,
    "user_active" character(1) DEFAULT 0 NOT NULL
);

ALTER TABLE ONLY users
    ADD CONSTRAINT users_pkey PRIMARY KEY ("user_id");

ALTER TABLE ONLY users
    ADD CONSTRAINT "users_email_local_key" UNIQUE ("email_local");

ALTER TABLE ONLY users
    ADD CONSTRAINT "users_login_key" UNIQUE ("login");

CREATE SEQUENCE user_id_seq
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;

Para la tabla de usuarios en MySQL:

CREATE DATABASE email;
use email;

CREATE TABLE users (
  user_id int(7) NOT NULL AUTO_INCREMENT,
  name varchar(64) DEFAULT NULL,
  surname varchar(128) DEFAULT NULL,
  login varchar(32) NOT NULL DEFAULT '',
  password_crypt varchar(64) NOT NULL,
  email_local varchar(255) NOT NULL DEFAULT '',
  insert_date datetime NOT NULL,
  description text,
  imap_access char(1) NOT NULL DEFAULT '0',
  smtp_access char(1) NOT NULL DEFAULT '0',
  path_maildir varchar(255) NOT NULL DEFAULT '/',
  user_active char(1) NOT NULL DEFAULT '1',
  PRIMARY KEY (user_id),
  UNIQUE KEY email_local (email_local),
  KEY imap_access (imap_access),
  KEY smtp_access (smtp_access)
) ENGINE=MyISAM AUTO_INCREMENT=1;

Para la tabla de alias de usuarios en PostgreSQL:

CREATE TABLE users_aliases (
    "email_local" character varying(255) NOT NULL,
    "email_alias" character varying(255) NOT NULL
);

ALTER TABLE ONLY users_aliases
    ADD CONSTRAINT users_emails_ukey UNIQUE ("email_local", "email_alias");

Para la tabla de alias de usuarios en MySQL:

CREATE TABLE users_aliases (
  email_local varchar(255) NOT NULL DEFAULT '',
  email_alias varchar(255) NOT NULL DEFAULT '',
  UNIQUE KEY email_local (email_local, email_alias)
) ENGINE=MyISAM AUTO_INCREMENT=1;

Aparte de las tablas (y la secuencia, en el caso de PostgreSQL) necesitaremos crear también los usuarios que van a utilizar tanto Postfix como Courier para acceder a la base de datos. Siempre es recomendable crear un usuario para cada uno en lugar de crear uno en común.

Os recomiendo utilizar contraseñas complejas (que contengan letras, números y caracteres especiales, y cuya longitud no sea nunca inferior a 10 caracteres) generadas de forma aleatoria, ya que una vez tengáis los servicios configurados, no necesitaréis recordarlas.

Una web bastante útil y sencilla para generar contraseñas complejas de forma aleatoria es http://www.clavesegura.org/

Crearemos entonces 3 usuarios, uno para cada uno de los servicios que vamos a configurar más adelante (Postfix, Courier y SASL), por lo tanto ejecutamos éstas querys en nuestra base de datos para crear dichos usuarios y para darles permisos sobre las tablas que acabamos de crear.

No hay que confundir estos usuarios (que son los que usará Postfix, por ejemplo, para obtener los datos del destinatario de un email) con los usuarios de nuestro correo (es decir, las personas que van a disponer de direcciones de email gestionadas por nuestro servidor).

Para crear los usuarios que usarán estos servicios (Postfix, Courier y SASL) para conectarse a la base de datos en PostgreSQL:

CREATE ROLE app_postfix;
ALTER ROLE app_postfix WITH NOSUPERUSER INHERIT NOCREATEROLE NOCREATEDB LOGIN NOREPLICATION PASSWORD 'QZrRP-fzuq';

CREATE ROLE app_courier;
ALTER ROLE app_courier WITH NOSUPERUSER INHERIT NOCREATEROLE NOCREATEDB LOGIN NOREPLICATION PASSWORD 'OQ5JQ3+pNR';

CREATE ROLE app_sasl;
ALTER ROLE app_sasl WITH NOSUPERUSER INHERIT NOCREATEROLE NOCREATEDB LOGIN NOREPLICATION PASSWORD 'hb9mwJGcc';

GRANT SELECT ON TABLE users TO app_postfix;
GRANT SELECT ON TABLE users TO app_courier;
GRANT SELECT ON TABLE users TO app_sasl;

GRANT SELECT ON TABLE users_aliases TO app_postfix;
GRANT SELECT ON TABLE users_aliases TO app_courier;
GRANT SELECT ON TABLE users_aliases TO app_sasl;

Y para crear los usuarios que usarán estos servicios (Postfix, Courier y SASL) para conectarse a la base de datos en MySQL:

CREATE USER 'app_postfix'@'localhost' IDENTIFIED BY PASSWORD 'QZrRP-fzuq';
CREATE USER 'app_courier'@'localhost' IDENTIFIED BY PASSWORD 'OQ5JQ3+pNR';
CREATE USER 'app_sasl'@'localhost' IDENTIFIED BY PASSWORD 'hb9mwJGcc';

GRANT SELECT ON email.users TO 'app_postfix'@'localhost';
GRANT SELECT ON email.users TO 'app_courier'@'localhost';
GRANT SELECT ON email.users TO 'app_sasl'@'localhost';
GRANT SELECT ON email.users_aliases TO 'app_postfix'@'localhost';
GRANT SELECT ON email.users_aliases TO 'app_courier'@'localhost';
GRANT SELECT ON email.users_aliases TO 'app_sasl'@'localhost';

FLUSH PRIVILEGES;

En el caso de PostgreSQL, es necesario especificar en su archivo de configuración de accesos pg_hba.conf habilitemos el acceso de los 3 usuarios que acabamos de crear.

Editamos el archivo y especificamos que estos 3 últimos usuarios pueden conectarse a la base de datos email para leer. Repito: únicamente en el caso de PostgreSQL. Si estamos configurando el servidor únicamente para MySQL, entonces NO hay que hacer esto:

#
# Database administrative login by Unix domain socket
local   all             postgres                                peer

# TYPE  DATABASE        USER            ADDRESS                 METHOD
host    email           app_postfix     127.0.0.1/32            md5
host    email           app_courier     127.0.0.1/32            md5
host    email           app_sasl        127.0.0.1/32            md5

# "local" is for Unix domain socket connections only
local   all             all                                     peer
# IPv4 local connections:
host    all             all             127.0.0.1/32            md5
# IPv6 local connections:
host    all             all             ::1/128                 md5
# Allow replication connections from localhost, by a user with the
# replication privilege.
#local   replication     postgres                                peer
#host    replication     postgres        127.0.0.1/32            md5
#host    replication     postgres        ::1/128                 md5

Por último, comprobamos que podemos conectarnos a las tablas de nuestra base de datos, que en el caso de PostgreSQL se hace así:

$ psql -h 127.0.0.1 -U app_postfix -W --command='SELECT COUNT(*) FROM users;' email

 count
-------
     0
(1 row)

Y en el caso de MySQL se hace así:

$ echo "SELECT COUNT(*) FROM users;" | mysql -h 127.0.0.1 -u app_postfix -p email

COUNT(*)
0

Al ejecutar estos últimos comandos se os pedirá la contraseña del usuario que vayáis a probar (en éste caso el usuario es app_postfix). Una vez introducida debería ejecutarse la query correctamente... si por el contrario obtenéis algun mensaje de error, seguramente se deba a problemas con los permisos de los usuarios. Échale un ojo a lo que has ido haciendo, averigua en qué punto la has cagado y arréglalo... xDDD

Si todo ha ido bien, ésta parte ya la hemos acabado... ahora solo nos quedaría insertar un usuario para probar, y también algun alias. Es importante recordar que conviene insertar un registro en la tabla de aliases que contenga la propia dirección local del usuario que estamos creando (es decir, un alias de si mismo, aparte de los demás alias que vayamos a configurar para ese usuario) ya que en algunas circunstancias Postfix únicamente consulta la existencia de un usuario mirando en la tabla de aliases, por lo que si no tenemos un registro ahí que especifique la dirección normal del usuario, Postfix no lo encontrará y pensará que dicho usuario no existe, aunque sí que exista en la tablas users.

La password del usuario tiene que ir cifrada por motivos obvios de seguridad, para que nadie (incluso quien pudiera tener acceso a consultar la tabla en la que se almacena) pudiera verla.

El algoritmo de encriptación que vamos a usar es el mismo que utiliza GNU/Linux para almacenar las contraseñas de los usuarios del sistema, y que si no me equivoco, es el utilizado en la función CRYPT mediante el algoritmo DES.

Pero no os preocupéis si no estáis muy puestos en criptografía... existe un comando que os permitirá generar el hash de la contraseña que queráis utilizando diferentes algoritmos. Éste comando se llama authpasswd y forma parte del paquete courier-authlib, por lo que debemos instalarlo.

De nuevo, si usamos Debian/Ubuntu, basta con:

$ sudo apt-get install courier-authlib

Y si usamos CentOS/RedHat, me temo que estos paquetes no forman parte de sus repositorios oficiales, por lo que tendríais que compilar el código vosotros mismos. Si es vuestro caso, podéis bajarlo desde aquí: http://www.courier-mta.org/download.htmls

En cualquier caso, una vez que tengáis el paquete courier-authlib instalado, y por tanto el comando authpasswd disponible, solo tenéis que ejecutarlo especificando el algoritmo CRYPT y después de introducir la password que queráis. Eso os devolverá el hash correspondiente a dicha password, que por ejemplo, en el usuario de prueba que vamos a crear ésta password va a ser galactica :

$ authpasswd crypt
Password:
Reenter password:
{CRYPT}V1TBTcBUTkibk

Por lo tanto, la password encriptada de galactica es V1TBTcBUTkibk.

Con éstas querys deberíamos ser capaces de insertar un usuario de prueba con 1 alias y con la password cifrada en nuestra recién creada base de datos:

-- Insertamos el usuario
INSERT INTO
    users
    (
        name,
        surname,
        login,
        password_crypt,
        email_local,
        description,
        imap_access,
        smtp_access,
        path_maildir,
        user_active
    )
    VALUES
    (
        'William',
        'Adama',
        'bill',
        'V1TBTcBUTkibk',
        'adama@pornohardware.com',
        'Email del Comandante Adama',
        1,
        1,
        '/srv/maildirs/pornohardware.com/adama/',
        1
    );

-- Insertamos el alias de si mismo
INSERT INTO
    users_aliases
    (
        email_local,
        email_alias
    )
    VALUES
    (
        'adama@pornohardware.com',
        'adama@pornohardware.com'
    );

-- Insertamos un alias para el usuario
INSERT INTO
    users_aliases
    (
        email_local,
        email_alias
    )
    VALUES
    (
        'adama@pornohardware.com',
        'william.adama@pornohardware.com'
    );

Una vez ejecutados estos INSERT ya tendremos configurado nuestro usuario con sus alias, así que ahora vamos a ver cómo los utilizamos...

Instalación de Postfix como servidor SMTP

Ahora que ya tenemos la base de datos creada y nuestro primer usuario de prueba guardado en ella, vamos a preparar un servidor SMTP para que cuando le llegue un email para nuestro usuario, sepa que efectivamente es para él y lo guarde en su mailbox para que éste pueda leerlo cuando quiera.

Como ya comenté anteriormente, el SMTP que utilizo normalmente es Postfix.

No es perfecto, pero en mi opinión es el mejor SMTP que hay hoy en día, aunque como en casi todo hay varios bandos enfrentados (en éste caso el otro bando son los defensores de Exim, otro gran SMTP).

Hay que tener claro de antemano que la tarea de configurar un servidor SMTP se divide en 2 subtareas:

  • Configurar el servidor para que nuestros usuarios puedan enviar emails a otras personas.
  • Configurar el servidor para que cuando le llegue un email a uno de nuestros usuarios, éste lo guarde para que el usuario pueda leerlo.

Quiero que quede clara la división porque aunque sea Postfix quien se encargue de ambas, son 2 procesos diferentes.

Vamos con la primera...

Un servidor SMTP es un servicio que corre normalmente en el puerto 25 (y/o en el puerto 465 si nos conectamos a través de SSL).

Esto significa que cuando queramos enviar un email, debemos conectarnos a éste servidor y mediante los comandos propios de su protocolo debemos indicar quienes somos, a quién queremos enviar el email, con qué texto queremos enviarlo, etc. y si lo hemos hecho bien, nuestro servidor enviará dicho email al SMTP del destinatario (como ya dije en el esquema de funcionamiento del correo que puse arriba).

Sin embargo, el SMTP no puede estar abierto a cualquiera (situación conocida como open relay), ya que entonces los spammers lo utilizarán para enviar emails publicitarios o de cualquier otro tipo a todo el mundo, lo que aparte de generar numerosos problemas, podría hacer que la IP de nuestro servidor de correo fuera incluida en alguna base de datos pública de spammers, lo que provocaría que la mayor parte de los servidores de correo del mundo rehusaran recibir nuestros emails (aunque éstos fueran emails legítimos enviados normalmente por nosotros).

Únicamente nuestros usuarios (aquellos que mediante su login y password se autentiquen satisfactoriamente) debería tener permisos para poder enviar emails a través de este SMTP.

El SPAM es una lacra, y no solo es molesto, sino que puede llegar a causar problemas de verdad... así que, por favor, pon especial atención a proteger tu servidor para que ésta panda de desgraciados no pueda servirse de él.

Así que debemos configurar Postfix para que únicamente acepte emails de los usuarios que se autentiquen. Como estos usuarios los tenemos en una base de datos, vamos a configurar Postfix para que se conecte a ella y los busque.

Lo primero es instalar los paquetes de Postfix según la base de datos que estemos usando (ya sea MySQL o PostgreSQL). Y como siempre, esta instalación es trivial si usamos una distribución de GNU/Linux decente como por ejemplo Debian. En éste caso (o en el de las que se basan en ella, como por ejemplo Ubuntu), bastaría con:

$ sudo apt-get install postfix postfix-mysql postfix-pgsql

Si por algun motivo (por ejemplo, que seamos masoquistas) utilizamos CentOS, Redhat o similares, podemos instalarlo también de forma muy fácil con:

$ sudo yum install postfix

Ahora que ya lo tenemos instalado vamos a configurarlo. Los 2 archivos de configuración principal de Postfix son master.cf y main.cf (ambos en el directorio /etc/postfix).

En el primero de ellos (/etc/postfix/master.cf) se especifican las opciones del proceso demonio de nuestro servidor SMTP, tales como filtros, configuración de chroot, etc. Es normal que las primeras veces que se examina éste archivo puede parecer algo complejo de manejar... pero al final es tan simple como el resto de Postfix.

Un ejemplo de éste archivo podría ser el siguiente:

/etc/postfix/master.cfdownload
# Postfix master process configuration file.  For details on the format
# of the file, see the master(5) manual page (command: "man 5 master").
#
# ==========================================================================
# service type  private unpriv  chroot  wakeup  maxproc command + args
#               (yes)   (yes)   (yes)   (never) (100)
# ==========================================================================
smtp      inet  n       -       n       -       -       smtpd
#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       -       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
mailman   unix  -       n       n       -       -       pipe
  flags=FR user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py
  ${nexthop} ${user}
scalemail-backend unix	-	n	n	-	2	pipe
  flags=R user=scalemail argv=/usr/lib/scalemail/bin/scalemail-store ${nexthop} ${user} ${extension}
smtp-amavis unix -      -       n       -       2       smtp
        -o smtp_data_done_timeout=1200
        -o disable_dns_lookups=yes
# Amavis filter
127.0.0.1:10025 inet n  -       -       -       -       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
        -o smtpd_sasl_auth_enable=yes

La estructura del archivo es sencilla: se empieza con el nombre del servicio que estamos configurando, seguido de - o n dependiendo de si queremos activar o desactivar las diferentes funcionalidades (cada columna del archivo corresponde a una funcionalidad), y en la línea siguiente se especifican las diferentes opciones que pudiera tener el servicio.

La primera línea que debemos modificar es la 8, que corresponde al servicio smtp. En ella debemos desactivar el chroot, aunque si bien no lo recomiendo, es posible instalarlo utilizando la jaula del chroot (de hecho, el resultado sería mucho más seguro), pero la complejidad del sistema aumenta tantísimo que personalmente no creo que sea necesario.

Ten en cuenta que ahora estamos únicamente configurando Postfix, pero cuando termines de leer éste artículo tendremos un sistema de correo en el que además de él habrá muchos otros servicios que deben interactuar, y tener a Postfix encerrado en un chroot dificultaría las cosas muchísimo. Hay muchas otras formas de proteger el sistema... pero obviamente esto es solo una recomendación mía. Si eres el sysadmin de la NSA y estás montando el Postfix personal de Obama en el mismo servidor en el que él guarda sus fotos más comprometidas, quizás sí que sería buena idea que dejaras el chroot activado... xDDD

Lo mismo haremos con la linea 14, que corresponde al servicio smtps (es decir, el servicio a través del protocolo seguro SSL): descomentamos las lineas (si es que estaban comentadas) y desactivamos el chroot. Más adelante ya hablaremos de cómo utilizar el SSL en todos los servicios de nuestro servidor de correo.

Si te fijas en las líneas que van de la 74 a la 76 y las que van de la 79 a la 94 del archivo master.cf que he puesto de ejemplo, verás que se trata de la configuración de 2 filtros: uno llamado mailman y otro llamado smtp-amavis. Pero de momento no te preocupes por esto, no lo configures aún... ya hablaremos de estos servicios cuando tengamos el resto terminado...

Una vez terminado master.cf (al menos de momento), si abrimos el otro archivo de configuración /etc/postfix/main.cf nos encontraremos todas las directivas que vienen preconfiguradas por defecto. Podéis echarle un ojo para familiarizaros con el archivo y con sus directivas, la mayoría de ellas tienen un nombre bastante descriptivo.

Un ejemplo de éste archivo (remarcando las directivas más relevantes) sería algo así:

/etc/postfix/main.cfdownload
# Debian specific:  Specifying a file name will cause the first
# line of that file to be used as the name.  The Debian default
# is /etc/mailname.
myorigin = "pornohardware.com"

smtpd_banner = $myhostname ESMTP $mail_name (Debian/GNU)
biff = no

# appending .domain is the MUA's job.
append_dot_mydomain = no

# Uncomment the next line to generate "delayed mail" warnings
delay_warning_time = 4h

# TLS parameters
smtpd_tls_cert_file=/srv/sites/conf/ssl/mail.pornohardware.com.crt
smtpd_tls_key_file=/srv/sites/conf/ssl/mail.pornohardware.com.key
smtpd_use_tls = yes
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache

# See /usr/share/doc/postfix/TLS_README.gz in the postfix-doc package for
# information on enabling SSL in the smtp client.

myhostname                      = pornohardware.com
mydomain                        = pornohardware.com
alias_maps                      = hash:/etc/aliases
alias_database                  = hash:/etc/aliases
mydestination                   = pornohardware.com
relay_domains                   = $mydestination,
                                pornosoftware.com
mynetworks                      = 127.0.0.0/8, 188.165.118.8
mailbox_command                 = procmail -a "$EXTENSION"
mailbox_size_limit              = 0
recipient_delimiter             = +
inet_interfaces                 = all
transport_maps                  = hash:/etc/postfix/transport
message_size_limit              = 25600000

# MySQL
virtual_mailbox_base            = /
virtual_uid_maps                = static:102
virtual_gid_maps                = static:8
virtual_mailbox_maps            = mysql:/etc/postfix/mysql/mysql_virt.cf
virtual_maps                    = mysql:/etc/postfix/mysql/alias.cf
local_transport                 = virtual

# Amavis
content_filter                  = smtp-amavis:[127.0.0.1]:10024

# No backscatter
soft_bounce                     = no
unknown_local_recipient_reject_code = 550

# SASL2 Auth
smtpd_sasl_auth_enable          = yes
smtpd_sasl_security_options     = noanonymous
smtpd_sasl_local_domain         = $myhostname
broken_sasl_auth_clients        = yes
smtpd_recipient_restrictions    = permit_mynetworks,
                                reject_invalid_hostname,
                                reject_non_fqdn_sender,
                                reject_non_fqdn_recipient,
                                reject_unknown_sender_domain,
                                reject_unknown_recipient_domain,
                                permit_sasl_authenticated,
                                reject_unauth_destination,
#                                check_policy_service unix:private/policy,
                                check_policy_service inet:127.0.0.1:10023,
                                regexp:/etc/postfix/blacklist,
                                permit
maps_rbl_domains                = rbl.maps.vix.com,
                                relays.mail-abuse.org,
                                relays.ordb.org,
                                dev.null.dk,
                                spews.relays.osirusoft.com,
                                spamhaus.relays.osirusoft.com,
                                relays.visi.com

Directiva: myorigin, myhostname y mydomain

La primera de las directivas que tenemos que configurar es myorigin (línea 4 del archivo). Con ésta variable definimos el nombre del dominio por defecto desde el que vamos a enviar los emails.

Por ejemplo, si la configuramos con el valor pornohardware.com, cuando enviemos un email desde ese servidor (desde la línea de comandos, con el usuario root, por ejemplo), el destinatario de dicho email vería como remitente la dirección root@pornohardware.com.

Conviene saber que ésta directiva acepta 2 tipos de valores: o bien el nombre del dominio, o bien la ruta de un archivo que contenga dicho nombre. Es decir, podemos poner:

myorigin = pornohardware.com

O bien podemos crear un archivo llamado /etc/mailname que únicamente contenga pornohardware.com, y configurar la directiva así:

myorigin = /etc/mailname

Ambos casos sería iguales, así que hacerlo como más o guste. Personalmente prefiero el primer caso por facilidad y simplicidad, así la configuración está en un único archivo en lugar de en varios, pero hasta que me alce como vuestro Líder en un Nuevo Orden Mundial, esto es un mundo libre, por lo que podéis hacerlo como queráis (aunque insisto: solo de momento xDD).

Así mismo, la directiva myhostname (línea 25) especifica el nombre de nuestro servidor (host), y mydomain (línea 26) el nombre del dominio principal (ambas no tienen porqué coincidir, aunque es frecuente que lo hagan).

Directiva: smtpd_banner

La directiva smtpd_banner (línea 6) permite definir el texto que nuestro servidor mostrará cuando se establezca una conexión al puerto del SMTP. Normalmente no es algo que el usuario vea, por lo que es indiferente lo que pongamos aquí, pero ten en cuenta que si nos conectamos manualmente (con telnet, por ejemplo) al puerto del SMTP, veremos ese texto... y un atacante podría usar la información que mostremos en él (nombre del servidor SMTP que estamos usando, sistema operativo que tenemos instalado, etc) para recopilar datos sobre nuestro servidor como primer paso a un ataque... pero bueno, eso ya depende de vuestro grado de paranoya. Personalmente no me gusta dar nunca más información de la necesaria, pero no pasa nada porque mostremos el nombre del software de servidor SMTP que estamos usando (Postfix) ni el sistema operativo (GNU/Linux).

Directivas: smtpd_tls_key_file y smtpd_use_tls

Si disponéis de un certificado SSL válido para el servidor de correo que estáis montando, debéis especificar la ruta de los archivos crt y key de dicho certificado. Para eso debéis usar las directivas smtpd_tls_cert_file, smtpd_tls_key_file y smtpd_use_tls (líneas 16 a 20). El uso, generación y firma de certificados SSL escapa al ámbito de éste artículo, así que no lo explicaré ahora (ya escribiré otro artículo explicando esto en cuanto pueda, mientras tanto asumiré que si vas a usar dichas opciones, ya sabes manejar éste tipo de certificados).

Directivas: alias_maps y alias_database

Estas directivas (líneas 27 y 28) se utilizan para indicar la relación de alias de los usuarios locales del servidor. Es decir, si queremos evitar (por ejemplo) que el correo que se envíe al usuario root local del sistema se redirija a otro usuario (o a otra dirección), podemos definir un alias para ese usuario, de forma que los correos que se le envíen serán redirigidos al alias automáticamente.

Una recomendadísima práctica en la administración de servidores de correo suele ser la de definir un alias como mínimo al usuario root, de forma que los emails que se le podrían llegar a enviar sean redirigidos a otro usuario. Esto se hace para evitar que alguien pudiera colapsar el servidor llenando el buzón de correo del usuario root con miles de enormes emails (ya que normalmente el usuario root no suele tener establecida una quota de disco, ni un límite de emails, ni ninguna otra restricción).

Postfix utiliza una base de datos propia para almacenar ésta información, y la forma de generar dicha base de datos es mediante el comando newaliases, que convierte el archivo /etc/aliases (texto plano) en /etc/aliases.db (la base de datos que Postfix utiliza). Por lo tanto, nosotros debemos trabajar siempre con /etc/aliases, y una vez modificado, ejecutar de nuevo el comando para convertirlo en el archivo que Postfix espera.

Un ejemplo de /etc/aliases podría ser éste:

/etc/aliasesdownload
# /etc/aliases
mailer-daemon: postmaster
postmaster: root
nobody: root
hostmaster: root
usenet: root
webmaster: root
www: root
abuse: root
noc: root
security: root
root: fulanito

fulanito: fulanito@dominio.com

Según éste archivo, todo el correo enviado al usuario local mailer-daemon se redirigiría al usuario postmaster... y éste a su vez se redirigiría al usuario root.

También se redirigiría al usuario root el correo enviado a nobody, hostmaster, usenet, webmaster, etc..

Finalmente, todo el correo enviado hacia root será redirigido al usuario fulanito (para evitar llena el buzón de root), el cual a su vez será reenviado a la cuenta externa fulanito@dominio.com.

Directiva: mydestination

Aquí (línea 29) especificamos los dominios de correo de los que nuestro servidor se va a encargar. Es decir, cuando recibamos un email que vaya a algun usuario de alguno de estos dominios, asumiremos que es nuestro e intentaremos entregárselo al usuario en cuestión (buscándolo en la base de datos que habíamos creado antes, o en el archivo /etc/aliases). Y si recibimos un email dirigido a un dominio que no es uno de los nuestros (es decir, un dominio que NO esté especificado en ésta directiva) buscaremos el servidor de correo que se encarga de los emails de dicho dominio, y se lo pasaremos para que sea él quien trate de entregárselo al destinatario.

Directiva: relay_domains

Con ésta directiva (línea 30) podemos decirle a nuestro servidor SMTP una serie de dominios de los cuales SI debe aceptar los emails, aunque dichos dominios NO sean de los que nos encargamos en éste servidor. Es decir, con relay_domains podemos decirle a nuestro Postfix que acepte emails de determinados dominios aunque estos no estén especificados en mydestination. Esto es útil como backup de correo, ya que si disponemos de 2 servidores de correo diferentes, podemos hacer que cada uno tenga configurado al otro en ésta directiva, de forma que si algun día uno de los 2 está fuera de servicio, el otro iría recogiendo el correo del servidor caído, y se los entregaría posteriormente cuando éste volviera a estar disponible. Para esto hay que especificar también éste segundo servidor de correo en el registro MX del DNS del dominio, así como utilizar la directiva transport_maps para indicar el servidor al que entregar todo el correo ajeno que estamos aceptando al usar ésta directiva (ya lo veremos más adelante).

No obstante, relay_domains únicamente se utiliza en instalaciones un poco más avanzadas de lo normal... si lo que estáis configurando es un servidor de correo normal para gestionar los emails de alguno de vuestros dominios, normalmente no os hará falta utilizarla.

Directiva: mynetworks

Aquí indicamos las direcciones de red de aquellas máquinas que queremos que nuestro servidor considere como máquinas de nuestra red. Esto es útil sobre todo para indicar el servidor que el envío de correo debe estar autenticado cuando dichos emails proceden de Internet (para que nadie pueda usarnos para enviar SPAM), pero los demás servidores de nuestra red sí que pueden enviar emails sin necesidad de autenticación.

Directiva: inet_interfaces

Como su propio nombre indica, aquí podemos especificar en qué interfaces queremos que escuche nuestro servidor SMTP. Normalmente el valor que usaremos será all, ya que lo más habitual es que queramos que el servidor SMTP esté accesible en todos los interfaces de red que haya en nuestro servidor, pero podría darse algun caso en el que nos interese que únicamente podamos conectarnos al servidor SMTP desde localhost o desde un interface de red determinado, ignorando las conexiones desde los demás.

Directiva: transport_maps

Como dije antes, para poder utilizar nuestro servidor también como backup del correo de otro dominio es necesario el uso de ésta directiva, pero también se usa para enviar el correo que queramos a un filtro determinado (configurando dicho filtro previamente en master.cf) o para indicar la dirección del servidor SMTP de un dominio concreto de forma manual.

El valor que debemos indicar en ésta directiva es la ruta donde se encuentra el archivo que contiene la información de transporte del correo. Es decir, algo como :

transport_maps = hash:/etc/postfix/transport

El formato de éste archivo es el mismo que con el archivo aliases que expliqué antes. Debemos utilizar el archivo /etc/postfix/transport (en texto plano) para indicar la información que queramos, y una vez modificado y guardado dicho archivo, debemos generar el archivo en el formato que utiliza Postfix... que en éste caso, a diferencia del archivo aliases (que había que ejecutar el comando newaliases para generarlo) se hace mediante el comando postmap de ésta forma:

sudo postmap /etc/postfix/transport

Después de ejecutar ese comando, obtendremos el archivo /etc/postfix/transport.db, que no es más que el archivo transport pero en el formato requerido por Postfix.

Algunos ejemplos de archivo transport que pueden ayudar a entender mejor su funcionamiento podrían ser estos:

  • Configurar transport para que el correo que llegue para el dominio fulanito.com a nuestro servidor se reenvíe a otro servidor SMTP distinto. Esto se usa normalmente para backup de correo, configurando el DNS del dominio de fulanito.com para que nuestro servidor sea uno de sus servidores de correo (añadiéndolo como registro MX) pero indicando un número de prioridad mayor (para que solo envíen mensaje de ese dominio a nuestro servidor cuando el principal esté caído:

    Para hacer esto, lo primero sería añadir nuestro servidor al registro DNS de fulanito.com:

    MX 5 mail.fulanito.com
    MX 10 nuestro-servidor.com
    

    Cuando mail.fulanito.com (que como tiene la prioridad más baja, es el servidor de correo principal de ese dominio) no funcione, se enviarán los emails a nuestro-servidor.com, y éste a su vez estará configurado para aceptar los emails que vayan a dicho dominio, pero en lugar de guardarlos en el mailbox del usuario en cuestión, los encolará e irá intentando cada cierto tiempo conectarse a mail.fulanito.com para entregarle dichos emails.

    Lo primero sería decirle a nuestro Postfix que aunque nos encarguemos del correo de los dominios especificados en la directiva mydestination del /etc/postfix/main.cf (que en éste caso son los del dominio pornoharware.com), también debe aceptar los correos para los dominios especificados en la directiva relay_domains (que serán los que vayan dirigidos al dominio fulanito.com):

    mydestination = pornohardware.com
    relay_domains = fulanito.com
    

    Y por último, en el archivo transport está la dirección del servidor SMTP que se encarga de esos emails

    fulanito.com    smtp:mail.fulanito.com:25
    

    Con ésta configuración, nuestro servidor de correo será el encargado de gestionar los emails del dominio pornoharware.com, pero también aceptará los que vayan al dominio fulanito.com mientras el servidor principal de éste esté caído. Y a diferencia de los emails que le lleguen a nuestro servidor y que vayan a pornohardware.com (que serán guardados en el mailbox del destinatario en cuestión), los que vayan a fulanito.com los iremos encolando, y tan pronto vuelva a funcionar el servidor principal de ese dominio, le reenviaremos todos los que hayamos encolado hasta ese momento, de forma que no se habrá perdido ningún email durante el tiempo que su servidor estuvo caído.

  • Configurar transport para que el correo que llegue a un dominio entero y a una dirección concreta, sean enviados a un script en Perl (para que éste haga lo que sea con ellos). Éste script lo habremos configurado previamente en el archivo master.cf de la siguiente forma:

    filtro_script  unix -   n   n   -   -   pipe
      flags=B user=nobody argv=/usr/bin/perl /opt/scripts/parse_emails.pl
    

    Con esas 2 lineas habremos configurado un filtro llamado filtro_script, que enviará el contenido del email mediante pipe al comando especificado en el parámetro argv.

    Ahora debemos indicar en el archivo transport qué emails son los que deben pasar por ese filtro:

    admin@fulanito.com      filtro_script:
    menganito.com           filtro_script:
    

    Con ésta configuración (y una vez generado el archivo transport.db con el comando postmap como expliqué antes) nuestro servidor reenviaría al script que habíamos configurado en master.cf con el nombre de filtro_script aquellos emails cuyo destinatario sea la dirección admin@fulanito.com y cualquier dirección del dominio menganito.com.

Directiva: message_size_limit

Esta directiva es muy fácil: como su propio nombre indica, especifica el tamaño máximo que podrán tener los emails que manejará nuestro servidor Postfix.

El valor debe ir en bytes, por lo que si queremos establecer un tamaño máximo de archivo de 25Mb(que para mi es el límite máximo que debería permitirse, ya que para archivos más grandes no deberíamos utilizar el email), debemos multiplicar 25 * 1024000, es decir:

message_size_limit = 25600000

Directivas: virtual_*

Aquí viene lo bueno...

Estas directivas son las que van a permitir a Postfix conectarse a nuestra base de datos para comprobar la existencia de los usuarios a los que van dirigidos los emails que recibamos.

Cada vez que nuestro Postfix reciba un email dirigido a una dirección de correo de uno de los dominios de los que él se hace cargo (los especificados en la directiva mydestination) se conectará a la base de datos que indiquemos aquí para comprobar que dicho destinatario existe, y en caso afirmativo, de cuál es el mailbox (directorio del disco del servidor) donde tiene que almacenar dicho email.

Las directivas principales son:

  • virtual_mailbox_base: La base de la ruta física en el disco duro del servidor donde están los mailbox de cada usuario. El valor más indicado es /, ya que la ruta de cada mailbox la especificaremos en la base de datos, segun sea un usuario u otro.
  • virtual_uid_maps: El uid del usuario que ejecuta el demonio de Postfix. Normalmente es el usuario postfix, y su uid se puede ver con el comando vipw. Si éste valor fuera por ejemplo el 102, el valor que habría que configurar para ésta directiva sería static:102.
  • virtual_gid_maps: Igual que el valor anterior, pero ésta vez en lugar del uid hace referencia al gid del grupo mail. Éste valor se puede ver con el comando vigr, y si dicho valor fuera por ejemplo el 8, el valor que habría que configurar para ésta directiva sería: static:8.
  • virtual_mailbox_maps: Aquí vamos a indicar la ruta física del mailbox del usuario, que como en nuestro caso está en la base de datos, hay que crear un archivo de texto plano con la configuración necesaria para que Postfix pueda conectarse a dicha base de datos. Por lo tanto, el valor que pondremos en ésta directiva será pgsql:/etc/postfix/db/users.cf o mysql:/etc/postfix/mysql/users.cf (después crearemos dicho archivo).
  • virtual_maps: En ésta directiva podemos configurar dónde debe Postfix buscar los posibles alias del usuario que esté buscando, y dado que en nuestro caso ésta información está también en la base de datos, hay que crear un archivo de texto plano con la configuración necesaria para que Postfix pueda conectarse a dicha base de datos. Por lo tanto, el valor que pondremos en ésta directiva será mysql:/etc/postfix/db/alias.cf o pgsql:/etc/postfix/db/alias.cf (después crearemos éste archivo también).

A modo de resumen, la configuración de éstas directivas sería algo así:

Para PostgreSQL:

virtual_mailbox_base = /
virtual_uid_maps     = static:102
virtual_gid_maps     = static:8
virtual_mailbox_maps = pgsql:/etc/postfix/db/users.cf
virtual_maps         = pgsql:/etc/postfix/db/aliases.cf

Para MySQL:

virtual_mailbox_base = /
virtual_uid_maps     = static:102
virtual_gid_maps     = static:8
virtual_mailbox_maps = mysql:/etc/postfix/db/users.cf
virtual_maps         = mysql:/etc/postfix/db/aliases.cf

Como veis, únicamente se diferencian en las lineas que están resaltadas (lineas 45 y 46), a la hora de especificar qué tipo de base de datos vamos a usar (PostgreSQL o MySQL).

Y en esos archivos (/etc/postfix/db/users.cf y /etc/postfix/db/aliases.cf) únicamente tenemos que especificar la base de datos a la que Postfix tiene que conectarse para buscar los usuarios y sus alias, el nombre de las tablas, la query SQL que necesitamos para obtener los datos que queremos, etc.

Por lo tanto, dichos archivos (según la base de datos de usuarios que habíamos creado antes) serían algo así:

Para PostgreSQL:

# Configuracion de Postfix para obtener los datos de los
# usuarios virtuales que hay en la base de datos
#

hosts    = localhost
user     = app_postfix
password = QZrRP-fzuq
dbname   = email
query    = SELECT "path_maildir" FROM users WHERE "email_local" = '%s' AND "user_active" = '1'
# Configuracion de Postfix para obtener los alias de los
# usuarios virtuales que hay en la base de datos
#

hosts    = localhost
user     = app_postfix
password = QZrRP-fzuq
dbname   = email
query    = SELECT "email_local" FROM users_aliases WHERE "email_alias" = '%s'

Para MySQL:

# Configuracion de Postfix para obtener los datos de los
# usuarios virtuales que hay en la base de datos
#

hosts    = localhost
user     = app_postfix
password = QZrRP-fzuq
dbname   = email
query    = SELECT path_maildir FROM users WHERE email_local = '%s' AND user_active = '1'
# Configuracion de Postfix para obtener los alias de los
# usuarios virtuales que hay en la base de datos
#

hosts    = localhost
user     = app_postfix
password = QZrRP-fzuq
dbname   = email
query    = SELECT email_local FROM users_aliases WHERE email_alias = '%s'

Como podeis ver, la única diferencia que hay entre si utilizamos PostgreSQL o Mysql es que en éste último los nombres de las columnas NO pueden ir entre comillas, mientras que en PostgreSQL es obligatorio.

Y con esto, ya deberíamos tener toda la parte de configuración básica de nuestro servidor SMTP (Postfix) terminada...

Vamos a intentar iniciar el servicio (o reiniciarlo, si ya estaba levantado) para ver si hemos configurado todo correctamente:

$ sudo /etc/init.d/postfix start
[ ok ] Starting Postfix Mail Transport Agent: postfix

Podemos echar un ojo al log para ver si el servicio se ha iniciado correctamente. El log de los servicios de correo se encuentra en /var/log/mail.log en Debian y similares, y en /var/log/maillog en CentOS/RedHat.

Si vemos algo parecido a esto en el log (sin ningún otro mensaje chungo), podemos alegrarnos:

postfix/master[27126]: daemon started -- version 2.9.6, configuration /etc/postfix

Si vemos algun mensaje de error, Postfix debería ser lo suficientemente explícito como para darnos en el log una buena pista sobre donde está el problema, que si lo hay, a éstas alturas de la configuración seguramente no sea más que un error de sintaxis o alguna tontería que hayamos hecho en alguno de los archivos que hemos editado hasta ahora. Así que arréglalo!! xDD

Para probar que todo funciona correctamente, lo suyo es tratar de enviar un email al usuario que habíamos creado en la base de datos y ver si Postfix es capaz de aceptar el email, obtener la información del destinatario y guardar el email en su mailbox. Y para eso nada mejor que conectarnos mediante telnet al puerto del Postfix y teclear los comandos SMTP necesarios para enviar un email.

Primero nos conectamos:

$ telnet localhost 25
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 pornohardware.com ESMTP Postfix (Debian/GNU)

Y luego, mediante los comandos SMTP descritos en el RFC2821, primero saludamos al servidor con HELO (o EHLO), después identificamos el remitente del email con MAIL FROM, luego especificamos al destinatario con RCPT TO y después escribimos el contenido del email con DATA. Cuando hayamos terminado de escribir el contenido del email, debemos finalizar con una nueva linea y punto . para enviar el mensaje. Después finalizamos la conexión con QUIT.

Esto sería un ejemplo de la conversación que debemos mantener con el servidor SMTP:

$ telnet localhost 25
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 pornohardware.com ESMTP Postfix (Debian/GNU)

EHLO remitente.com
250-remitente.com
250-PIPELINING
250-SIZE 25600000
250-VRFY
250-ETRN
250-STARTTLS
250-AUTH PLAIN
250-AUTH=PLAIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN

MAIL FROM: prueba@bhean.com
250 2.1.0 Ok

RCPT TO: adama@pornohardware.com
250 2.1.5 Ok

DATA
354 End data with <CR><LF>.<CR><LF>
Esto es una prueba para ver si todo funciona correctamente
.
250 2.0.0 Ok: queued as BE75A100D0

QUIT
221 2.0.0 Bye
Connection closed by foreign host.

Si hay algun problema lo veremos en el log del servidor, y también al ejecutar los comandos anteriores con el telnet.

Antes de dar por terminada la configuración del SMTP, hay un par de opciones muy interesantes que se pueden incluir en el main.cf y que pueden resultar muy útiles en algunas ocasiones:

  • blacklist: Se utiliza para especificar direcciones de email concretas (o dominios enteros) que deben ser rechazados (porque sepamos que son spam o slgo así).
  • whitelist: Igual que el anterior, pero al revés. Permite configurar servidores de los que SI queremos aceptar emails.
  • check_sender: Permite aceptar o rechazar emails en función de la dirección del remitente.
  • check_body: Igual que el anterior, pero en función del cuerpo del email.

Los 2 primeros (blacklisty whitelist) forman parte de la configuración de smtpd_recipient_restrictions, es decir, una serie de comprobaciones que Postfix hace cuando recibe un email.

Todas estas comprobaciones se irán ejecutando por orden de aparición. Postfix irá procesándolas una tras otra hasta que una de ellas concuerde con el email recibido. Si ninguna concuerda, el email será aceptado. Pero si alguna de ellas concuerda, se aceptará o rechazará dependiendo de lo que hayamos configurado en dicha comprobación.

Una configuración típica de smtpd_recipient_restrictions en el archivo main.cf sería:

smtpd_recipient_restrictions = regexp:/etc/postfix/blacklist,
                               permit_mynetworks,
                               reject_invalid_hostname,
                               reject_non_fqdn_sender,
                               reject_non_fqdn_recipient,
                               reject_unknown_sender_domain,
                               reject_unknown_recipient_domain,
                               permit_sasl_authenticated,
                               reject_unauth_destination,
                               regexp:/etc/postfix/blacklist,
                               permit

Aquellas que comienzan por regexp: se utilizan para definir (en un archivo aparte) determinadas acciones (aceptar el email, rechazarlo, etc) mediante patrones de expresiones regulares. Por ejemplo, el archivo /etc/postfix/blacklist podría ser parecido a esto:

/soyun@spamer\.com$/   REJECT   SPAM is not allowed here / El SPAM no esta permitido aqui
/@spam\.com$/          REJECT   SPAM is not allowed here / El SPAM no esta permitido aqui

Nota: Antes de nada, al igual que en los anteriores casos que hemos visto, hay que utilizar el comando postmap con estos archivos para que Postfix pueda utilizarlos. Simplemente ejecutamos:

$ postmap blacklist

para que se genere el archivo blacklist.db, que no es más que el archivo blacklist que hemos creado, pero en un formato que Postfix sabe manejar.

Volviendo al ejemplo, segun el archivo blacklist que hemos creado y a la configuración de smtpd_recipient_restrictions, si recibiéramos un email de la dirección soyun@spamer.com o de cualquier dirección del dominio @spam.com, sería rechazado automáticamente (REJECT) utilizando "SPAM is not allowed here / El SPAM no esta permitido aqui" como razón del rechazo.

Pero si el email recibido no coincidiera con ninguna de las expresiones regulares de blacklist, entonces Postfix pasaría a la siguiente restricción que hubiera configurada en smtpd_recipient_restrictions, en éste caso permit_mynetworks (que significa que están permitidos los emails enviados desde las máquinas de nuestra red, es decir, los servidores cuyas IPs están especificadas en la directiva mynetworks del main.cf).

Del mismo modo podemos configurar también un archivo para hacer todo lo contrario, es decir, en lugar de rechazar aquellos emails que coincidan con las expresiones regulares que especifiquemos, podríamos querer que Postfix aceptara aquellos emails que coincidan con dichas expresiones.

Un ejemplo de un archivo whitelist podría ser algo así:

83.138.165.68   OK
5.153.231.4     OK

Cualquier email procedente de dichas IPs sería aceptado por nuestro servidor. Por supuesto, para utilizar éste archivo habría que generar también el correspondiente whitelist.db con el comando postmap.

Y por último, los archivos check_sender y check_body se basan en el mismo concepto que los anteriores... solo que como su propio nombre indican, estos comprueban coincidencias con el remitente del email y con el cuerpo del mismo, respectivamente.

Para utilizarlos, nuesto main.cf debería incluir algo parecido a esto:

smtpd_sender_restrictions       = regexp:/etc/postfix/check_sender
body_checks                     = regexp:/etc/postfix/check_body

Y en dichos archivos se crearían las expresiones regulares que queramos comprobar, junto con el código de estado y el mensaje que queremos que se devuelva si alguna coincide:

/@dominiospamer\.com$/    550 No queremos SPAM
/@otrospamer\.com$/       550 No queremos SPAM
/Ryan Harding/     REJECT No queremos SPAM
/Bet2Day/          REJECT No queremos SPAM

Hay muchas otras opciones, por lo que os recomiendo que le echeis un ojo a la documentación oficial de Postfix si quereis ver algo más en detalle.

En cuanto al SMTP, por el momento podemos darlo por terminado... pero recordar que si utilizais un firewall (y si no lo haceis, deberíais! insensatos!) debéis abrir los puertos necesarios, que en éste caso son el 25 para el SMTP y el 465 para el SMTP-SSL...

Ahora que ya tenemos Postfix funcionando para el servicio SMTP, vamos a continuar con una de las partes más importantes para evitar el spam: configurarlo para que únicamente nuestros usuarios puedan usarlo para el envío de emails.

Configuración de SASL para autenticación de Postfix

Postfix debe aceptar los emails que vayan destinados a nuestros usuarios... pero qué pasa con aquellos emails que nuestros usuarios quieran enviar a otras personas?

Un servidor SMTP abierto es el paraiso de cualquier spamer, por lo que únicamente nuestros usuarios deben poder utilizar nuestro SMTP para enviar emails. De lo contrario, cualquiera que descubra nuestro servidor nos utilizará para enviar miles de emails a todo el mundo... y no solo debemos evitarlo para no contribuir con el envío de spam, sino que podrían meter la IP de nuestro servidor en alguna de las muchísimas listas negras de servidores de spam que hay en Internet, lo que haría que todos los servidores de emails del mundo rechazaran el correo enviado por nuestro servidor, incluso los emails legítimos enviados por nuestros usuarios.

Para evitarlo, debemos configurar Postfix para que solo nuestros usuarios puedan hacer uso de él. Para llevar a cabo ésta tarea debemos utilizar SASL.

SASL hará que Postfix solo acepte enviar emails de los usuarios que se identifiquen, para lo cual consultará la base de datos a través de PAM (Pluggable Authentication Modules), que es un sistema de autenticación muy extendido en el mundo unix/linux.

La instalación de los paquetes necesarios para la autenticación de Postfix, si utilizamos Debian/Ubuntu, se lleva a cabo de ésta forma:

$ sudo apt-get install libgsasl7 libsasl2-2 libsasl2-modules libsasl2-modules-sql sasl2-bin libpam-mysql libpam-pgsql libpam-modules-bin libpam-modules

Y si utilizamos Redhat/CentOS, debemos descargar e instalar los paquetes manualmente, ya que no se encuentran en los repositorios oficiales de éstas distribuciones (elije Debian la próxima vez, jejejee) xDD

Una vez instalados tanto SASL2 como PAM, la configuración de ambos es muy sencilla: primero habilitamos la ejecución del demonio de SASL en el arranque del servidor y especificamos el método de autenticación pam, editando el archivo /etc/default/saslauthd:

#
# Settings for saslauthd daemon
# Please read /usr/share/doc/sasl2-bin/README.Debian for details.
#

# Should saslauthd run automatically on startup? (default: no)
START=yes

# Which authentication mechanisms should saslauthd use? (default: pam)
#
# Available options in this Debian package:
# getpwent  -- use the getpwent() library function
# kerberos5 -- use Kerberos 5
# pam       -- use PAM
# rimap     -- use a remote IMAP server
# shadow    -- use the local shadow password file
# sasldb    -- use the local sasldb database file
# ldap      -- use LDAP (configuration is in /etc/saslauthd.conf)
#
# Only one option may be used at a time. See the saslauthd man page
# for more information.
#
# Example: MECHANISMS="pam"
MECHANISMS="pam"

# To know if your Postfix is running chroot, check /etc/postfix/master.cf.
# If it has the line "smtp inet n - y - - smtpd" or "smtp inet n - - - - smtpd"
# then your Postfix is running in a chroot.
# If it has the line "smtp inet n - n - - smtpd" then your Postfix is NOT
# running in a chroot.
OPTIONS="-c -m /var/run/saslauthd -r"

Después, configuramos PAM para que se conecte a nuestra base de datos para comprobar el login/password de nuestros usuarios. Para ello, editamos el archivo /etc/pam.d/smtp (si no existiera, lo crearíamos) con los valores de nuestra base de datos, y del usuario app_sasl que ya habíamos creado previamente para esto al comienzo de éste artículo:

auth sufficient pam_pgsql.so \\
        user=app_sasl \\
        passwd=hb9mwJGcc \\
        host=127.0.0.1 \\
        db=email \\
        table=users \\
        usercolumn=login \\
        passwdcolumn=password_crypt \\
        crypt=1 \\
        where=user_active=1 \\
        debug=1

auth sufficient pam_unix_auth.so

account required pam_pgsql.so \\
        user=app_sasl \\
        passwd=hb9mwJGcc \\
        host=127.0.0.1 \\
        db=email \\
        table=users \\
        usercolumn=login \\
        passwdcolumn=password_crypt \\
        crypt=1 \\
        where=user_active=1 \\
        debug=1

account sufficient pam_unix_acct.so

Obviamente, si en lugar de PostgreSQL utilizamos MySQL, debemos cambiar pam_pgsql.so por pam_mysql.so.

El parámetro debug se puede establecer a 1 para aumentar la información que se mostrará en el log, algo muy útil para darnos pistas si algo no va bien. Si no queremos información de debug, lo dejamos a 0.

Por último, editamos (o creamos, en el caso de no existir) el archivo /etc/postfix/sasl/smtpd.conf. En él indicaremos a Postfix que debe usar el demonio SASL para autenticar a los usuarios:

pwcheck_method: saslauthd
saslauthd_path: /var/run/saslauthd/mux
mech_list: plain
log_level: 5

Es importante que el usuario postfix sea miembro del grupo sasl, ya que de lo contrario Postfix no tendrá permisos para acceder a SASL. Para eso basta con ejecutar:

$ sudo usermod -G sasl postfix

Por último, debemos asegurarnos que las directivas de configuración de SASL están correctamente especificadas en el main.cf de Postfix:

smtpd_sasl_path             = smtpd
smtpd_sasl_auth_enable      = yes
#smtpd_sasl2_auth_enable    = yes
smtpd_sasl_security_options = noanonymous
smtpd_sasl_local_domain     = $mydestination
broken_sasl_auth_clients    = yes

Así como la restricción adecuada para rechazar aquellos usuarios que NO se identifiquen correctamente:

smtpd_recipient_restrictions  = permit_mynetworks,
                              reject_invalid_hostname,
                              reject_non_fqdn_sender,
                              reject_non_fqdn_recipient,
                              reject_unknown_sender_domain,
                              reject_unknown_recipient_domain,
                              permit_sasl_authenticated,
                              reject_unauth_destination,
                              check_client_access hash:/etc/postfix/whitelist,
                              permit

Y listo! Arrancamos el demonio de SASL:

$ sudo /etc/init.d/saslauthd start

Y si todo ha ido bien, ya deberíamos tener el servidor Postfix correctamente.

Para comprobar que SASL está correctamente configurado y funciona como queremos, existe el comando testsaslauth. Es muy sencillo de utilizar, solo hay que pasarle el usuario, el password y el método de autenticación que queremos comprobar. Por ejemplo, en nuestro caso bill es el usuario (campo login de la tabla users), galactica la password (cuyo valor cifrado es el que habíamos guardado en el campo password_crypt de la tabla users) y smtp es lo que queremos comprobar, por lo que el comando quedaría así:

$ testsaslauthd -s smtp -u bill -p galactica
0: OK "Success."

Si ejecutamos el mismo comando, pero con el nombre de usuario o la password mal puesta, deberíamos ver algo parecido a:

$ testsaslauthd -s smtp -u nobill -p nogalactica
0: NO "authentication failed"

Si el resultado de éstos comandos no es el esperado (siempre os sale authentication failed o algo así), podeis habilitar el modo de depuración (debug) de SASL para que muestre la información de autentificación en el log, descomentando la linea #debug que os indiqué en el archivo /etc/pam_pgsql.conf o /etc/pam_pgsql.conf.

También podeis comprobar que todo funciona como debería intentando enviar un email de forma anónima (sin identificarnos) y comprobar que Postfix NO os deja hacerlo... y después hacer la misma prueba, pero ésta vez identificándonos correctamente antes.

Para hacerlo, de nuevo recurrimos al comando telnet para ir viendo paso a paso las respuestas que nos da el servidor. Pero ojo! No debeis conectaros con el comando telnet desde el propio servidor o desde cualquier otra máquina de vuestra red, ya que como habíamos especificado la opción permit_mynetworks en la directiva smtpd_recipient_restrictions del archivo de configuración de Postfix, todas las máquinas de nuestra red estan autorizadas a enviar emails SIN necesidad de autenticarse. Por eso, la prueba con telnet debeis hacerla desde un servidor FUERA de vuestra red (es decir, fuera de lo especificado en la directiva mynetworks del archivo /etc/postfix/main.cf)

Para comprobar que el servidor NO acepta que enviemos emails sin identificarnos:

$ telnet ip-de-vuestro-servidort 25
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 pornohardware.com ESMTP Postfix (Debian/GNU)

EHLO remitente.com
250-remitente.com
250-PIPELINING
250-SIZE 25600000
250-VRFY
250-ETRN
250-STARTTLS
250-AUTH PLAIN
250-AUTH=PLAIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN

MAIL FROM: prueba@bhean.com
250 2.1.0 Ok

RCPT TO: cualquiercosa@hotmail.com
554 5.7.1 <cualquiercosa@hotmail.com>: Relay access denied

QUIT
221 2.0.0 Bye
Connection closed by foreign host.

Como podéis ver, estamos intentando enviar un email desde nuestro servidor de correo a la dirección cualquiercosa@hotmail.com, a lo cuál éste nos responde con un Relay access denied. Es decir, que NO podemos enviar emails a direcciones que no sean las de nuestro propio servidor, a no ser que nos identifiquemos previamente.

Si en lugar del mensaje 554 5.7.1 Relay access denied obtenéis un 250 2.1.5 Ok significa que vuestro servidor está aceptando CUALQUIER EMAIL para CUALQUIER DESTINATARIO (es decir, sois lo que se considera un Open Relay), y de ser así, para cuando hayais terminado de leer ésta frase ya habrá medio internet conectado a vuestro servidor enviando spam a todo el planeta... así que parar inmediatamente Postfix, cerrar el puerto SMTP en el firewall o lo que queráis, pero detener el servicio inmediatamente y revisar la configuración de SASL, PAM y Postfix antes de volver a abrirlo a Internet...

Quizás haya algo en el log que os ayude a encontrar el problema. Recordar que el log de los servicios de correo se encuentra en /var/log/mail.log en Debian y similares, y en /var/log/maillog en CentOS/RedHat.

Instalación de Courier como servidor POP/IMAP

Así como para poder enviar emails necesitamos un servidor SMTP, para poder acceder a ellos para su lectura necesitamos un servidor POP o IMAP, que son los 2 protocolos más extendidos para ese fin.

Podéis montar ambos o únicamente uno... aunque la verdad es que POP no tiene prácticamente ninguna ventaja hoy en día, cada vez se usa menos, y en mi opinión no tiene ningún sentido mantenerlo. Si os quedásteis anclados en los 90 y echáis de menos geocities, los gifs animados con símbolos de @rrobas dando vueltas, o simplemente eres un Amish montando el servidor de correo de tu aldea, POP es lo que buscas. Para todos los demás, IMAP es la solución.

No quiero extenderme mucho, pero para que quede un poco más claro, os pondré una pequeña tabla comparativa sobre algunas de las diferencias más notables entre ambos protocolos:

  POP3 IMAP4
Permite trabajar offline Si Depende del cliente
Número de transacciones Bajo Alto
Permite trabajar online No Si
Ver emails/cabeceras sin descargarlos previamente No Si
Nº de carpetas gestionables 1 Ilimitado
Gestión de carpetas No Si
Buzones multiusuario (acceso múltiple) No Si
Estados/flags en mensajes No Si
Búsqueda en mensajes No Si
Gestión MIME No Si
Mecanismos de extensión de funciones No Si
Firma cifrada No Si
Autenticación protegida APOP Nativo

Como podéis ver, el uso de POP hoy en día no tiene ningún sentido... por lo que a no ser que necesiteis implementarlo por algún extraño motivo, usar siempre IMAP. De hecho, aunque se pueden utilizar ambos al mismo tiempo NO os recomiendo que lo hagais, ya que si un usuario (por ejemplo) se descarga el correo utilizando POP, si más tarde accede por IMAP no podrá ver nada ya que una vez que POP descarga el correo, éste se elimina del servidor. Y al no permitir POP el uso de carpetas, únicamente se descarga el correo del INBOX (bandeja de entrada), lo que significa que si habeis organizado vuestros mensajes en carpetas utilizando IMAP, esos mensajes no podreis descargarlos desde POP.

Lo dicho, POP es de nenazas, así que voy a explicar únicamente la de IMAP. No obstante, si quereis instalar también el servidor POP, su instalación es muy sencilla (y similar).

Vamos al tema: así como para el uso del SMTP utilizábamos Postfix, para el uso de IMAP (o POP) vamos a utilizar Courier.

Courier es un servidor POP/IMAP que se encargará de acceder a los mensajes de correo electrónico que previsamente nuestro Postfix haya almacenado en los buzones de nuestros usuarios.

Como siempre, lo primero que tenemos que hacer es instalar los paquetes necesarios.

En Debian/Ubuntu:

sudo apt-get install courier-authdaemon courier-imap courier-imap-ssl courier-authlib-mysql courier-authlib-postgresql

En Redhat/CentOS:

Por desgracia en éstas distribuciones no existen paquetes RPM en sus repositorios oficiales, así que o bien lo instalais compilando su código fuente a mano (podéis descargarlo aquí) o bien generais los RPMs vosotros mismos tal y como se explica aquí. Obviamente es mucho más incómodo que utilizar los paquetes de los repositorios oficiales, pero si hubiérais elegido una distribución como Dios manda no tendríais que preocuparos...

En cualquier caso, una vez instalado, la configuración de Courier es muy sencilla: únicamente hay que editar 3 archivos:

  • /etc/courier/authdaemonrc
  • /etc/courier/imapd
  • /etc/courier/authpgsqlrc (o /etc/courier/authmysqlrc, según lo que estemos usando)

En el primero de ellos (/etc/courier/authdaemonrc) únicamente hay que indicar qué módulo es el que se va a encargar de autenticar a los usuarios (authpgsql, authmysql, etc).

##NAME: authmodulelist:2
#
# The authentication modules that are linked into authdaemond.  The
# default list is installed.  You may selectively disable modules simply
# by removing them from the following list.  The available modules you
# can use are: authuserdb authpam authpgsql authldap authmysql authcustom authpipe

authmodulelist="authpgsql"

En el archivo /etc/courier/imapd se pueden configurar varias cosas (dirección de red y puerto en el que escuchará nuestro servidor, opciones que se pasarán al demonio imapd, etc) pero nosotros solo vamos a cambiar 2 de ellas: MAXPERIP e IMAPDSTART.

La primera de ellas indica el número de conexiones por IP que nuestro servidor IMAP puede atender. El valor por defecto suele ser válido en la mayoría de los casos, pero en el protocolo IMAP se establece una conexion por cada carpeta IMAP a la que nos conectemos, por lo que si tenemos varias cuentas y leemos el correo de varias carpetas, puede que necesitemos aumentarlo. El valor por defecto es 50, pero yo suelo configurarlo a 120:

##NAME: MAXPERIP:0
#
#  Maximum number of connections to accept from the same IP address

MAXPERIP=120

Y en cuanto a IMAPDSTART, simplemente hay que establecerlo a YES para que el servicio IMAP se inicie automáticamente al arrancar el servidor:

##NAME: IMAPDSTART:0
#
# IMAPDSTART is not used directly.  Rather, this is a convenient flag to
# be read by your system startup script in /etc/rc.d, like this:
#
#  . /etc/courier/imapd
#
#  case x$IMAPDSTART in
#  x[yY]*)
#        /usr/lib/courier/imapd.rc start
#        ;;
#  esac
#
# The default setting is going to be NO, so you'll have to manually flip
# it to yes.

IMAPDSTART=YES

Ya solo quedaría el archivo /etc/courier/authpgsqlrc (o /etc/courier/authmysqlrc, según proceda), que es el archivo en que se especifican los valores de la base de datos necesarios para que Courier pueda acceder a ella para identificar a los usuarios, obtener la rutas hacia sus mailbox (los directorios que contendrán los mensajes de cada usuario) y el resto de información necesaria.

Lo primero es la información de conexión (servidor, usuario/password, etc). Dicho usuario/password son los que ya habíamos creado cuando instalamos la base de datos (arriba, en el apartado Creación de la base de datos de usuarios).

Esta información de conexión se indica utilizando las directivas:

  • PGSQL_HOST: Dirección del servidor de base de datos. En nuestro caso es localhost, ya que tanto Courier como la base de datos están en el mismo servidor.
  • PGSQL_PORT: Puerto en el que está escuchando la base de datos. El puerto por defecto de PostgreSQL es el 5432 y el de MySQL es el 3306.
  • PGSQL_USERNAME: Usuario que utilizará Courier para conectarse a la base de datos. Nosotros habíamos creado el usuario app_courier para esto.
  • PGSQL_PASSWORD: Password del usuario definido en PGSQL_USERNAME.

NOTA: Si por algún motivo quisiéramos conectar a un servidor de base a través de un socket local en lugar de a través de la red, debemos eliminar la directiva PGSQL_HOST e indicar en la directiva PGSQL_PORT el número de dicho socket. Por ejemplo, si nuestro socket local de base de datos es /tmp/.s.PGSQL.5400, debemos indicar el valor 5400 en PGSQL_PORT.

El archivo de configuración quedaría entonces así:

##NAME: LOCATION:0
#
# The server hostname, port, userid, and password used to log in.

PGSQL_HOST     localhost
PGSQL_PORT     5432
PGSQL_USERNAME app_courier
PGSQL_PASSWORD OQ5JQ3+pNR

Por supuesto, si en lugar de PostgreSQL estuviéramos utilizando MySQL, debemos cambiar el PGSQL_ por MYSQL_ en las directivas del archivo de configuración. Ya se que es obvio, pero lo comento por si acaso os estáis limitando a copiar-y-pegar sin enterder lo que estamos haciendo (merluzos!! hay que leerlo todo, que para algo llevo semanas escribiendo éste artículo! xDDD).

El resto del archivo de configuración es muy sencillo, y casi todas sus directivas son autoexplicativas, pero vamos a dar un pequeño repaso al resto de ellas:

  • PGSQL_DATABASE: Aquí se indica el nombre de la base de datos que contiene las tablas donde se encuentra la información de los usuarios.
  • PGSQL_USER_TABLE: Nombre de la tabla que contiene la información de los usuarios.
  • PGSQL_CRYPT_PWFIELD: Nombre del campo (columna) que contiene la password cifrada de los usuarios.
  • DEFAULT_DOMAIN: Si definimos éste parámetro, si alguien intenta autenticarse (por ejemplo) con el usuario fulanito, Courier lo sustituirá po fulanito@DEFAULT_DOMAIN. Esto es útil cuando el username de nuestros usuarios es su dirección de email, y nuestro servidor únicamente se usa para el correo de un solo dominio, de forma que la gente puede utilizar el username sin tener que teclear el resto hasta completar la dirección (@DEFAULT_DOMAIN).
  • PGSQL_UID_FIELD: UID del usuario local del servidor que se usará para acceder a los emails del servidor. Típicamente se suele utilizar el usuario del sistema postfix, ya que al guardarse dichos emails usando ese usuario, nos aseguramos así de tener permisos para acceder a dichos archivos. Para saber qué UID tiene un usuario en cuestión podemos usar el comando id (pasándole como parámetro el nombre del usuario del que queremos obtener la información). Por ejemplo: id postfix. En nuestro caso el valor obtenido es el 103, pero asegúrate de comprobar cuál es el que necesitas tu ya que puede variar de un sistema a otro.
  • PGSQL_GID_FIELD: En éste caso hay que indicar el GID del grupo que utilizaremos para acceder a los emails del servidor. Típicamente se suele utilizar el grupo mail, por lo que para averiguar el gid de dicho grupo podemos utilizar de nuevo el comando id mail. En nuestro caso el valor obtenido es el 8, pero al igual que antes, asegúrate de comprobar cuál es éste gid en tu sistema.
  • PGSQL_LOGIN_FIELD: Nombre del campo (columna) que contiene los usernames de los usuarios.
  • PGSQL_HOME_FIELD: Nombre del campo (columna) que contiene la ruta a la home del usuario (no confundir con la ruta de los mailbox).
  • PGSQL_MAILDIR_FIELD: Nombre del campo (columna) que contiene la ruta de los mailboxes de los usuarios. Normalmente los mailbox suelen estar en la ruta $HOME/Maildir, donde $HOME es el valor especificado en PGSQL_HOME_FIELD.
  • PGSQL_QUOTA_FIELD: Nombre del campo (columna) que contiene la información sobre la cuota de disco de los usuarios.
  • PGSQL_WHERE_CLAUSE: Aquí podemos indicar una condición que deberán cumplir los usuarios para poder identificarse en nuestro servidor. La condición aquí especificada se añadirá como WHERE en la consulta SQL que Courier ejecutará cuando un usuario intente autenticarse en nuestro servidor. Es muy útil para (por ejemplo) restringir temporalmente el acceso a un usuario en concreto sin tener que eliminarlo, simplemente utilizando una columna "user_active" como la que hemos creado en la tabla de usuario, o algo similar. Os quedará más claro viendo el ejemplo del archivo de configuración que pondré a continuación.

Por lo tanto el archivo /etc/courier/authpgsqlrc debería quedar más o menos así:

PGSQL_HOST          localhost
PGSQL_PORT          5432
PGSQL_USERNAME      app_courier
PGSQL_PASSWORD      OQ5JQ3+pNR

PGSQL_DATABASE      email
PGSQL_USER_TABLE    users

PGSQL_CRYPT_PWFIELD "password_crypt"
PGSQL_UID_FIELD     103
PGSQL_GID_FIELD     8
PGSQL_LOGIN_FIELD   "login"
PGSQL_HOME_FIELD    '/'
PGSQL_NAME_FIELD    concat("name", " ", "surname")
PGSQL_MAILDIR_FIELD "path_maildir"
PGSQL_WHERE_CLAUSE  "imap_access"='1' AND "user_active"='1'

Y con esto ya deberíamos tener Courier listo... así que ya solo queda levantar los servicios. Primero authdaemon (para autenticar a los usuarios) y luego los servicios propios de IMAP e IMAP-SSL:

$ sudo /etc/init.d/courier-authdaemon start
$ sudo /etc/init.d/courier-imap start
$ sudo /etc/init.d/courier-imap-ssl start

Configurar el servicio IMAP a través de SSL (algo MUY importante) no tiene ningún misterio. Si vais a utilizar certificados SSL generados por vosotros mismos y autofirmados, basta con que levanteis el servicio courier-imap-ssl sin más. Y si tenéis certificados SSL propios y firmados, solo hay que configurar dichos certificados en el archivo /etc/courier/imapd-ssl antes de levantar el servicio, y listo.

Es importante que os aseguréis de tener instalado en el servidor el servicio Gamin, un sub-sistema de FAM (File Alteration Monitor). Se trata de un demonio encargado de notificar a algunos programas (a Courier, por ejemplo) los cambios que se producen en algunos archivos del disco. Es necesario instalarlo porque Courier-imap necesita estar al tanto de esos cambios a la hora de notificar a los clientes de correo. Si no lo instalamos, algunos clientes de correo podrían mostrar incómodos mensajes de error (aunque el funcionamiento del correo no debería verse afectado en la mayoría de los casos).

De todas formas, instalarlo es tan sencillo como siempre:

En Debian/Ubuntu:

$ sudo apt-get install gamin

En RedHat/CentOS:

$ sudo yum install gamin

Una vez hecho esto, ya debería funcionar perfectamente (tanto la recepción de emails mediante SMPT->Postfix como el acceso a ellos mediante IMAP->Courier). Así que si todo ha ido bien, ya deberíais poder configurar la cuenta en vuestro cliente de correo. Existen muchísimos clientes de correo diferentes (Thunderbird, Evolution, KMail, etc) por lo que no entraré en detalles sobre cómo configurar una cuenta en ellos, pero no tiene ningún misterio... es igual que cualquier otra cuenta de correo que hayais configurado, solo que indicando los datos de conexión de vuestro servidor (la dirección del host donde lo habeis instalado) y los datos de acceso a vuestra cuenta (según el ejemplo que os he puesto, usuario bill, password galactica y dirección de email adama@pornohardware.com).

Por supuesto, y al igual que hicimos al configurar Postfix, debemos abrir los puertos necesarios para los servicios de IMAP e IMAP-SSL en nuestro firewall. Debeis abrir el puerto 143 para IMAP y el 993 para IMAP-SSL.

Si llegados a éste punto no pudiérais conectaros, o no pudiérais acceder con el usuario/password o hubiera algun otro error o comportamiento extraño, podéis editar el archivo /etc/courier/authdaemonrc y habilitar la directiva DEBUG_LOGIN=1 para aumentar el nivel de detalle en los logs del proceso de autenticación. Si lo haceis, no olvideis reiniciar los servicios de (courier-authdaemon, courier-imap y courier-imap-ssl) para que se reflejen los cambios.

El log por defecto donde se guarda toda la información relativa al correo (Postfix, Courier, etc) es /var/log/mail.log en Debian/Ubuntu, o /var/log/maillog en Redhat/CentOS.

Instalación de antivirus y antispam

No se concibe un servidor de correo hoy en día sin estos 2 servicios.

Debido a la ingente cantidad de emails que se intercambian cada día en Internet, el correo electrónico se ha convertido para los virus en el medio preferido para transmitirse por todo el mundo.

En mis tiempos, la única forma de coger un virus en tu ordenador era que alguien te pasara un disquete infectado (muchos no sabréis ni lo que es éso del disquete, jejeje). El número de virus en aquella época era bajísimo, e incluso los mejores de ellos tardaban muchísimo tiempo en propagarse (y aun así, jamás lograban expandirse como lo hacen hoy en día).

La llegada del correo electrónico facilitó la comunicación entre personas y sistemas por todo el mundo, sin importar las distancias físicas que hubiera entre los interlocutores de dichas comunicaciones. Rápidamente los virus aprovecharon ésta via para propagarse como lo hacen hoy en día.

Por desgracia, el usuario en general sigue siendo un mero usuario tonto (es decir, que prácticamente desconoce el funcionamiento de cualquier sistema, y se limita únicamente a usarlo casi a ciegas) por lo que no se puede confiar en que tengan un antivirus actualizado en sus ordenadores. Esta es una de las razones principales por las que es responsabilidad del servidor de correo interceptar y eliminar los virus antes de que lleguen al usuario (además, es más sencillo y tiene más sentido acabar con ellos ANTES de que lleguen a su destinatario que dejar ésta labor en sus manos).

Y con respecto al spam, la lacra de Internet que más odio, sucede exactamente lo mismo.

Cualquier persona con unos minimísimos conocimientos tecnológicos puede enviar miles de emails a millones de personas en cuestión de minutos sin invertir ni un solo euro, y además sin que los destinatarios de dichos emails puedan saber incluso quién se los está enviado.

Esto es aprovechado cada minuto del día por miles de spammers, que inundan los mailbox de todo el mundo con publicidad no solicitada.

Y aunque parezca una práctica inofensiva, el spam no solo cuesta ingentes candidades de dinero a las empresas y organizaciones que sostienen Internet debido a las grandes y sobredimensionadas infraestructuras que deben manejar para cubrir éste uso extra del correo electrónico (se estima que el 94% del correo mundial es spam, sino que provoca una enorme pérdida de tiempo y recursos personales a quienes padecen éste tormento.

Por todos estos motivos, un buen antivirus y algunos filtros antispam son absolutamente necesarios en todos los servidores de correo del mundo.

Para instalar y configurar estos elementos, la mejor forma de hacerlo es mediante un filtro de contenidos. Y en mi opinión, el mejor en éste campo es Amavis.

Podríamos definir Amavis (o mejor dicho, amavisd-new, que es como se llama realmente) como un interface que conecta el servidor de correo con otros programas (antivirus, antispams, etc) de forma transparente para el usuario.

Cuando un email llega a nuestro servidor de correo, éste se lo entrega a amavisd-new, el cual se encarga de pasárselo a los distintos filtros que tengamos configurados, y si el mensaje los supera, el servidor de correo lo almacena en el buzón del destinatario correspondiente. En caso contrario se pueden llevar a cabo diferentes acciones dependiendo de qué filtro haya sido el que ha bloqueado el email. Por ejemplo, se puede configurar para que si un email contiene un virus, automáticamente se envíe un mensaje a la persona que ha enviado el email advirtiéndole de que su ordenador podría estar infectado.

Existen varios programas antivirus libres, gratuitos y que funcionan muy bien en GNU/Linux. Personalmente el que más me gusta es ClamAV.

Uno de los puntos más importantes en este tipo de software es la rápida localización e inclusión en sus bases de datos de los nuevos virus que se van encontrando.

Gracias a los propios usuarios de ClamAV y a sitios como Virustotal.com a medida que se van identificando nuevos virus, troyanos o cualquier otro tipo de malware, estos son rápidamente introducidos en ClamAV, por lo que se su base de datos de virus se actualiza diariamente para que nuestro servidor se mantenga siempre al día.

El software que se encarga de mantener ClamAV actualizado es el llamado Freshclam, el cual forma parte del paquete ClamAV.

Y con respecto a los filtros antispam, también existen varios... aunque el que más destaca en el mundo open-source es SpamAssassin.

Dispone de multitud de filtros y reglas, y se le puede entrenar para que vaya aprendiendo a identificar qué mensajes son spam y cuáles no.

El funcionamiento normal de SpamAssassin es el de ir sometiendo los mensajes a diferentes tests, los cuales van emitiendo una puntuación en función de si consideran el mensaje sospechoso de ser spam o no. Estas puntuaciones individuales de cada test se van sumando, y si al finalizar todos el número obtenido supera el umbral que hayamos definido, el mensaje se considerará spam y o bien será rechazado (de forma que el destinatario jamás llegará ni siquiera a verlo) o bien se entregará a su destinatario normalmente, pero añadiendo una serie de cabeceras al email que lo identifiquen como spam para que sea el usuario el que determine qué hacer con él.

Ambos programas (ClamAV y SpamAssassin) están perfectamente integrados en Amavis, por lo que la instalación de todo esto es (como de costumbre) algo trivial en GNU/Linux:

En Debian/Ubuntu:

$ sudo apt-get install amavisd-new spamassassin clamav-daemon clamav-freshclam

En RedHat/CentOS:

$ sudo yum install amavisd-new clamav spamassassin

Los virus en los emails suelen ir en los archivos adjuntos que hay en ellos... pero dichos archivos a veces están comprimidos, lo cual impide que el antivirus pueda analizarlos. Para evitar esto, debemos instalar los descompresores de los formatos más comunes (zip, arj, rar, etc).

Para ello, instalamos los siguientes paquetes:

En Debian/Ubuntu:

$ sudo apt-get install bzip2 gzip xzip rpm lzop unrar-free arj p7zip-full zoo arc cabextract

En RedHat/CentOS:

$ sudo yum install bzip2 gzip rpm lzop arj p7zip unzoo arc cabextract

Para configurar Amavis debemos editar algunos archivos:

  • /etc/amavis/conf.d/05-domain_id: En éste archivo debemos indicar el dominio principal de nuestro servidor. Hay dos formas de hacerlo: o bien asignando directamente el nombre del dominio a la variable $mydomain, o bien indicando en dicha variable que obtenga el valor del archivo /etc/mailname, con lo que indicaríamos el dominio en dicho archivo. En nuestro caso utilizamos pornohardware.com.
  • /etc/amavis/conf.d/05-node_id: En éste archivo debemos indicar (del mismo modo que en el anterior) el nombre del servidor. En nuestro caso utilizamos mail.pornohardware.com.
  • /etc/amavis/conf.d/15-content_filter_mode: Descomentando la linea correspondiente en éste archivo habilitaremos el uso del antivirus (en éste caso, ClamAV) y del antispam (Spamassassin). Si por algún motivo no quisiéramos que Amavis utilizara alguno de los dos, bastaría con dejar comentada la linea correspondiente.
  • /etc/amavis/conf.d/20-debian_defaults: La mayoría de las opciones de configuración se encuentran aquí. Los nombres de las variables son bastante descriptivos y hay bastantes comentarios en el archivo. Las principales opciones que debemos configurar son:
    • $sa_spam_subject_tag: Aquí definimos el prefijo que se antepondrá al título de los emails que Amavis considere como spam. Yo suelo utiliza [SPAM] (incluyendo un espacio en blanco al final).
    • $final_banned_destiny: Aquí definimos la acción que queremos que Amavis lleve a cabo cuando un mensaje sea *baneado por contener un virus. Los posibles valores son:
      • D_DISCARD: Rechaza el mensaje SIN informar al remitente.
      • D_BOUNCE: Rechaza el mensaje informando al remitente a través de amavisd-new (éste es el valor que yo suelo utilizar).
      • D_REJECT: Rechaza el mensaje informando a través del MTA.
      • D_PASS: Acepta el mensaje.
    • $final_spam_destiny: Lo mismo que en el caso anterior, pero para los mensajes que Amavis haya marcado como spam.

Después, debemos añadir el usuario sobre el que se ejecuta el demonio de ClamAV (clamav) al grupo amavis para que éste tenga los permisos necesarios. Para ello utilizamos el comando vigr, o si lo prefieres, a través del comando:

$ sudo usermod -G amavis clamav

En cuanto a Spamassassin, por ahora únicamente editamos el archivo /etc/default/spamassassin para que el demonio se inicie, poniendo a 1 el valor de la directiva ENABLED:

# /etc/default/spamassassin
# Duncan Findlay

# WARNING: please read README.spamd before using.
# There may be security risks.

# Change to one to enable spamd
ENABLED=1

Para conectar Amavis a nuestro SMTP, debemos indicar en la configuración de Postfix el puerto en el que Amavis escucha. Editamos su configuración (archivo master.cf) y lo indicamos:

#
# 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}
smtp-amavis unix -      -       y       -       2       smtp
        -o smtp_data_done_timeout=1200
        -o disable_dns_lookups=yes
# Filtro para Amavis/Postfix
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

Ahora solo hay que indicar en el otro archivo de configuración de Postfix (main.cf) que el filtro de contenidos que vamos a usar está en dicho puerto:

virtual_mailbox_maps            = mysql:/etc/postfix/mysql/mysql_virt.cf
virtual_maps                    = mysql:/etc/postfix/mysql/alias.cf
local_transport                 = virtual

# Amavis
content_filter                  = smtp-amavis:[127.0.0.1]:10024

soft_bounce                     = no
unknown_local_recipient_reject_code = 550

Ahora que está todo configurado, iniciamos los servicios que acabamos de instalar y configurar, y reiniciamos Postfix:

$ sudo /etc/init.d/clamav-daemon start
$ sudo /etc/init.d/clamav-freshclam start
$ sudo /etc/init.d/spamassassin start
$ sudo /etc/init.d/amavis start
$ sudo /etc/init.d/postfix restart

Si hubiera algún problema o alguno de los demonios no se iniciara correctamente, ya sabes que toda la información de los procesos relacionados con el email está en /var/log/mail.log (si usas Debian/Ubuntu) o en /var/log/maillog (si usas Redhat/CentOS).

Pero contra el SPAM nunca se está completamente protegido... y obviamente Spamassasin nos ayudará a frenarlo, pero no lo evitará al 100%. Por lo tanto, aún hay más cosas que podemos hacer para completar nuestro sistema.

PostGrey

La primera de ellas se llama PostGrey, y aunque hay gente que piensa que es tan efectiva como molesta para el usuario, es una de las mejores medidas que podemos implantar para reducir la cantidad de spam que llegue a nuestros buzones.

El protocolo de envío de correo establece que si se intenta enviar un email a un servidor, y éste responde con un código de error 45x (error temporal), se debe intentar volver a enviar el email pasado un tiempo (normalmente 5 minutos después).

La mayoría de los servidores de correo que utilizan los spamers no están configurados correctamente, y NO reintentan el envío de un email si éste falla.

Postgrey hará que siempre que nos llegue un email de un destinatario desconocido, se rechace el email y se responda con un error 45x. Si el servidor está correctamente configurado, reintentará de nuevo la entrega pasados unos minutos... y cuando lo haga, Postgrey lo aceptará. Además, se guardará dicho remitente en una base de datos propia de Postgrey, por lo que a partir de ese momento se aceptarán los emails de éste remitente a la primera, sin necesidad de volver a rechazarlos.

Puede que sea un poco molesto en alguna circunstancia (sobre todo si necesitamos recibir un email urgente de alguien que no nos ha escrito antes) ya que tardaremos más de lo normal en recibir dicho email, pero gracias a esto evitaremos recibir un montón de spam.

La instalación de Postgrey es igual de sencilla que el resto:

En Debian/Ubuntu:

$ sudo apt-get install postgrey

En RedHat/CentOS:

$ sudo yum install postgrey

Una vez instalado, el puerto por defecto en el que estará escuchando PostGrey es el 10023, así que tenemos que añadirlo como una nueva restricción en nuestro Postfix (en el mismo sitio donde anteriormente habíamos configurado las blacklists y el resto de restricciones):

smtpd_recipient_restrictions = regexp:/etc/postfix/blacklist,
                               permit_mynetworks,
                               reject_invalid_hostname,
                               reject_non_fqdn_sender,
                               reject_non_fqdn_recipient,
                               reject_unknown_sender_domain,
                               reject_unknown_recipient_domain,
                               permit_sasl_authenticated,
                               reject_unauth_destination,
                               check_policy_service inet:127.0.0.1:10023,
                               regexp:/etc/postfix/blacklist,
                               permit

Ya podemos iniciar el demonio de PostGrey:

$ sudo /etc/init.d/postgrey start

Y reiniciar Postfix para que tenga en cuenta la nueva restricción:

$ sudo /etc/init.d/postfix restart

A partir de éste momento, cada vez que nos llegue un email, Postfix lo rechazará temporalmente para que el servidor de correo del remitente lo intente de nuevo pasados unos minutos.

Si transcurrido ese tiempo el servidor de correo de dicho remitente reintenta el envío de nuevo, Postfix lo aceptará normalmente, y marcará en su base de datos interna que ya no será necesario volver a rechazar correos de ese destinatario en el futuro.

Si alguna vez migrais el servidor de correo a otro servidor diferente, y quereis conservar ésta base de datos interna con los datos que PostGrey haya conseguido hasta ese momento, basta con que migreis también el contenido de /var/lib/postgrey/ al nuevo servidor.

Y por supuesto, podéis especificar también excepciones (whitelists) para que PostGrey no rechace los emails ni siquiera la primera vez editando los archivos /etc/postgrey/whitelist_recipients y /etc/postgresy/whitelist_clients.

No olvideis que ~~podéis~~ debéis revisar el log del servidor de correo a menudo por si hubiera algún problema o algún comportamiento no deseado, que como ya sabeis se encuentra en /var/log/mail.log si usais Debian o similares, y en /var/log/maillog si usais CentOS/RedHat.

Y para poder dar por terminadas las configuraciones relativas al spam, solo nos faltaría implementar el sistema SPF en nuestro servidor:

SPF (Sender Policy Framework)

El sistema SPF intenta disminuir el spam evitando la falsificación de las direcciones de correo electrónico de los mensajes. Y su principal implementación es el proyecto OpenSPF.

Bajo mi punto de vista es una medida de seguridad MUY buena, y realmente sería útil si todos los servidores de correo lo utilizaran de forma predeterminada y obligatoria... pero por desgracia no lo hacen, y lo que es aún peor, muchos de los administradores de sistemas que gestionan servidores de correo ni siquiera saben de su existencia.

Su funcionamiento es muy simple: dado que la dirección del remitente de un email viene indicada únicamente en una de las cabeceras del email, cualquiera puede manipular dicha cabecera y enviar un email con un remitente falso.

No se necesitan grandes conocimientos ni herramientas avanzadas, cualquier lamer puede enviar un email a cualquier persona haciéndose pasar por cualquiera. Y los spamers utilizan esto a diario para simular emails de personas conocidas o de sitios webs de interés, de forma que aumentan las posibilidades de que al recibir esos emails, caigamos en la trampa y los leamos.

SPF intenta evitar esto, rechazando los emails que provengan de servidores de correo que NO son los servidores de correo oficiales de dicho dominio. Es decir, si el servidor de correo de pornohardware.com tiene la IP 1.2.3.4 (por ejemplo), si un servidor de correo recibe un email de una dirección del tipo @pornohardware.com que proviene de la IP 5.6.7.8, automáticamente lo rechazará porque asumirá que no se trata de un email legítimo. SPF da por sentado que para enviar emails del dominio @pornoharware.com únicamente se van a utilizar unos servidores determinados (los que el Todopoderoso administrador de pornohardware.com haya configurado), por lo que si un email proviene de otro sevidor dirente, muy seguramente se trate de un email NO legítimo (spam).

El sistema SPF consta de 2 partes:

  • Incluir un registro en el DNS de nuestro dominio que sirva para que los demás servidores de correo sepan cuales son nuestros servidores legítimos, y rechacen emails que (aunque parezca que provinien de nosotros) hayan sido enviados desde otros servidores.
  • Configurar nuestro servidor de correo para que cuando nos llegue un email, comprobemos en el DNS del dominio del remitente del email si efectivamente dicho mensaje proviene de un servidor autorizado o no.

El paso 1 es tan sencillo como incluir un registro de tipo TXT que indique quiénes son los servidores que pueden enviar nuestros emails.

La sintaxis de estos registros es muy sencilla:

  • v: Con éste parámetro se indica la versión de SPF (que actualmente es la 1).
  • mx: Con éste parámetro se indica que los servidores de correo configurados en el registro de tipo MX de nuestro dominio están autorizados a enviar email de dicho dominio.
  • ptr: Con éste parámetro se indica que los servidores correspondientes a subdominios de nuestro dominio están autorizados a enviar nuestros emails. Es decir, cualquier servidor cuyo nombre sea *.pornohardware.com.
  • all: Dependiendo del código que indiquemos aquí, los servidores serán más o menos estrictos a la hora de recibir nuestros correos. Los posibles valores de éste parámetro son:
    • -all: NO se deben aceptar emails nuestros que provengan de servidores que NO son los especificados en el registro SPF de nuestro DNS.
    • ~all: Se deben aceptar emails nuestros aunque provengan de servidores que NO son los especificados en el registro SPF de nuestro DNS, pero marcando dichos emails como posible SPAM, de forma que sea los clientes de correo de los usuarios finales quiens puedan establecer reglas para aceptar o no dichos emails.
    • ?all: Se deben aceptar emails nuestros aunque provengan de servidores que NO son los especificados en el registro SPF de nuestro DNS.

Vistas éstas opciones, un ejemplo de registro TXT para el SPF del dominio pornohardware.com sería:

pornohardware.com.  IN TXT "v=spf1 mx a:mail.ejemplo1.com a:mail.ejemplo2.com -all"

Éste registro especificaría como válidos para enviar emails de nuestro dominio a aquellos servidores que estén definidos en los registros MX de nuestro dominio, y también los servidores mail.ejemplo1.com y mail.ejemplo2.com. Y al haber especificado -all, aquellos servidores que reciban un email proveniente de un servidor diferente a los que acabamos de mencionar, deben RECHAZAR dicho email.

Existen muchos servicios en Internet que os pueden ayudar a configurar online el registro SPF de vuestro dominio, como por ejemplo SPF Wizard.

De ésta forma hemos configurado nuestro DNS para que los demás servidores de correo del mundo sepan cuáles son nuestros servidores... pero ahora tenemos que hacer que nuestro servidor haga esa misma comprobación cuando llegue un email de los demás, y rechazar dichos emails si hubieran sido enviados por servidores distintos a los que esos dominios hayan autorizado.

Para eso necesitamos postfix-policyd-spf-python o postfix-policyd-spf-perl, un programa escrito en Python o Perl respectivamente, y que permite a Postfix consultar el registro SPF del dominio de los emails que llegan a nuestro servidor para determinar la acción a realizar en cada caso.

En distribuciones basadas en Redhat/CentOS no existe una versión precompilada disponible en los repositorios oficiales, por lo que debereis descargarlo desde https://www.open-spf.org/Software e instalarlo de forma manual (únicamente hay que copiarlo en el directorio apropiado, como /usr/bin o algo similar).

En distribuciones basadas en Debian/Ubuntu, como siempre es tan fácil como ejecutar:

$ sudo apt-get install postfix-policyd-spf-python

Después, editamos de nuevo el archivo master.cf de Postfix, y lo incluimos justo después de la configuración que habíamos creado para Amavis:

# Filtro para Amavis/Postfix
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

# postfix-policyd-spf-python
policyd-spf unix - n n - - spawn
     user=nobody argv=/usr/bin/policyd-spf

Y por último, editamos también el archivo main.cf para indicar a Postfix que use el filtro que acabamos de configurar (justo en la sección de restricciones que habíamos utilizado para añadir el filtro de PostGrey):

smtpd_recipient_restrictions = regexp:/etc/postfix/blacklist,
                               permit_mynetworks,
                               reject_invalid_hostname,
                               reject_non_fqdn_sender,
                               reject_non_fqdn_recipient,
                               reject_unknown_sender_domain,
                               reject_unknown_recipient_domain,
                               permit_sasl_authenticated,
                               reject_unauth_destination,
                               check_policy_service inet:127.0.0.1:10023,
                               check_policy_service unix:private/policyd-spf,
                               regexp:/etc/postfix/blacklist,
                               permit

Reiniciamos Postfix, y ya tenemos nuestro servidor preparado para hacer frente al maldito spam!

$ sudo /etc/init.d/postfix restart

Estadísticas y monitorización

Ahora que ya tenemos el servidor completo funcionando al 100% no podemos abandonarlo a su suerte y esperar que siga funcionando durante el resto de nuestras vidas sin ni siquiera dedicarle un mínimo de atención. No me refiero a que haya que estar pendiente de él cada día, pero sí que conviene al menos tener monitorizados algunos de sus valores, sobre todo a la hora de identificar posibles cuellos de botella o picos de actividad que puedan darnos algún indicativo de que algo no va bien, o de que necesitamos ampliar el hardware de nuestros sistemas para hacer frente a la demanda...

Dejando al margen las recomendaciones obvias sobre monitorización propia de los servicios de nuestro sistema (me refiero a algún software para detectar y avisar si alguno de ellos cae, tipo Nagios o similar) lo que pretendo explicar es la monitorización del USO que se le da a nuestro sistema.

Los 3 principales programas que yo conozco y suelo utilizar para monitorizar el uso de mis servidores de correo son:

  • mailgraph: Éste programa muestra gráficas en tiempo real sobre el uso de Postfix, tales como emails recibidos, emails enviados, etc. y genera gráficas con la información diaria, semanal, mensual y anual.
  • queuegraph: Lo mismo que el anterior, pero con información acerca de la cola de mensajes (número de mensajes encolados, mensajes mensajes enviados, etc).
  • couriergraph: Lo mismo que los dos anteriores, pero con información sobre las conexiones a Courier (conexiones IMAP, conexiones POP, etc).

Los 3 programas son muy parecidos, y se basan en RDD para almacenar la información, por lo que no necesitan servidores de base de datos a los que conectarse ni tienen apenas ninguna dependencia. Simplemente se instalan en el mismo servidor donde están los servicios que queremos monitorizar, y desde un navegador accedemos a una URL concreta para ver las gráficas generadas.

La instalación, como siempre, no puede ser más sencilla en distribuciones basadas en Debian/Ubuntu:

$ sudo apt-get install mailgraph queuegraph couriergraph

Y en distribuciones basadas en Redhat/CentOS:

$ sudo yum install mailgraph queuegraph couriergraph

En el caso de distribuciones basadas en Redhat/CentOS, quizás couriergraph no se encuentre en los repositorios oficiales (ahora mismo no lo está, aunque juraría que lo ha estado) por lo que si es vuestro caso, debereis instalarlo manualmente en lugar de a través de yum.

Una vez los hayais instalado, basta con abrir un navegador y acceder a dichos CGIs tecleando en la barra de direcciones: http://localhost/cgi-bin/mailgraph.cgi, http://localhost/cgi-bin/queuegraph.cgi o http://localhost/cgi-bin/couriergraph.cgi (en lugar de localhost, quizás en vuestro caso debais poner la dirección del servidor donde los hayais instalado).

Si lo habeis instalado bien, al acceder a esas URLs deberías ver algo parecido a esto:

mailgraph:

queuegraph:

couriergraph:

Y con respecto a tener un informe más o menos detalladado sobre el número de emails que se han enviado/recibido, destinatarios que más correo han enviado/recibido, dias que más emails se han enviado/recibido, etc. yo recomiendo el programa Isoqlog.

Con este software, y a base de la información que se obtiene del log del servidor (/var/log/mail.log o /var/log/maillog) se pueden generar informes bastante detallados y útiles sobre la actividad individual de cada usuario y obtener así una visión mucho más amplia del uso que se le da a nuestro servidor.

De nuevo la instalación es trivial en Debian/Ubuntu:

$ sudo apt-get install isoqlog

Y para el resto de distribuciones, se puede descargar tanto el código fuente como paquetes RPM desde la web del proyecto: http://www.enderunix.org/isoqlog/

Una vez instalado, únicamente hay que definir un cron para que genere los informes cada cierto tiempo. Yo lo suelo hacer cada 12 horas, así tengo los informes detallados actualizados 2 veces al día, pero realmente puedes ponerlo cuando quieras.

La configuración es extremadamente simple: basta con indicar en el archivo de configuración (generalmente /etc/isoqlog/isoqlog.conf) la ruta donde está el log del servidor de correo, el directorio donde queremos que se guarden los informes que se irán generando, el idioma en el que queremos dichos informes, etc. Y en el archivo /etc/isoqlog/isoqlog.domains únicamente indicamos la lista de dominios a los que nuestro servidor de correo prestará servicio (es decir, los dominios que habíamos configurado en las directivas mydestination y relay_domains del archivo /etc/postfix/main.cf)

  • /etc/isoqlog/isoqlog.conf

    #isoqlog 2.0 Configuration file
    
    logtype     = "postfix"
    logstore    = "/var/log/mail.log"
    domainsfile = "/etc/isoqlog/isoqlog.domains"
    outputdir   = "/var/www/reports"
    htmldir     = "/usr/share/isoqlog/htmltemp"
    langfile    = "/usr/share/isoqlog/lang/english"
    hostname    = "mail.pornohardware.com"
    
    maxsender   = 100
    maxreceiver = 100
    maxtotal    = 100
    
    maxbyte     = 100
    
  • /etc/isoqlog/isoqlog.domains

    pornohardware.com
    pornosoftware.com
    

Para generar el informe de forma manual basta con ejecutar el comando:

$ sudo isoqlog

Una vez generados, los informes son algo parecido a esto:

Como veis la información que muestran todos estos sistemas de monitorización es MUY útil, por lo que sumado a la monitorización global del servidor (con Cacti, Zabbix o similar) nos permitirán mantener nuestro recién instalado servidor en perfecto funcionamiento durante el tiempo que haga falta.

Y de momento aquí se acaba éste artículo, que ya va siendo hora!

Espero que toda ésta chapa que he escrito os sirva de ayuda a la hora de configurar vuestro propio servidor de correo, ya sea porque os lo han pedido en vuestra empresa o porque habeis decidido tener el control de vuestro propio correo personal, lo cual es una de las mejores cosas que podéis hacer en la vida si de verdad os preocupa lo más mínimo vuestra privacidad y la seguridad de vuestros datos y conversaciones. Por favor, no hagais como la gran masa tonta y delegueis la gestión de vuestro email a ladrones y estafadores con doble moralidad (como Google/Gmail y todas esas grandes empresas) que no dudarán en parsear, etiquetar y catalogar incluso vuestros emails más personales con la excusa de mostraros publicidad más relevante (como si además eso fuera algo bueno).

He tenido especial cuidado a la hora de enumerar los comandos, configuraciones, etc. y he ido contrastándolo paso a paso con mis actuales servidores de correo para verificar que toda la información que os he puesto es correcta... pero por supuesto he podido cometer algún fallo (ja-ja) xDDDD.

Si se ha dado éste remoto y extrañísimo caso, por favor, decírmelo (escribirlo en los comentarios del artículo) y lo corregiré lo antes posible.

Y por supuesto, no dudeis en distribuir y compartir ésta información con todo el mundo... pero por favor, citar siempre la fuente de éste artículo, que después de la cantidad de horas y trabajo que me ha costado escribirlo, al menos darme el reconocimiento apropiado! xDDD

Alaaaaaaaaaaaaaaaa

Referencias