Artisan Numérique

/système/réseau/ssh/mutt/sendmail/ Envoyer des mails via ssh/sendmail

Un problème classique d'unixien itinérant qui possède un serveur de mail type postfix : comment envoyer d'un client tel mutt (ou tout autre client sérieux) du courriel d'où que l'on soit, de manière sécurisée et sans trop se prendre la tête. La solution est encore et toujours notre meilleur ami, SSH.

Problématique

L'approche classique pour résoudre ce problème consiste à mettre en place un protocole de reconnaissance entre le client courriel et le serveur. Ce protocole peut aller de l'échange de mot de passes, à celui de certificat, ou plus généralement par l'autorisation de certaines IP. Dans le cadre itinérant, la solution par mot de passes semble la plus logique. Mais lorsque l'on a déjà un tunnel SSH proprement configuré entre la machine itinérante et le serveur, on se demande s'il n'y a pas un moyen de réutiliser cette mécanique et ainsi éviter de fastidieuses configurations. En d'autre terme, comment faire tout cela sans toucher à la configuration du serveur :-)

Mais étrangement, dés que j'ai cherché sur la voie "SMTP over SSH", je suis tombé sur des solutions finalement aussi casse-bonbons que de mettre en place l'authentification que je cherchais à éviter. J'ai donc essayer de reprendre le problème à la base.

Faux sendmail over SSH

Traditionnellement sur un système UNIX, l'envoi de courrier se fait par la commande sendmail. Cette commande prend un certains nombre de paramètres dont l'adresse courriel du destinataire principale et reçoit, via pipe, le corps brut (en-têtes compris) du message. Cette commande est disponible dés lors qu'un MTA (Mail Transport Agent) comme Postfix, Exim ou autre est présent. C'est donc aussi le cas sur notre serveur.

Sachant cela, il nous vient alors logiquement l'idée suivante : "pourquoi ne pas accéder au sendmail distant via SSH". En effet, SSH peut lancer n'importe quelle commande distante et la nourrir avec des données. Le principe développé est donc de faire sur la machine itinérante une fausse commande sendmail qui récupère les paramètres et le flux en entrée pour le rediriger vers le vrai sendmail distant. Un script qui semble somme toute simple à réaliser :

#! /bin/bash

/usr/bin/ssh mon.serveur.de.mail "/usr/sbin/sendmail $*"
exit $?

Rien de bien sorcier dans ce script (et un merci à Sputnik pour m'éviter le passage par des fichiers intermédiaires). Le message injecté via StdIn est routé dans le tunnel ssh et récupéré directement par la commande sendmail nourrie des paramètres qui ont été donnés au faux sendmail. On termine par un echo $? qui va retransmettre à l'appelant une éventuelle erreur.

Sur le principe, le faux sendmail fonctionne à merveille pour peux que vous ayez configuré votre tunnel SSH sans mot de passe (via un jeu de clefs publique/privée).

Pour tester, par exemple avec mutt, il suffit de spécifier le chemin vers le faux sendmail par une commande set sendmail=/chemin/vers/faux/sendmail. Une autre option encore plus simple consiste à mettre ce script en lieu et place d'un vrai sendmail, soit en /sbin/sendmail.

Conclusion

Cette solution très simple à mettre en œuvre m'a ainsi permis d'envoyer mes courriels de manière totalement sécurisée, rapide, et avec 0 configuration du serveur car pour lui, tout part en local, ce qui est toujours autorisé.

Maintenant cette solution n'est pas spécialement conventionnelle même si elle a le mérite de faire le job sans broncher. Une approche plus robuste serait sûrement de passer par UUCP comme l'indique Julm dans ses commentaires.

Mise à jour : création d'un tunnel synchronisé avec mutt

En quinze jours de baroude à travers le vietnam, j'ai eu le temps de tester le concept. Et finalement j'ai abouti sur une version plus bête encore que celle donnée plus haut, tout simplement en ne lançant pas mutt directement, mais en encapsulant ce lancement dans un script qui ouvre un tunnel (smtp et imap), attends que le tunnel soit opérationnel, lance mutt, et ferme le tunnel à la mort de mutt.

#! /bin/bash

# paramètres du tunnel
IMAP_LOCAL=10143
SMTP_LOCAL=10025
REMOTE_HOST=mon_serveur_distant

# Lancement du tunnel
ssh -nNT -L $IMAP_LOCAL:localhost:143 -L $SMTP_LOCAL:localhost:25 $REMOTE_HOST &
PID=$!

# On attends que le tunnel soit actif
until nc -zw30 localhost $IMAP_LOCAL;  do
  sleep 1
done
echo "Tunnel actif, lancement de mutt..."

mutt

# Nettoyage
kill $PID

Comme vous le voyez, c'est simple, efficace et relativement tout terrains (merci à Spoutnik pour ses corrections/simplifications !)