Trafic SMTP(S)/IMAP via tunnel OpenVPN

Introduction

Cette article fait suite à mon précédent article décrivant la mise en place d'un monitoring avec Munin pour mon nouveau VPS chez OVH.

Pour rappel, la mise en place de ce serveur VPS chez OVH fait suite à un changement de fournisseur d'accès internet, et la perte prochaine de mon adresse IPv4 fixe que celui-ci m'offrait gracieusement depuis quasiment 10 ans.

Sachant que mon serveur mail est auto-hébergé à mon domicile, la perte de l'adresse IPv4 fixe, ainsi que la possibilité de configurer le reverse DNS pour celle-ci est très problématique. Une IPv4 fixe est obligatoire pour mettre en place l'enregistrement MX dans le DNS pour que les emails arrivent sur le serveur.

Ajouté au blocage du trafic SMTP sortant imposé par mon futur opérateur, deux solutions s'offraient à moi:

  • Déplacer le serveur mail dans son intégralité sur mon VPS.
  • Garder le serveur mail à la maison, mais faire passer tout le trafic mail par le VPS.

Sachant que le VPS ne support pas le RAID et qu'il possède qu'une quantité très limité pour le stockage, j'ai décidé d'utiliser la solution du tunnel.

Mise en place du tunnel OpenVPN

Afin de simplifier la mise en place du VPN, celui-ci est dédié à la communication entre le VPS et le serveur chez moi que j'appellerais dorénavant Maison.

Il n'utilisera donc pas de certificats RSA, pas de KPI locale à gérer, pas de certificats à révoquer. Uniquement une clef statique partagée entre les 2 protagonistes.

L'installation dans ces conditions sur Debian stretch est très simple. Sur le VPS:

vps:~# apt install openvpn
...
vps:~# cd /etc/openvpn/serveur
vps:/etc/openvpn/serveur# openvpn --genkey --secret static.key
vps:/etc/openvpn/serveur# cat >tun0.conf <<EOF
dev tun0
ifconfig 172.16.123.1 172.16.123.2
secret static.key
cipher AES-256-CBC
;script-security 2
;route-up ./tun0.up
compress lz4
keepalive 15 60
persist-tun
persist-key
verb 3
EOF
vps:/etc/openvpn/serveur# systemctl enable openvpn-server@tun0.service

Si un firewall est actif sur le VPS, ce qui est extrêmement important, il faut autoriser le trafic OpenVPN. Ici, j'utilise UFW:

vps:~# cat >/etc/ufw/applications.d/openvpn-server <<EOF
[OpenVPN]
title=OpenVPN server
description=OpenVPN is a free secure VPN client/server implementation.
ports=1194/udp
EOF
vps:~# ufw allow OpenVPN
...

Sur Maison:

maison:~# apt install openvpn
...
maison:~# cd /etc/openvpn/client
maison:/etc/openvpn/client# cat >tun0.conf <<EOF
remote vps.example.com
dev tun0
ifconfig 172.16.123.2 172.16.123.1
secret static.key
cipher AES-256-CBC
;script-security 2
;route-up ./tun0.up
compress lz4
verb 3
EOF
maison:/etc/openvpn/client# systemctl enable openvpn-client@tun0.service

Puis copier le fichier static.key depuis le VPS vers Maison et mettez le dans /etc/openvpn/client. Veillez aux droits d'accès à ce fichier sur les 2 machines.

Vous pouvez dès maintenant lancer le tunnel en démarrant le service sur les 2 machines en même temps (ils s'attendent mutuellement).

vps:~# systemctl start openvpn-serveur@tun0.service
maison:~# systemctl start openvpn-client@tun0.service

Normalement, là, si tout se passe bien, un tunnel est actif et les 2 machines peuvent se pinguer via les IPs configurées (172.16.123.1 & 172.16.123.2).

vps:~# ifconfig tun0
tun0: flags=4305<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST>  mtu 1500
        inet 172.16.123.1  netmask 255.255.255.255  destination 172.16.123.2
        inet6 fe80::ae7e:a7b8:b8dc:8e94  prefixlen 64  scopeid 0x20<link>
        unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  txqueuelen 100  (UNSPEC)
        RX packets 30082  bytes 8228000 (7.8 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 18936  bytes 4815846 (4.5 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

Il reste maintenant à faire transiter le traffic mail entrant et sortant de Maison par ce tunnel.

Routage du trafic email via le tunnel

C'est la partie la plus compliquée. 2 configurations distinctes doivent être en place. La première, sur VPS, doit forwarder le trafic venant du tunnel vers internet, en changeant l'IP source (SNAT) et doit forwarder le trafic entrant sur le VPS vers le tunnel si et seulement si, c'est du trafic email.

Par commodité, les règles iptables pour le NAT sont mise en place automatiquement par OpenVPN après l'établissement des routes.

vps:~# cat >/etc/openvpn/server/tun0.up <<EOF
#!/bin/bash
# Forwarding is already configured by UFW at boot time.
echo "Set SMTP routing to/from tunnel peer"
# Incomming SMTP(S)/IMAPS connections are DNATed.
iptables -t nat -F PREROUTING
iptables -t nat -A PREROUTING -i ens3 -d 145.239.85.142/32 -p tcp --dport 25 -j DNAT --to-destination 172.16.123.2
iptables -t nat -A PREROUTING -i ens3 -d 145.239.85.142/32 -p tcp --dport 465 -j DNAT --to-destination 172.16.123.2
iptables -t nat -A PREROUTING -i ens3 -d 145.239.85.142/32 -p tcp --dport 993 -j DNAT --to-destination 172.16.123.2
# Outgoing SMTP connections are SNATed.
iptables -t nat -F POSTROUTING
iptables -t nat -A POSTROUTING -o ens3 -s 172.16.123.2/32 -p tcp --dport 25 -j SNAT --to-source 145.239.85.142
EOF

Comme vous pouvez le voir, il n'y a qu'un seul type de connexion sortante. Celles sur le port de destination 25 utilisé par le serveur pour envoyer les email aux serveurs des destinataires.

Le firewall doit aussi autoriser ce trafic:

vps:~# ufw route allow in on ens3 out on tun0 proto tcp to 172.16.123.2 port 25
vps:~# ufw route allow in on ens3 out on tun0 proto tcp to 172.16.123.2 port 465
vps:~# ufw route allow in on ens3 out on tun0 proto tcp to 172.16.123.2 port 993
vps:~# ufw route allow out on ens3 in on tun0 proto tcp to any port 25 from 172.16.123.2

Voilà, le VPS est prêt pour recevoir tout le trafic SMTP(S)/IMAPS. N'oubliez pas de supprimer les ; dans le fichier tun0.conf créé au précédent chapitre pour que OpenVPN puisse lancer le script qui contient les nouvelles règles iptables.

Vous pouvez relancer le service openvpn maintenant.

Le champ MX de la zone DNS pourrait déjà être mise à jour, mais on va attendre un petit peu car en l'état, impossible de recevoir un email. Si vous tester avec telnet, vous verrez qu'il est impossible de se connecter à VPS sur le port 25.

La demande de connexion (TCP SYN) est bien forwarder vers Maison via le tunnel, mais la réponse n'arrive jamais sur l'interface tun0 (tcpdump -i tun0 -n -v 0 tcp port 25 ne voit passer que les SYN).

Ceci est du aux règles de routage qui doivent être adapté. Plus précisément, il faut faire du routage en fonction de la source pour le trafic email.

Cela nécessite de créer une nouvelle table de routage en éditant la configuration iproute2. Ajouter la ligne suivant dans /etc/iproute2/rt_tables:

maison:~# echo "100 vpn" >>/etc/iproute2_rt_tables

Puis créer le script de configuration tun0.up:

maison:/etc/openvpn/client# cat >tun0.up <<EOF
#!/bin/bash
echo "Set SMTP routing to tunnel peer"
iptables -t mangle -F OUTPUT
iptables -t nat -F POSTROUTING
iptables -t nat -F PREROUTING
# add a default route throw tunnel for marked traffic
ip route del default table vpn
ip route add default via 172.16.123.1 dev tun0 table vpn
ip rule del fwmark 0x1 table vpn
ip rule add fwmark 0x1 table vpn
# mark all smtp output traffic so that iproute can route it through tun0
iptables -t mangle -A OUTPUT -o eth0 -p tcp --dport 25 -j MARK --set-mark 0x1
# mark all output from tun0 addr to route back through tun0
iptables -t mangle -A OUTPUT -o eth0 -s 172.16.123.2/32 -j MARK --set-mark 0x1
# and rewrite the src-addr of outgoing SMTP connection
iptables -t nat -A POSTROUTING -o tun0 -p tcp --dport 25 -j SNAT --to-source 172.16.123.2
EOF

C'est un peu plus compliqué. On commence par (re-)créer une nouvelle route par défaut dans la table de routage spécialement pour le tunnel qui s'appelle vpn.

Ensuite, on ajoute une rule pour activer l'usage de cette table de routage pour tous les paquets qui sont marqués avec la valeur 0x1.

Ensuite avec la table mangle de iptables, on marque tout le trafic vers les serveurs SMTP et le trafic associé à l'IP local du tunnel.

Enfin, on s'assure que les connexions sortantes vers les serveurs SMTP ont toutes pour origine l'IP locale du tunnel.

Tout est enfin prêt. Maintenant, redémarrage du tunnel en relançant le service openvpn sur les 2 machines, modification et vérification des champs MX et SPF dans la zone DNS.

Et voilà! Tout le trafic email passe par le VPN.

Commentaires

links

social