Mettre en place un environnement sftp chrooté

Note : Je propose une autre approche pour mettre en place cette solution: mettre-en-place-un-environnement-sftp-chroote-2/

La demande

Ma copine m’a demandé de trouver une solution simple pour échanger des fichiers avec sa sœur, msn posant des problèmes… J’ai pensé à mon serveur ssh et mettre en place une connexion sftp pour ça. Sur le principe cela a été adopté avec une petite présentation de filezilla (je ne sais pas s’il existe des clients sftp intégrés sous windows?), j’ai donc commencé à mettre en place le système. De mon côté, la condition principale est de n’autoriser les connexions que par clef publique (pas de mot de passe), ma copine a tenu à ce que sa sœur ne puisse pas accéder aux documents présents dans son home, et du mien à ce que l’on ne puisse pas pour autant se promener dans l’arborescence du serveur: il va donc falloir chrooter l’environnement. Il existe pas mal de documentation la dessus sur internet, mais je me suis souvent retrouvé face à des exemples incorrects ou incompatible avec le fait de passer par une clef publique, je vais donc détailler les problèmes rencontrés.

Le compte + clef publique

La première étape est de créer le compte, cela se fait assez simplement :

# adduser ${user}

Création de la clef ssh avec puttygen et en répondant aux questions par défaut… Vient ensuite la clef publique: filezilla gère les clefs privés au format ppk (putty) et je n’ai pas trouvé d’outil pour les générer sous windows. Je suis donc passé par wine + puttygen pour créer la clef. Une fois celle-ci crée, on enregistre la partie publique et la partie privée de la clef. La clef publique va être enregistrée dans le fichier ${user}/.ssh/know_host sur le serveur pour autoriser le client à s’y connecter. La clef privée sera enregistrée de son côté au format ppk pour être utilisée par filezilla (il est possible à partir de ce fichier de générer une clef privée de type openssh).

image1

Il faut ensuite intégrer la clef privée dans filezilla en passant par les paramètres: elle sera automatiquement lue à la connexion (il faut choisir «interactive» dans le type d’authentification). (Attention: sous windows j’ai rencontré des problèmes avec un répertoire contenant des accents, la clef semblait être lue, mais la connexion ne se faisait pas pour autant.)

Chrooter l’environnement

Aujourd’hui il est possible de chrooter nativement un environnement sftp avec openssh. Il faut pour cela mettre en place une condition sur l’utilisateur (ou le groupe) pour faire le chroot:

Match user ${user}
   ChrootDirectory /var/chroot/
   X11Forwarding no
   AllowTcpForwarding no
   ForceCommand internal-sftp

Dans cet exemple le chemin /var/chroot sera utilisé comme racine lors des connexions sftp. Ce répertoire doit être détenu par root:root et avoir les droits 755. Cela veut dire que si notre utilisateur à pour répertoire home /home/${user}, il se retrouvera dans /var/chroot/home/${user} lors des connexions sftp. Il est nécessaire de conserver le répertoire home de l’utilisateur pour que ssh accepte une connexion par clef. En effet, lorsque l’utilisateur va se connecter, ssh va lire dans son répertoire personnel pour lire le fichier .ssh/know_host et autoriser ou non la clef qui se présente. Ce qui signifie que si l’on modifie le répertoire personnel, il faut aussi déplacer cette arborescence (hors de question dans ce cas de mettre / comme racine de l’utilisateur). À noter: j’ai préféré faire le match sur le nom de l’utilisateur plutôt que sur son groupe (le groupe sera utilisé par ailleurs). Dans le cas où nous avons plusieurs utilisateurs, il est possible de les mettre à la suite (séparés par des virgules). J’ai vu de nombreux tutoriaux qui indiquent comme répertoire de chroot « /home/%u» (le répertoire de l’utilisateur standard), et qui demandent de changer le répertoire de login de l’utilisateur par « / ». Je pense que c’est une très mauvaise idée: d’une part parce que cela oblige à déposer les clefs à la racine du serveur, mais aussi à cause de la contrainte d’openssh demandant à ce que le répertoire root soit détenu par root: cela veut dire que l’utilisateur n’a pas le droit de déposer de fichiers ou de créer de répertoires dans son propre home! Le plus simple est donc de prendre un autre répertoire pour l’échange, et laisser le home de l’utilisateur pour la configuration. (Cela permet aussi d’être sûr que le répertoire .ssh ne sera pas effacé par erreur par l’utilisateur…) J’ai donc mis un lien symbolique pour lier le /home de l’utilisateur avec son répertoire d’échange:

# mkdir /home/${user}/echanges
# ln -s /var/chroot/home/${user} /home/${user}/echanges

On retrouvera ainsi la possibilité de voir les fichiers déposés en passant par le /home de l’utilisateur (même si ce dernier ne pourra pas y aller…)

Isoler l’environnement

Maintenant que nous avons empêché l’utilisateur de se balader sur l’ordinateur, nous allons l’empêcher de se balader dans les autres répertoires des utilisateurs: cela se fait en une ligne de commande (pour chacun des répertoires que nous allons ouvrir en sftp:)

# for fichier in /var/chroot/home/* ; do chmod o-r ${fichier}; done

Et voilà! Les utilisateurs peuvent voir qu’il existe d’autres comptes que le leur, mais ne peuvent pas y accéder.

Autoriser le partage

Maintenant que nous avons fermé les droits de manière générale il nous reste à autoriser le partage des fichiers (après tout c’était le but de la demande!) de manière plus fine. Cela implique pour moi deux choses:

  1. permettre à un autre utilisateur d’accéder aux données présentes
  2. permettre à un autre utilisateur de déposer (ou de supprimer des données)

Pour le premier point, c’est facile il suffit d’ajouter l’utilisateur A au groupe de l’utilisateur B:

# usermod -a -G ${user} ${un_autre_utilisateur}

Et l’utilsateur un_autre_utilisateur pourra donc accéder à l’ensemble des fichiers pour les lire (et éventuellement les rapatrier chez lui). Pour le second point (possibilité d’écrire et modifier) c’est un peu plus compliqué; en gros nous voulons que les fichiers déposés par sftp dans le répertoire de l’utilisateur ait comme groupe d’appartenance celui du propriétaire du répertoire (quel que soit l’utilisateur qui dépose) et qu’ils soient modifiable par le groupe (g+w) du propriétaire. Par exemple: l’utilisateur A dépose un fichier dans le répertoire d’échange de l’utilisateur B. Il faut que les droits de ce fichier se présentent ainsi une fois le transfert terminé:

$ ls -l fichier
-rw-rw----  1 utilisateurA utilisateurB

(ainsi l’un et l’autre pourront supprimer le fichier). Pour cela nous allons utiliser une «bidouille» de l’os: le sgid bit. Derrière ce nom barbare se trouve un marqueur qui permet de fixer le droit de tous les fichiers qui seront créés dans le répertoire (plus d’info ici). Pour le déterminer on passe par chmod:

# chmod g+s /var/chroot/${user}

image2

Cela détermine bien quel est le groupe qui sera propriétaire du fichier, mais cela ne donne pas à ce groupe le droit de le modifier pour autant! Sous linux, c’est la commande umask qui permet de déterminer les droits des fichiers. Le problème est qu’il s’agit d’une commande liés à l’environnement de l’utilisateur, et non pas aux répertoires sur lesquels nous travaillons (à moins de passer par les ACLs mais cela est déjà assez compliqué comme ça…). Ici, nous sommes dans un environnement sftp, sans shell de login, donc sans possibilité d’exécuter la commande directement, il faut que ce soit le serveur sftp qui le configure. J’ai trouvé énormément de documentations (la plupart des bidouillages) pour contourner le problème, mais la solution la plus simple vient de la dernière version d’OpenSSH (5.4) sortie le 8 mars dernier.

Une nouvelle option sur le serveur sftp permet d’indiquer quel est l’umask qui sera appliqué (dans notre cas 002) : dans le fichier/etc/ssh/sshd_config nous allons configurer les paramètres par défaut du serveur sftp: Remplacer:

Subsystem sftp /usr/lib/openssh/sftp-server.sh

par:

Subsystem sftp /usr/lib/openssh/sftp-server -u 002

Pour définir les droits umask qui seront appliqués par défaut pour toutes les connexions sftp par défaut. Ce paramétrage est à redéfinir pour les paramétrages personnalisés (bloc Match) :

ForceCommand internal-sftp -u 002

Conclusion

Nous avons un environnement bien hermétique, pouvant gérer l’augmentation du nombre de compte (il suffit de refaire les chmod dans notre environnement chrooté à la création du compte), et hermétique. Le paramétrage côté serveur est effectivement assez lourd au début, mais je pense que la mise à jour ne demande pas trop de travail, et on gère les droits de manière assez fine (en passant par les groupes ce qui me semble être dans la mentalité unix). Pour le client, il n’y a pas grand chose à paramétrer (récupérer la clef et l’intégrer), et il n’y a aucun risque que celui-ci vienne casser son paramétrage. On peut même sauvegarder sa clef privée dans son home (le vrai), au cas où il perdrait le fichier.