No hay nada que te envejezca más rápido que una caída del correo cuyo motivo raíz sea “nos convertimos en un relay abierto”. Un minuto estás enviando una versión normal; al siguiente ves tu IP pública en listas negras mientras tu CEO pregunta por qué “nuestro servidor de correo está enviando spam a Moldavia”.
Esto no es un riesgo teórico. Es un modo de fallo de configuración con pruebas claras y repetibles y evidencia inequívoca en los logs. La solución es aburrida, precisa y completamente controlable. Hagámoslo como exigen los sistemas en producción: pruébalo, compruébalo, ciérralo y documenta el proceso para que no vuelva a aparecer.
Qué significa realmente “relay abierto” (y qué no)
Un relay abierto es un servidor SMTP que aceptará un mensaje de un cliente no autenticado y no confiable y lo reenviará a un dominio tercero. En términos claros: un host aleatorio en Internet se conecta a tu Postfix, le entrega un mensaje “de” cualquiera “a” cualquiera, y tu servidor acepta entregarlo hacia el exterior.
Eso es el núcleo. Todo lo demás es ruido.
- No es un relay abierto: un servidor que acepta correo para sus propios dominios (
mydestination, dominios virtuales) desde Internet y entrega localmente. - No es un relay abierto: un servidor que reenvía correo saliente solo para usuarios autenticados (SASL en submission) o redes de confianza (
mynetworks). - Sí es un relay abierto: acepta correo desde fuentes arbitrarias y lo reenvía a destinos arbitrarios.
El malentendido peligroso: “Estamos detrás de un firewall” o “El puerto 25 es solo para inbound” puede convertirse en “Vale, permitamos relaying desde 10.0.0.0/8” y entonces alguien añade una VPN, una subred mal enrutada o una red de contenedores que no debería ser de confianza. Felicidades: le has dado a tu infraestructura el equivalente por email de un pase de invitado que nunca expira.
Exactamente lo que debes poder afirmar: “Desde una IP no confiable, sin autenticación, Postfix rechaza intentos de relaying hacia destinos no locales con un error de política claro.” Esa es tu prueba. Todo lo demás son sensaciones.
Hechos e historia: por qué esto sigue sucediendo
Los relays abiertos son un problema antiguo, pero reaparecen porque el correo es un campo minado de compatibilidad y la gente lo trata como una casilla a marcar.
- El SMTP temprano asumía una red amigable. El ecosistema de correo original se comportaba como un club donde todos se conocían. Esa suposición murió en Internet público.
- En los años 90 los relays abiertos estaban por todas partes. Se configuraban para “ayudar” a usuarios dial-up o redes comerciales mal configuradas.
- Las listas negras se volvieron un mecanismo de supervivencia. Cuando el spam explotó, operadores empezaron a publicar IPs de relays y spammers. La entregabilidad pasó a ser una propiedad operacional, no solo técnica.
- Postfix se diseñó para ser más seguro por defecto. Una razón para su adopción es que buscaba ser secure-by-default comparado con la cultura de “edita este archivo y reza”.
- Submission (587) existe porque el puerto 25 es complicado. La industria separó SMTP servidor-a-servidor de “envío por usuario” para mejorar la autenticación y control de políticas.
- SASL y TLS no “resolvieron” el spam, pero cambiaron dónde aplicas la política. El diseño moderno es: autentica usuarios en 587, sé estricto en 25.
- NAT y redes cloud crearon nuevos límites de confianza. “IP interna” ya no significa “host controlado por operadores”. Puede significar “algún contenedor que olvidaste”.
- La misconfiguración es la causa dominante. Los relays abiertos rara vez son brechas sofisticadas. Suelen ser “pusimos
mynetworks=0.0.0.0/0durante una prueba y se nos olvidó”.
Una cita que merece estar en una nota adhesiva junto a tu config de MTA: “La esperanza no es una estrategia.”
— Gordon R. Dickson
Modelo de amenaza: cómo los atacantes encuentran y explotan relays
Los atacantes no necesitan “hackear” Postfix para abusar de él. Solo necesitan que diga “OK” en el momento equivocado.
Descubrimiento
Escanean. Constantemente. Rangos enteros de IPv4 son sondeados en busca de SMTP en 25, 465, 587. El host que escanea puede ser un nodo de botnet, un VPS o algo ya en listas negras. Verás conexiones breves, HELO que parecen una pulsación aleatoria del teclado e intentos rápidos de enviar a un dominio externo.
Explotación
Si se permite relay, el atacante entrega a tu servidor una pila de correo. Tu sistema se vuelve el cañón; tu IP se convierte en la huella. Pagas por ancho de banda, almacenamiento en cola, CPU y reputación.
Impacto
- Inmediato: crecimiento de la cola de correo, picos de uso de disco, saturación de workers SMTP, correo saliente legítimo retrasado o descartado.
- Secundario: listas negras; socios rechazan correo; correos de restablecimiento no llegan; tickets de soporte se multiplican.
- Largo plazo: la recuperación de entregabilidad lleva tiempo aun después de arreglar el relay. La reputación es persistente; también las listas negras.
Broma #1: Un relay abierto es como dejar un cartel de “envío gratis” en tu muelle de carga. Internet no tomará educadamente solo una caja.
Guía de diagnóstico rápido (primeras/segundas/terceras comprobaciones)
Si sospechas exposición por relay abierto —o estás respondiendo a “por qué la cola de correo explota”— no te pierdas en archivos de configuración como si buscaras una llave perdida. Ejecuta las mismas tres comprobaciones cada vez.
Primero: confirma el síntoma (¿estamos relaying?)
- Busca
status=senta dominios externos originados por IPs sospechosas. - Busca
Relay access denied(bueno) frente a relays exitosos (malo). - Comprueba si la afluencia está en el puerto 25 (servidor-a-servidor) o 587 (submission).
Segundo: identifica la puerta de política que falló
- Inspecciona
smtpd_recipient_restrictions,smtpd_relay_restrictions,mynetworksy ajustes SASL. - Confirma qué considera Postfix “local” mediante
mydestinationy mapas de dominios virtuales.
Tercero: detén la hemorragia de forma segura
- Endurece temporalmente las restricciones (rechaza relay desde todas partes excepto redes conocidas / auth).
- Aplica límites de tasa y/o rechaza clientes sospechosos; considera bloquear en el firewall si el tráfico es extremo.
- Gestiona y controla la cola (no borres a ciegas—identifica el alcance primero).
Una vez apagado el fuego, puedes hacer el trabajo más cuidadoso: demostrar comportamiento no relay desde fuera, validar la configuración de submission y actualizar runbooks.
Demuéstralo con pruebas: comandos, salidas, decisiones (12+ tareas)
Abajo hay tareas prácticas que puedes ejecutar en un host Linux típico con Postfix. El objetivo no es admirar la salida. Es tomar decisiones a partir de ella.
Task 1: Confirmar que Postfix está activo y en qué puertos escucha
cr0x@server:~$ systemctl status postfix --no-pager
● postfix.service - Postfix Mail Transport Agent
Loaded: loaded (/lib/systemd/system/postfix.service; enabled; preset: enabled)
Active: active (running) since Tue 2026-01-03 08:11:32 UTC; 3h 14min ago
Docs: man:postfix(1)
Main PID: 1223 (master)
Tasks: 4 (limit: 18921)
Memory: 18.4M
CPU: 1min 12s
Qué significa: Postfix está activo. Si no está en ejecución, no eres un relay abierto—simplemente estás caído.
Decisión: Procede a las comprobaciones de puertos. Si está inactivo, restaura el servicio primero y luego valida la configuración antes de reabrir el firewall.
cr0x@server:~$ ss -lntp | egrep ':(25|465|587)\s'
LISTEN 0 100 0.0.0.0:25 0.0.0.0:* users:(("master",pid=1223,fd=13))
LISTEN 0 100 0.0.0.0:587 0.0.0.0:* users:(("master",pid=1223,fd=15))
Qué significa: El puerto 25 y 587 están abiertos en todas las interfaces. Eso es normal para muchos servidores; también es la razón por la que debes ser estricto con la política de relaying.
Decisión: Si este host no debería aceptar SMTP público, enlaza a interfaces específicas o cierra puertos en el firewall/security group.
Task 2: Ver la configuración efectiva de Postfix (no lo que crees que pusiste)
cr0x@server:~$ postconf -n
myhostname = mx1.example.net
mydestination = $myhostname, localhost.example.net, localhost
mynetworks = 127.0.0.0/8 [::1]/128 10.10.0.0/16
smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination
smtpd_recipient_restrictions = permit_mynetworks,permit_sasl_authenticated,reject_unauth_destination
smtpd_sasl_auth_enable = yes
smtpd_tls_security_level = may
Qué significa: Esta es la configuración efectiva no por defecto. Te importan sobre todo mynetworks, smtpd_relay_restrictions y dónde aparece reject_unauth_destination.
Decisión: Si falta defer_unauth_destination o reject_unauth_destination, estás en territorio peligroso. Arréglalo inmediatamente.
Task 3: Verificar que mynetworks no sea “Internet disfrazada”
cr0x@server:~$ postconf mynetworks
mynetworks = 127.0.0.0/8 [::1]/128 10.10.0.0/16
Qué significa: Se confía en 10.10.0.0/16. Eso es aceptable solo si controlas totalmente esa red y puedes garantizar cada host que puede alcanzar el puerto 25/587.
Decisión: Si ves 0.0.0.0/0, 10.0.0.0/8 “porque es interno” o CIDRs de VPC que incluyen cargas de terceros o workloads transitorios, aprieta. Prefiere subredes explícitas para clientes de correo o evita usar permit_mynetworks para relaying por completo.
Task 4: Confirmar que las restricciones de relay están en el lugar correcto (matiz de versión de Postfix)
cr0x@server:~$ postconf smtpd_relay_restrictions
smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination
Qué significa: Postfix permitirá relaying para redes de confianza y clientes autenticados, y diferirá destinos no autorizados (efectivamente “no permitido”). Postfix moderno espera la política de relay aquí.
Decisión: Si smtpd_relay_restrictions está vacío o es demasiado permissivo, eres candidato a relay abierto. Arréglalo antes de hacer cualquier otra cosa.
Task 5: Probar comportamiento de relay desde el propio servidor (línea base)
Esta prueba no es suficiente por sí sola (porque localhost puede estar en mynetworks), pero confirma tus herramientas y la base de DNS.
cr0x@server:~$ swaks --server 127.0.0.1 --from test@external.example --to someone@gmail.com
=== Trying 127.0.0.1:25...
=== Connected to 127.0.0.1.
<-- 220 mx1.example.net ESMTP Postfix
--> EHLO server
<-- 250-mx1.example.net
<-- 250 PIPELINING
--> MAIL FROM:<test@external.example>
<-- 250 2.1.0 Ok
--> RCPT TO:<someone@gmail.com>
<-- 554 5.7.1 <someone@gmail.com>: Relay access denied
Qué significa: El servidor rechazó el relaying a Gmail. Eso es bueno. Si aceptó RCPT y procedió a DATA, eso es alerta roja.
Decisión: Aunque esto parezca bien, debes probar desde un host no confiable fuera de mynetworks.
Task 6: Probar comportamiento de relay desde un host externo (la prueba)
Ejecuta desde una máquina separada en Internet que no esté en tus redes de confianza y no esté autenticada. Usa un dominio de destino que no controles.
cr0x@server:~$ swaks --server mx1.example.net --from probe@external.example --to someone@yahoo.com --timeout 15
=== Trying 203.0.113.10:25...
=== Connected to 203.0.113.10.
<-- 220 mx1.example.net ESMTP Postfix
--> EHLO probehost
<-- 250-mx1.example.net
<-- 250 STARTTLS
--> MAIL FROM:<probe@external.example>
<-- 250 2.1.0 Ok
--> RCPT TO:<someone@yahoo.com>
<-- 554 5.7.1 <someone@yahoo.com>: Relay access denied
Qué significa: Esta es tu evidencia. El servidor rechaza el relaying para clientes externos no autenticados.
Decisión: Guarda esta salida (ticket, notas de incidente, evidencia de auditoría). Si no lo rechaza, trátalo como incidente.
Task 7: Confirmar que aún acepta correo entrante para dominios locales
cr0x@server:~$ swaks --server mx1.example.net --from probe@external.example --to postmaster@example.net --timeout 15
=== Trying 203.0.113.10:25...
=== Connected to 203.0.113.10.
<-- 220 mx1.example.net ESMTP Postfix
--> EHLO probehost
<-- 250-mx1.example.net
--> MAIL FROM:<probe@external.example>
<-- 250 2.1.0 Ok
--> RCPT TO:<postmaster@example.net>
<-- 250 2.1.5 Ok
--> DATA
<-- 354 End data with <CR><LF>.<CR><LF>
Qué significa: Tu servidor no está “cerrado para negocios”. Acepta correo para destinatarios locales mientras rechaza relay hacia terceros.
Decisión: Si la entrega local falla, revisa mydestination, mapas de dominios virtuales y tablas de destinatarios antes de tocar de nuevo las reglas de relay.
Task 8: Inspeccionar logs de correo para decisiones de relay (qué hizo Postfix realmente)
cr0x@server:~$ sudo grep -E "Relay access denied|reject_unauth_destination|status=sent" /var/log/mail.log | tail -n 20
Jan 03 10:44:11 mx1 postfix/smtpd[18844]: NOQUEUE: reject: RCPT from unknown[198.51.100.77]: 554 5.7.1 <someone@yahoo.com>: Relay access denied; from=<probe@external.example> to=<someone@yahoo.com> proto=ESMTP helo=<probehost>
Jan 03 10:44:42 mx1 postfix/smtpd[18845]: NOQUEUE: reject: RCPT from unknown[198.51.100.78]: 554 5.7.1 <random@gmail.com>: Relay access denied; from=<payroll@external.example> to=<random@gmail.com> proto=ESMTP helo=<workstation>
Qué significa: NOQUEUE y “reject at RCPT” es lo que quieres: rechazo barato antes de aceptar datos del mensaje.
Decisión: Si ves relays exitosos (status=sent) para clientes que no reconoces, comienza la contención y revisión de configuración ahora.
Task 9: Comprobar tamaño de la cola y si es spam descontrolado
cr0x@server:~$ mailq | head -n 20
-Queue ID- --Size-- ----Arrival Time---- -Sender/Recipient-------
A1B2C3D4E5 1423 Tue Jan 3 10:49:02 spammer@fake.example
victim1@gmail.com
F6G7H8I9J0 1501 Tue Jan 3 10:49:03 spammer@fake.example
victim2@yahoo.com
Qué significa: Destinatarios externos y remitentes sospechosos son un patrón clásico de abuso por relay. La cola consumirá disco e IOPS hasta que tu caja se convierta en un calentador muy caro.
Decisión: Si el crecimiento de la cola es activo, contiene: aprieta reglas de relay, bloquea IPs abusivas y considera límites temporales de tasa. Luego decide si purgar el spam en cola tras preservar evidencia.
Task 10: Inspeccionar un mensaje en cola específico (alcance y origen)
cr0x@server:~$ postcat -q A1B2C3D4E5 | sed -n '1,60p'
*** ENVELOPE RECORDS ***
message_size: 1423
message_arrival_time: Tue Jan 3 10:49:02 2026
sender: spammer@fake.example
recipient: victim1@gmail.com
*** MESSAGE CONTENTS ***
Received: from unknown (unknown [198.51.100.77])
by mx1.example.net (Postfix) with ESMTP id A1B2C3D4E5
for <victim1@gmail.com>; Tue, 3 Jan 2026 10:49:02 +0000 (UTC)
Subject: Urgent invoice
Qué significa: Muestra una conexión desde una IP no confiable. Esa es la evidencia contundente si se aceptó relay.
Decisión: Si confirmas abuso, preserva una muestra de cabeceras más líneas de log relevantes. Luego purga el spam y rota credenciales si hubo autenticación involucrada.
Task 11: Revisar master.cf por servicios no intencionados (submission, smtps, overrides de política)
cr0x@server:~$ sudo postconf -M | egrep '^(smtp|submission|smtps)/'
smtp/inet/smtp
submission/inet/submission
Qué significa: Los servicios existen. Eso está bien. El peligro son las sobreescrituras por servicio que accidentalmente permiten relay de forma amplia.
Decisión: Inspecciona los stanzas de submission y smtps por overrides -o que debiliten las restricciones.
cr0x@server:~$ sudo sed -n '1,160p' /etc/postfix/master.cf
smtp inet n - y - - smtpd
submission inet n - y - - smtpd
-o syslog_name=postfix/submission
-o smtpd_tls_security_level=encrypt
-o smtpd_sasl_auth_enable=yes
-o smtpd_recipient_restrictions=permit_sasl_authenticated,reject
Qué significa: Submission requiere TLS y autenticación, y rechaza de otro modo. Eso es bueno: evita la “submission anónima”.
Decisión: Si ves permit_mynetworks en submission sin un mynetworks estricto, estás confiando en la capa equivocada.
Task 12: Confirmar que SASL funciona realmente en 587 (o perforarás agujeros en otra parte)
cr0x@server:~$ swaks --server mx1.example.net --port 587 --tls --auth LOGIN --auth-user 'user@example.net' --auth-password 'wrongpass' --from user@example.net --to someone@gmail.com
=== Trying 203.0.113.10:587...
=== Connected to 203.0.113.10.
<-- 220 mx1.example.net ESMTP Postfix
--> EHLO probehost
<-- 250-AUTH PLAIN LOGIN
--> AUTH LOGIN
<-- 334 VXNlcm5hbWU6
--> dXNlckBleGFtcGxlLm5ldA==
<-- 334 UGFzc3dvcmQ6
--> d3JvbmdwYXNz
<-- 535 5.7.8 Error: authentication failed: authentication failure
Qué significa: El auth está aplicado. Contraseña incorrecta falla. Bien.
Decisión: Si el auth está “off” o no se anuncia, arregla eso en lugar de ampliar mynetworks como solución temporal.
Task 13: Validar dominios locales del servidor y evitar confusión “local = relay” por accidente
cr0x@server:~$ postconf mydestination
mydestination = $myhostname, localhost.example.net, localhost
Qué significa: Solo estos dominios se tratan como locales para la entrega clásica local. Si hospedas example.net como dominio entrante, debería aparecer vía virtual_mailbox_domains o similar, no necesariamente en mydestination.
Decisión: Mantén las definiciones de dominios locales precisas. Dominios locales demasiado amplios pueden causar bucles de enrutamiento y sorpresas de política.
Task 14: Confirmar qué IP piensa Postfix que es el cliente (trampas de proxy y balanceador)
cr0x@server:~$ postconf smtpd_upstream_proxy_protocol
smtpd_upstream_proxy_protocol =
Qué significa: No hay proxy protocol. Si estás detrás de un load balancer TCP o un proxy reverso para SMTP y has malconfigurado la preservación de IP de cliente, Postfix puede tratar a cada cliente como “interno” (la IP del proxy), concediendo relay por accidente.
Decisión: Si frontalizas SMTP con un proxy, diseña con cuidado: preserva la IP real del cliente y restringe según fuentes reales, no según el proxy.
Modelo mental de configuración de Postfix: las perillas que importan
Postfix puede parecer una bolsa de parámetros hasta que aprendes la forma del árbol de decisiones.
La distinción clave: aceptar correo vs reenviar correo
La política SMTP se decide mayormente en la etapa RCPT TO:
- Si el destinatario es local (un dominio que hospedas), Postfix puede aceptarlo desde Internet. Eso es correo entrante normal.
- Si el destinatario no es local, aceptarlo es relay. El relay debe estar restringido a usuarios autenticados o a redes de confianza explícitas.
reject_unauth_destination es el portero
El control anti-relay más importante en Postfix es reject_unauth_destination (o su variante defer). Rechaza intentos de enviar a dominios no locales a menos que el cliente sea de confianza por reglas anteriores.
En Postfix moderno, normalmente lo colocas en smtpd_relay_restrictions. En configuraciones antiguas era común en smtpd_recipient_restrictions. Puedes usar ambos, pero debes entender exactamente qué lista se evalúa para qué. Lo que no debes hacer es eliminarlo porque “rompía el reenvío una vez”. Eso no es arreglar; es quitar los frenos porque el coche chirría.
mynetworks: la manera más fácil de dispararte en el pie
permit_mynetworks es cómodo y peligroso. Dice: “si estás en estos rangos de IP origen, estás confiado para relaying”. Esto está bien en entornos pequeños y controlados. Es arriesgado en redes modernas donde “interno” incluye portátiles, BYOD, nodos Kubernetes e instancias efímeras creadas por CI.
Patrones recomendables:
- Mantén
mynetworkslimitado a loopback y a la subred específica donde viven tus clientes de correo autenticados (si es necesario). - Prefiere submission autenticado (587) para correo de usuarios.
- Si las aplicaciones necesitan relay, autentícalas o restrínjelas por IP con precisión quirúrgica.
mydestination y “dominios locales” definen qué no es relay
Si Postfix piensa que un dominio es local, aceptará correo para él (sujeto a otras restricciones). Si Postfix piensa que un dominio no es local, aceptarlo es relay. Definir mal dominios locales causa dos problemas comunes:
- Rechazar correo entrante legítimo (“user unknown” o “relay access denied” para tus propios dominios).
- Aceptar por accidente correo que nunca debería manejar este servidor (bucles de enrutamiento, tormentas de correo, exposición de cumplimiento).
Submission es donde quieres ser generoso (con autenticación)
El puerto 587 es el lugar para permitir que tus usuarios y aplicaciones envíen correo hacia afuera, con:
- TLS obligatorio
- Autenticación SASL obligatoria
- Restricciones explícitas para evitar convertir submission en una puerta trasera de relay
Ciérralo: patrones seguros para Postfix en producción
Seamos opinativos. Si tu instancia Postfix está expuesta en Internet por el puerto 25, la postura por defecto debería ser: aceptar correo solo para los dominios que hospedas; no relayees para desconocidos; proveer envío saliente mediante submission autenticado.
Patrón A: MX público para correo entrante, sin relay público saliente
Este es el rol MX “clásico”. Aceptas correo entrante para tus dominios. No permites que clientes aleatorios reenvíen hacia afuera.
Configuraciones clave (ilustrativas, no sagradas):
smtpd_relay_restrictions: debe terminar condefer_unauth_destinationoreject_unauth_destinationmynetworks: solo loopback, a menos que tengas un caso controlado de relé internomydestination/dominios virtuales: exactamente tus dominios hospedados
Patrón B: Relay saliente para aplicaciones internas (recomendado: autenticado)
Tus aplicaciones quieren enviar correo. No quieres tomar decisiones de confianza basadas en IPs a través de redes complicadas.
Usa submission con SASL. Si tu aplicación no puede hacer SASL, eso es un problema de producto; trátalo como tal. Si absolutamente debes usar confianza por IP, aíslalo: escucha en una interfaz interna solamente, firewall estricto y CIDRs mínimos.
Patrón C: Smart host / relayhost (evita tránsito accidental)
Algunos hosts Postfix nunca deben hablar directamente con Internet. Deben enviar todo a un relayhost corporativo o a una pasarela de seguridad de correo.
Esto es más seguro para control de egress, pero no lo confundas con prevención de relay abierto. Un sistema puede reenviar todo a un smart host y aun así ser un relay abierto si acepta correo externo no autenticado y lo reenvía.
Dos guardarraíles prácticos que deberías implementar
- Haz que “demostrar que no somos un relay abierto” sea una puerta de despliegue. Una prueba externa simple con swaks en CI/CD o al menos en gestión de cambios.
- Reduce el radio de impacto con controles de red. Security groups/firewalls que restrinjan quién puede alcanzar 587, y en algunos diseños incluso 25 (si no eres MX).
Broma #2: Postfix hará exactamente lo que le dices, por eso a veces se comporta como un becario muy educado pero desastroso.
Tres mini-historias corporativas desde el terreno
Mini-historia 1: El incidente causado por una suposición equivocada
Migraron servicios de correo desde un cluster VM legado a un entorno cloud. El diseño antiguo confiaba en “red interna = confiable”. Funcionó años porque “interno” significaba un puñado de servidores en una VLAN estática. Luego la empresa se modernizó.
En la nueva VPC, “interno” incluía nodos Kubernetes, agentes de build, jump boxes y clientes VPN de contratistas que aterrizaban en el mismo espacio de direcciones amplio. Nadie tenía el mapa completo en la cabeza. La configuración de Postfix hizo lo de siempre: permit_mynetworks para relaying, con mynetworks establecido a un gran rango RFC1918.
La primera señal no fueron las quejas por spam. Fueron alertas de disco. La cola de correo creció lo suficiente como para disparar umbrales del sistema de archivos. El ingeniero on-call vio muchas entregas salientes hacia dominios webmail gratuitos. Al principio asumieron “fuga de credenciales” en el puerto submission.
El giro fue más simple: no había auth involucrado. Un runner de CI comprometido dentro de la VPC se estaba conectando al puerto 25 y haciendo relay a placer porque coincidía con mynetworks. El runner era efímero, así que la IP de origen cambiaba y los intentos de bloqueo parecían juegos de whack-a-mole.
La solución fue aburrida y decisiva: quitar la confianza amplia RFC1918, exigir auth para salida y restringir acceso al puerto 25 solo al gateway entrante. También añadieron una prueba externa swaks como parte de la validación post-cambio. La frase clave del informe del incidente: “tratamos la ubicación de red como identidad.” Esa suposición solía ser común. Hoy es cara.
Mini-historia 2: La optimización que salió mal
Otra empresa operaba Postfix como MX entrante combinado y relay saliente para apps internas. Ajustaban para rendimiento porque campañas de marketing generaban picos enormes salientes. Querían menos “SMTP rejects” en logs porque alguien los interpretó como errores.
Un ingeniero “optimizó” aflojando restricciones y moviendo chequeos más tarde en la conversación SMTP. La idea: aceptar el mensaje rápido, encolarlo y luego decidir qué hacer. También permitieron un CIDR interno más grande en mynetworks para evitar fallos de auth desde subredes raras.
Ese cambio sí redujo los rejects en RCPT. También aumentó el coste de decir no. Cuando empezó el abuso—triggered por un host comprometido en una subred de confianza—Postfix aceptó datos del mensaje y lo encoló antes de que la política posterior rechazara. La CPU subió. Las escrituras a disco subieron. La latencia subió. El MTA se convirtió en un motor de denegación de servicio contra sí mismo.
La entregabilidad sufrió porque el sistema gastaba recursos en manejar basura. El correo legítimo saliente llegó tarde, lo que provocó fallos en flujos de restablecimiento de contraseña. El impacto se pareció a una caída de autenticación, no a un problema de correo, hasta que alguien revisó la profundidad de la cola.
Revirtieron a rechazo temprano en RCPT y apretaron límites de confianza. El rendimiento mejoró porque rechazar temprano es más barato que recibir spam. La lección: “menos ruido en logs” no es una meta de optimización. Es una métrica de vanidad con incidente adjunto.
Mini-historia 3: La práctica aburrida pero correcta que salvó el día
Un equipo de servicios financieros ejecutaba Postfix para sistemas internos y usaba una pasarela externa de seguridad de correo para mail Internet. Su configuración no era ingeniosa; era explícita. El puerto 25 estaba firewall-eado para aceptar conexiones solo desde las IPs del gateway. El puerto 587 requería TLS y SASL, y estaba restringido a rangos de oficina/VPN.
También tenían un runbook pequeño: después de cualquier cambio, ejecutar dos pruebas swaks desde un host probe externo—una a un destinatario local (debe tener éxito), otra a un destinatario externo (debe fallar con relay denied). Las salidas se adjuntaban al ticket de cambio. A los auditores les encantaba, pero más importante aún, a los operadores también: convirtió la política de correo en evidencia.
Un día, un cambio de red expandió accidentalmente el acceso entrante al puerto 25 desde todo Internet. No fue malintencionado; fue una plantilla de security group aplicada mal. El monitoreo captó nuevos patrones de conexión inmediatamente, pero la salvación mayor fue el runbook: el siguiente cambio rutinario incluyó el paso de prueba swaks, que falló en la prueba de “debe rechazar relay” porque otra deriva de configuración había debilitado restricciones.
Lo solucionaron antes de que el abuso escalara. Sin drama de listas negras, sin implosión de cola, sin llamadas indignadas de proveedores. La práctica no era glamorosa. Era una checklist y una prueba. En producción, lo aburrido es una característica.
Errores comunes: síntoma → causa raíz → solución
Esta sección está pensada para acortar tu incidente. Encuentra tu síntoma, deja de adivinar y aplica la solución específica.
1) Síntoma: la prueba externa con swaks relaya correctamente a Gmail/Yahoo
- Causa raíz: Falta o mal posicionamiento de
reject_unauth_destination/defer_unauth_destinationen restricciones de relay/recipient. - Solución: Establece
smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination(o reject). Recarga y vuelve a probar externamente.
2) Síntoma: “Relay access denied” para tus propios dominios
- Causa raíz: Tu dominio no se considera local (mydestination mal, falta configuración de dominios virtuales, transport maps incorrectos).
- Solución: Define correctamente los dominios hospedados (dominios virtuales o mydestination). No “arregles” permitiendo relaying de forma amplia.
3) Síntoma: Funciona internamente, falla para usuarios en movilidad
- Causa raíz: Los usuarios dependen de confianza basada en IP (
mynetworks) en lugar de auth en submission; VPN/IPs fuera de casa no están confiadas. - Solución: Configura submission (587) con TLS + SASL; indica a los clientes que lo usen. Deja de ampliar
mynetworksbuscando cubrir IPs itinerantes.
4) Síntoma: La cola crece, disco se llena, logs muestran muchas entregas salientes
- Causa raíz: Relay abierto o remitente autenticado comprometido; rechazo demasiado tardío; sin rate limiting.
- Solución: Demuestra comportamiento de relay desde fuera, aprieta restricciones de relay, bloquea fuentes abusivas y considera policyd/límites de tasa. Purga spam tras acotar el alcance.
5) Síntoma: Cada cliente aparece como la misma IP en los logs
- Causa raíz: SMTP detrás de proxy/load balancer sin preservar IP de cliente; Postfix confía en la IP del proxy.
- Solución: Usa un diseño que preserve la IP cliente (proxy protocol si es compatible) o no confíes en
mynetworks. Restringe en el borde de la red.
6) Síntoma: El puerto submission permite enviar sin auth
- Causa raíz:
master.cfmal configurado para submission; faltasmtpd_sasl_auth_enable=yeso restricciones de recipient demasiado permisivas. - Solución: Exige auth y rechaza en caso contrario en submission. Vuelve a probar con swaks usando contraseña incorrecta y sin auth.
7) Síntoma: Algunos hosts internos pueden relayar, otros no, y nadie sabe por qué
- Causa raíz: Enrutamiento/NAT inconsistente o CIDRs superpuestos; mismatch en
mynetworks; múltiples instancias de Postfix con configuraciones distintas. - Solución: Identifica IPs reales de origen, aprieta listas de confianza, estandariza config con gestión de configuración y añade pruebas externas de comprobación.
Checklists / plan paso a paso
Checklist A: “¿Somos un relay abierto?” (15 minutos, basado en evidencia)
- Desde un host externo, ejecuta swaks a un destinatario tercero. Espera
Relay access denied. - Desde el mismo host externo, ejecuta swaks a un destinatario de dominio local. Espera
250 Oky aceptación de DATA. - En el host Postfix, captura
postconf -ny confirma quesmtpd_relay_restrictionsincluye el rechazo de destinos no autorizados. - Revisa los logs de correo en busca de rechazos de relay recientes y de relays exitosos sospechosos.
- Adjunta la salida de swaks + las líneas de log relevantes a tu ticket/registro de cambio.
Checklist B: Cerrar un relay abierto de forma segura (modo incidente)
- Contener: Corrige inmediatamente las restricciones de relay; si el tráfico es abrumador, bloquea fuentes abusivas en el firewall.
- Preservar evidencia: Guarda extractos de logs y algunas cabeceras de mensajes (
postcat -q) para confirmar origen. - Validar externamente: Repite la prueba externa swaks hasta que falle con relay denied.
- Triage de cola: Inspecciona la cola; identifica si el correo en cola es legítimo o spam.
- Limpieza: Elimina entradas de spam en la cola después de confirmar el alcance; evita borrar correo legítimo.
- Recuperar entregabilidad: Si fuiste listado, coordina la eliminación de la lista y comunica a las partes interesadas.
- Prevenir recurrencia: Reduce
mynetworks, exige auth en submission y añade una prueba periódica de comprobación.
Checklist C: Endurecimientos que puedes estandarizar
- Restringe la exposición del puerto 25 a lo estrictamente necesario (tráfico MX o IPs de gateway).
- Requiere TLS + SASL en puerto 587. No conviertas 587 en un relay por conveniencia.
- Mantén
mynetworkspequeño y revísalo como reglas de firewall. - Rechaza temprano en la etapa RCPT. No aceptes DATA a menos que lo quieras aceptar.
- Añade monitorización para profundidad de cola, mensajes diferidos y volumen saliente inusual.
Preguntas frecuentes
1) ¿Cómo pruebo definitivamente que Postfix no es un relay abierto?
Ejecuta una transacción SMTP desde un host externo y no confiable hacia un dominio tercero. Si RCPT es rechazado con “Relay access denied”, tienes la prueba. Guarda la salida.
2) ¿Por qué no basta probar desde localhost?
Porque localhost suele estar confiado vía mynetworks. Un relay abierto a Internet puede seguir pareciendo “seguro” cuando se prueba desde 127.0.0.1.
3) ¿Cuál es la diferencia entre smtpd_recipient_restrictions y smtpd_relay_restrictions?
smtpd_relay_restrictions es el lugar moderno para decisiones de política de relay. smtpd_recipient_restrictions controla la aceptación de destinatarios de forma más general. Colocar reglas en el sitio equivocado puede debilitar tus controles de relay.
4) ¿Debería usar reject_unauth_destination o defer_unauth_destination?
Cualquiera prevenirá relay abierto. reject es inmediato y claro. defer puede usarse en algunos flujos de política, pero es más fácil razonar con reject al endurecer.
5) ¿Puedo confiar solo en mynetworks para apps internas?
Puedes, pero probablemente no deberías. Las redes “internas” suelen ser extensas y porosas. Prefiere submission autenticado para apps; si debes usar confianza por IP, aíslala estrictamente.
6) Si el puerto 25 está firewall-eado al mundo, ¿puedo ignorar el riesgo de relay abierto?
No. Si cualquier red no confiable puede alcanzar el puerto 25 (incluidas VPNs, VPCs emparejadas o security groups mal configurados), aún puedes ser abusado. Además, la deriva de configuración ocurre; las pruebas de comprobación la detectan.
7) ¿Por qué nos listaron si arreglamos el relay rápido?
Las listas negras reaccionan al volumen de spam observado y al comportamiento; la reputación queda rezagada respecto a la realidad. Arreglar el relay detiene la hemorragia; la eliminación de listas y la recuperación de reputación pueden tardar más.
8) ¿Cómo distingo “relay abierto” de “buzón comprometido que envía spam”?
El spam por relay abierto proviene de conexiones no autenticadas (a menudo en puerto 25) y de muchas IPs de origen. Las cuentas comprometidas suelen mostrar envíos SASL autenticados en 587 desde identidades de usuario específicas y menos IPs de origen.
9) ¿Habilitar TLS previene el relay abierto?
No. TLS cifra la conexión; no define quién tiene permiso para relayar. Aún necesitas restricciones de relay y/o autenticación.
10) ¿Cuál es la configuración mínima más segura?
En puerto 25: acepta correo solo para dominios que hospedas; rechaza relaying no autorizado. En puerto 587: exige TLS y SASL; permite salida autenticada.
Próximos pasos que deberías hacer
No esperes a un correo de lista negra para saber si eres un relay abierto. Hazlo una prueba rutinaria.
- Ejecuta hoy la prueba externa swaks (Task 6). Guarda la salida en un lugar donde auditores y tu yo futuro puedan encontrarla.
- Revisa
postconf -ny confirma quesmtpd_relay_restrictionstermine en rechazo de destinos no autorizados. - Reduce
mynetworksa lo que puedas defender en una reunión. Loopback es un buen punto de partida. - Haz de submission (587) la vía oficial de salida con TLS + SASL, y deja de arreglar problemas de auth con CIDRs.
- Añade un panel de monitoreo: tamaño de cola, conteo de diferidos y volumen saliente. Sorprende lo a menudo que esto detecta “correo raro” antes que los usuarios.
- Convierte la prueba en proceso: cada cambio relacionado con correo incluye las dos pruebas swaks (aceptación local, rechazo externo). Adjunta la evidencia. Repite siempre.