Tunnel SSH à la demande grace à Launchd

Mac OS X 10.4 a introduit Launchd, une technologie plutôt intéressante et à fort potentiel.
Le démon launchd(8) remplace init(8), il émule inetd, crontab, et ajoute une panoplie de fonctions.

Pour passer outre certains pare-feu, il faut parfois recourir à des tunnels ssh. On peut aussi utiliser un tunnel ssh pour sécuriser une connexion entre deux machines. Quoi qu'il en soit, il est rapidement assez pénible d'avoir à ouvrir manuellement son ou ses tunnels à chaque fois qu'on en a besoin. C'est là qu'intervient launchd.

Malheureusement, ce dernier ne nous permet pas de créer un tunnel qui soit exploitable immédiatement par l'application qui a fait la demande. Dans le cas d'un agent launchd qui lancerait la commande complète de tunnel `ssh -N -L 1190:fournisseur.tld:119 login@passerelle-ssh.tld` par exemple, le client usenet doit être configuré pour lire les news sur localhost:1190. Le lancement du client usenet fait donc sa requête sur localhost. launchd détecte la tentative de connexion et lance launchproxy, qui ouvre alors le tunnel. Ce mode de fonctionnement ne permet à pas de "brancher" le client usenet sur le tunnel créé. Si par contre on relance le client, ou si on lui fait refaire une tentative de connexion, il trouve le tunnel existant et tout fonctionne.

Pour contourner ce problème, certains utilisent une clé ssh établissant une simple connexion avec lancement d'application sur la passerelle ssh. Cette méthode a l'inconvénient d'utiliser une clé ssh dédiée pour chaque connexion. Le fait que toute la commande de connexion distante soit intégrée à la clé peut aussi rendre les tests fastidieux.
L'approche choisie ici est donc d'utiliser une clé ssh générique, et de s'en servir pour lancer sur la passerelle distante une commande de connexion.

Je passe la phase de création et de l'installation de la clé ssh, seule contrainte : elle doit être sans mot de passe (je n'ai pas testé de combinaison avec ssh-agent). Le système launchd fonctionne à base de fichiers de configuration, et le démon s'attend à trouver ces fichiers à des endroits précis. Pour un agent à l'usage d'un seul utilisateur, on utilise le dossier ~/Library/LaunchAgents/ (qu'il faut créer).
Avec l'éditeur de son choix, on crée l'agent launchd :

vi ~/Library/LaunchAgents/tld.passerelle-ssh.news
# on colle :
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" 
 "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>Debug</key>
	<false/>
	<key>Label</key>
	<string>tld.passerelle-ssh.news</string>
	<key>OnDemand</key>
	<true/>
	<key>ProgramArguments</key>
	<array>
		<string>/usr/bin/ssh</string>
		<string>login@passerelle-ssh.tld</string>
		<string>nc</string>
		<string>fournisseur.tld</string>
		<string>119</string>
	</array>
	<key>Sockets</key>
	<dict>
		<key>Listeners</key>
		<dict>
			<key>SockServiceName</key>
			<string>1190</string>
			<key>SockType</key>
			<string>stream</string>
		</dict>
	</dict>
	<key>StandardErrorPath</key>
	<string>/tmp/news.err</string>
	<key>inetdCompatibility</key>
	<dict>
		<key>Wait</key>
		<false/>
	</dict>
</dict>
</plist>

On remplace bien évidemment passerelle-ssh.tld par le nom de domaine de la passerelle ssh, tld.passerelle-ssh.news par le nom de fichier choisi, fournisseur.tld par l'adresse du serveur distant, et 119 par le port du serveur distant qu'on veut contacter. On peut aussi remplacer 1190 par le port local sur le quel on souhaite faire la connexion.

Une fois le fichier sauvegardé, il faut le charger dans launchd :

launchctl load ~/Library/LaunchAgents/tld.passerelle-ssh.news

On peut vérifier le chargement par la commande `launchctl list`. Ensuite on procède au premier lancement de l'application qui va utiliser le tunnel. Néanmoins, si on souhaite tester le tunnel manuellement, on peut utiliser telnet. Le serveur fournisseur.tld:119 doit alors répondre quelque chose comme ceci :

telnet localhost 1190
Trying ::1...
Connected to localhost.
Escape character is '^]'.
200 fournisseur.tld NNRP Service Ready - news@fournisseur.tld (posting ok).

Si tout ne se passe pas comme prévu, vous pourrez peut être trouver quelques informations dans le fichier /tmp/news.err défini comme valeur pour StandardErrorPath. On peut aussi passer Debug à "true" au début du fichier. Chaque modification du fichier oblige à recharger l'agent via `launchctl load...`.

Attention : la configuration proposée n'est pas la plus sûre. La clé ssh générique sans mot de passe n'est pas forcément envisageable dans tous les contextes. C'est néanmoins une configuration simple très souple, c'est ce que j'ai choisi de privilégier.

Attention - BIS : pour éviter que n'importe qui profite de votre tunnel, il est impératif d'ajouter ces lignes au dessus de la ligne du SockServiceName :

                        <key>SockNodeName</key>
                        <string>127.0.0.1</string>

Ainsi votre tunnel sera lié uniquement à localhost, et non plus à toutes vos interfaces réseau.

Related posts

Manipulations sur les variables dans Bash

Voilà la suite de ma petite introduction aux variables dans bash. Je vais traiter ici des manipulations qu'on peut faire subir aux variables avec les outils natifs de bash.

Continue reading

Related posts

Les variables dans Bash

Avec un gros retard sur mes prévisions, voilà une introduction à la gestion des variables dans Bash.

Continue reading

Related posts

Quelques notions sur les boucles dans bash

Aujourd'hui je reviens avec un petit baratin sur les boucles dans les scripts bash. C'est très superficiel, mais ça peut servir de point de départ aux débutants qui nous lisent.

Continue reading

Related posts

"builtin" : quelques subtilités

Quand j'ai créé la liste AppleScript francophone, j'ai dispensé aux nouveaux venus des petits cours sans prétention pour leur mettre le pied à l'étrier.
Je récidive ici, et en toute humilité, avec un exemple complexe disséqué je l'espère avec clarté.

Un shell est un environnement de travail, en tant que tel, il doit mettre à disposition de l'utilisateur des outils pour lui faciliter la tâche. Pour ce faire, les shells proposent un certain nombre de commandes intégrées appelées "builtin" (man builtin). On trouve parmi celles-ci : cd, alias, login, bg, echo, ...

Continue reading

Related posts

Liste francophone des scripts shell

Depuis aujourd'hui la liste francophone des scripts shell est officiellement ouverte au public. En voici une présentation sommaire :

La liste francophone des scripts shell est dédiée à tous les utilisateurs de scripts shell au sens large (sh, bash, zsh,..., sed/awk/grep/...). On y aborde le développement de scripts, la configuration des environnements shell (.bashrc, ...) ainsi que les outils connexes comme les émulateurs de terminal et leur manipulation ou configuration. Les langages interprétés comme Python, Perl, Ruby, peuvent aussi être abordés mais ne sont pas le sujet principal de la liste. Les langages compilés comme le C/C++ sont hors sujet. L'accent est mis par défaut sur les environnements Unix et Linux, avec une pensée particulière pour les utilisateurs de Mac OS X et FreeBSD. Néanmoins, tous les utilisateurs de shell plus ou moins POSIX sont les bienvenus.

Pour s'inscrire c'est par là : http://listes.patpro.net/mailman/listinfo/script_shell_fr. Quant aux archives publiques, elles se trouvent ici

Related posts