Isolation d'environnements (chroot)

Magazine
Marque
Linux Pratique
Numéro
87
Mois de parution
janvier 2015
Domaines


Résumé
Cet article propose deux techniques de base permettant de cloisonner une machine Ubuntu/Debian (transposables sur d'autres distributions). À titre d'exemple, nous utiliserons ces techniques pour créer un hébergement cloisonné de sites web. Ceux-ci pourront être mis à jour par des utilisateurs distants en accès console (SSH). D'autres techniques d'isolation d'environnement existent, telles que l'utilisation de container LXC, mais ne seront pas abordées dans cet article.

Body

1. Principe de base de l'isolation d'environnements « chrootés »

Dans les systèmes d'exploitation UNIX, chroot est une commande servant à changer le répertoire racine d'un processus de la machine hôte. La commande permet alors d'isoler l'exécution d'un programme dans un environnement limité, sans accès au système complet. Par analogie, on peut voir chroot comme un coffre-fort à l'intérieur d'une banque ; quelqu'un enfermé dans ce coffre-fort ne peut accéder au reste de la banque (sauf s'il s'appelle Harry Houdini, mais nous nous égarons...).

2. Utilisation du chroot pré-intégré à OpenSSH

Depuis sa version 4.9, OpenSSH offre directement un chroot sur SFTP (SSH File Transfert Protocol). Cette version d'OpenSSH est disponible dans les dépôts depuis Ubuntu 9.10 et Debian 5. Les différentes commandes décrites ci-après sont saisies côté serveur distant.

Étape 1 : Préparation de l'environnement

1) Installation d'OpenSSH

Commençons par installer OpenSSH (si ce n'est déjà fait).

% sudo apt-get update ; sudo apt-get install openssh

Nous pouvons vérifier la version d'OpenSSH par la commande suivante :

% ssh -V

OpenSSH_6.0p1 Debian-4+deb7u1, OpenSSL 1.0.1e 11 Feb 2013

2) Choix et préparation de l'environnement utilisateur

Nous devons définir un dossier de base qui accueillera les homes (environnements isolés) de chaque utilisateur. Pour des raisons de facilité, nous placerons les différents environnements dans /home. Rien ne vous empêche de définir un autre dossier de base, que vous pouvez créer n'importe où :

% sudo mkdir -p /VOTRE_CHEMIN

Nous allons également créer un groupe qui rassemblera les utilisateurs SFTP et que nous appellerons (par exemple) sftpusers :

% sudo groupadd sftpusers

Étape 2 : Configuration

Les étapes préliminaires terminées, nous pouvons attaquer la configuration.

1) Configuration d'OpenSSH

La configuration du serveur OpenSSH se fait par le biais du fichier de configuration /etc/ssh/sshd_config. Nous allons commencer par remplacer le mode de gestion SFTP par défaut par le mode interne à SSH :

# Subsystem sftp /usr/lib/openssh/sftp-server

Subsystem       sftp    internal-sftp

Juste après cette section, nous allons définir les utilisateurs pour lesquels va s'appliquer ce mode de gestion :

Match Group sftpusers

      ChrootDirectory /home/%u

      ForceCommand  internal-sftp

      AllowTCPForwarding no

      X11Forwarding no

Vous pourriez de la même façon définir un pattern par utilisateur plutôt que par groupe, avec la syntaxe Match User NOM_DU_USER. Bien entendu, il faudra remplacer /home par tout autre dossier de base que vous auriez choisi au point précédent.

2) Création de compte utilisateur

Il ne reste plus qu'à créer des utilisateurs :

% sudo useradd -m -g sftpusers NOM_UTILISATEUR

% sudo passwd NOM_UTILISATEUR

Entrez le nouveau mot de passe UNIX : MDP_UILISATEUR

NOM_UTILISATEUR et MDP_UTILISATEUR doivent évidemment être remplacés par le nom et mot de passe de votre utilisateur. À noter qu'il faut ajouter l'argument -d /VOTRE_CHEMIN si vous n'utilisez pas /home comme dossier de base.

3) Validation de fonctionnement et configurations spécifiques

À ce niveau, vous pouvez déjà essayer depuis un poste client :

% sftp NOM_UTILISATEUR@SERVEUR_DISTANT

NOM_UTILISATEUR@SERVEUR_DISTANT's password:

Connection closed

Vous aurez alors un message d'erreur du type : « Connection closed, Error code 255, ... ». Il s'agit d'une sécurité incluse dans OpenSSH. En faisant un petit tour dans la manpage de sshd_config, nous noterons la description suivante :

ChrootDirectory

Specifies the pathname of a directory to chroot(2) to after authentication. All components of the pathname must be root-owned directories that are not writable by any other user or group. After the chroot, sshd(8) changes the working directory to the user's home directory.

La solution consiste à changer le propriétaire et les droits du dossier utilisateur :

% sudo chown root:root /home/NOM_UTILISATEUR

% sudo chmod o-w /home/NOM_UTILISATEUR

Réessayons de nous connecter depuis le client :

% sftp NOM_UTILISATEUR@SERVEUR_DISTANT

NOM_UTILISATEUR@SERVEUR_DISTANT's password:

Connected to SERVEUR_DISTANT.

sftp>

Parfait, ça fonctionne. Mais est-ce suffisant ? Essayons de vérifier que nous disposons bien d'un accès en écriture à l'environnement :

sftp> mkdir test

Couldn't create directory: Permission denied  

Comme indiqué précédemment, le premier niveau du dossier « chrooté » doit appartenir à root et ne doit pas être accessible en écriture aux autres utilisateurs. Donc, au niveau du principe de fonctionnement, il faut ajouter un sous-dossier qui, cette fois, appartiendra à l'utilisateur. Pour notre exemple, soit un dossier www :

% sudo mkdir /home/NOM_UTILISATEUR/www

% sudo chown NOM_UTILISATEUR /home/NOM_UTILISATEUR/www

Il ne nous reste plus qu'à valider que tout fonctionne correctement. Depuis le poste client :

% sftp NOM_UTILISATEUR@SERVEUR_DISTANT

NOM_UTILISATEUR@SERVEUR_DISTANT's password:

Connected to SERVEUR_DISTANT.

sftp> cd www

sftp> mkdir test

sftp> ls

test

sftp>

Maintenant, qu'en est-il de la connexion SSH normale ? Tentons de nous connecter en SSH simple :

% ssh NOM_UTILISATEUR@SERVEUR_DISTANT

NOM_UTILISATEUR@SERVEUR_DISTANT's password:

This service allows sftp connections only.

Connection to SERVEUR_DISTANT closed.

Nous venons donc de mettre en place un environnement isolé pour un utilisateur ! Vous pouvez répéter cette procédure pour chaque nouvel utilisateur.

3. Utilisation d'un chroot externe à OpenSSH

La simplicité de la solution précédente peut être intéressante s'il ne s'agit que de transferts de fichiers et d'opérations simples (renommage, déplacement…), mais nous pouvons être rapidement limités par les commandes disponibles. La solution alors, est de ne pas utiliser la commande chroot intégrée à OpenSSH, mais d'utiliser le chroot système.

Nous supposons que les différentes commandes décrites ci-après se font côté serveur distant. Par ailleurs, cette solution est indépendante de la solution précédente.

Étape 1 : Préparation de l'environnement

On commence par installer OpenSSH, comme dans la première partie. De même, on définit le répertoire qui accueillera les environnements isolés, puis un groupe d'utilisateurs (chrootusers ici).

Étape 2 : Configuration

1) Configuration de OpenSSH

Dans le fichier /etc/ssh/sshd_config, on ajoute une section pour définir les utilisateurs auxquels va s'appliquer ce mode de gestion :

Match Group chrootusers

      ChrootDirectory /home/%u

      AllowTCPForwarding no

      X11Forwarding no

À nouveau, il est possible de définir un pattern par utilisateur avec Match User NOM_DU_USER.

2) Création de compte utilisateur

% sudo useradd -m -g chrootusers NOM_UTILISATEUR

% sudo passwd NOM_UTILISATEUR

Entrez le nouveau mot de passe UNIX : MDP_UILISATEUR

Ici encore, n'oubliez pas d'ajouter l'argument -d /VOTRE_CHEMIN si vous n'utilisez pas /home comme dossier de base.

3) Génération de l'environnement restreint

Durant cette étape, nous allons générer une cage (jail) pour l'utilisateur. Cette dernière inclura les programmes et commandes que notre utilisateur aura le droit d'utiliser. Afin de simplifier les différentes opérations nécessaires à la génération de l'environnement restreint, nous allons commencer par créer un script de génération, que nous appellerons genJail.bash. Devant la complexité de ce script, nous allons le détailler partie par partie.

Pour commencer, déclarons nos variables d'environnement :

mag01

Dans APPS, nous déclarerons le chemin complet vers toutes les commandes que nous souhaitons accorder à l'utilisateur, séparées par un espace.

Nous allons à présent créer la structure de base du dossier utilisateur :

mag02

Ici, nous avons créé l'arborescence de base et généré les pseudo devices null et zero, utilisables directement par l'utilisateur dans sa cage et utilisés par nombre de commandes Linux. De nombreuses commandes ne fonctionnent pas (ou mal) si elles n'arrivent pas à récupérer les informations utilisateur (par exemple, la commande scp). Pour contourner ce problème, il faut générer un fichier etc/passwd contenant au minimum les informations sur l'utilisateur et sur root. Nous allons donc ajouter ceci dans notre script :

mag03

Ensuite, il faut copier dans la cage les dépendances des applications déclarées au début du script :

mag04

Malheureusement, ça ne suffit toujours pas. Comme expliqué précédemment, certaines applications nécessitent de récupérer les informations utilisateur. Juste créer un fichier passwd n'est pas suffisant, car en l'état, l'environnement de la cage ignore qu'il doit utiliser le fichier passwd. Pour ce faire, d'autres bibliothèques et fichiers de configuration sont nécessaires, mais n'ont pas été remontés par la commande ldd.

Sans rentrer dans les détails sur la méthode d'identification de ces fichiers, il faut comparer la liste des dépendances générée dans $TMPFILE3 avec les logs générés par la commande strace, en surveillance des applications demandant les UID et GID.

Au final, nous pouvons terminer notre script avec la récupération des fichiers manquants (certains à un emplacement fixe, d'autres à un emplacement variable en fonction de la distribution) les plus couramment utilisés (à noter qu'une identification basée sur autre chose que le fichier passwd local demandera sans doute d'autres librairies et fichiers de configuration) :

mag05

4) Ajout d'applications à l'environnement restreint : makejail

Nous avons un environnement restreint sur SSH fonctionnel. Après coup, nous pourrions avoir besoin d'autoriser l'une ou l'autre application supplémentaire. Comme nous avons pu le constater, la mécanique à mettre en œuvre n'est pas des plus simples. Pour faciliter l'ajout de nouvelles applications, nous allons cette fois utiliser un programme disponible dans les dépôts : makejail. Pour l'installer, nous utiliserons la commande suivante :

% sudo apt-get update 

% sudo apt-get install makejail

Ce programme fonctionne sur la base de scripts Python. Il rassemble à la fois la recherche de dépendances dynamiques (ldd) et de dépendances indirectes (strace).

Soit un fichier de configuration addCommand.pydans lequel nous allons définir les paramètres d'exécution demakejail :

mag06

Il suffit alors de lancer makejail avec notre fichier de configuration pour ajouter la(les) commande(s) à l'environnement restreint de l'utilisateur :

% sudo makejail addCommand.py

Le programme makejail lance des itérations successives de strace pour identifier tous les fichiers de dépendances indirectes. C'est à la fois sa force et sa faiblesse. Pour un grand nombre de commandes à ajouter à l'environnement restreint, son temps d'exécution devient vraiment énorme (principale raison pour laquelle il n'a pas été retenu pour la génération de l'environnement restreint initial).

Nous privilégierons donc son utilisation pour des environnements légers, ou pour des commandes ayant un grand nombre de dépendances (par exemple : Ruby, Python, …). Enfin, nous n'avons qu'effleuré l'utilisation du paquet makejail. Pour plus d'informations, je vous invite à visiter le site de son auteur sur http://www.floc.net/makejail/.

Nous avons vu que l'environnement restreint devait garder une trace des UID et GUID de l'utilisateur courant et de root pour certaines commandes (ex : scp). Si vous utilisez makejailplutôt que le scriptgenJail.bashdétaillé ci-avant, les informations de UID/GUID devront être ajoutées manuellementdans les fichiers /etc/passwd et /etc/group de l'environnement restreint.

Conclusion

Avec chacune de ces méthodes, nous arrivons au résultat final souhaité qui était d'avoir un dossier web accessible avec une session restreinte. La première méthode, plus simple à mettre en place, est plus limitée que la seconde. Nous avons également vu comment ajouter simplement des commandes à un environnement restreint existant, à l'aide du paquet makejail. Enfin, vous pourriez obtenir des solutions comparables par l'utilisation de conteneurs (LXC, …).

Il ne reste plus qu'à configurer votre serveur web pour utiliser ces dossiers pour le rendu de vos pages web. Si votre serveur web s'exécute avec un utilisateur particulier (par ex : www-data), ajoutez à votre procédure la création d'un groupe contenant votre utilisateur ET l'utilisateur du serveur web. Ensuite, définissez ce groupe comme groupe de base du dossier www de votre utilisateur.




Articles qui pourraient vous intéresser...

Sécurité réseau dans un cluster Kubernetes

Magazine
Marque
MISC
Numéro
112
Mois de parution
novembre 2020
Domaines
Résumé

En introduisant le concept de micro-services, Kubernetes lance un nouveau défi aux solutions d’isolation et de filtrage réseau : comment gérer les droits d’accès réseau dans une infrastructure en constante mutation et dans laquelle une machine n’a plus un rôle prédéterminé ?

Introduction au dossier : Sécurisez vos serveurs et votre réseau local

Magazine
Marque
Linux Pratique
HS n°
Numéro
49
Mois de parution
novembre 2020
Domaines
Résumé

2020 aura été une année marquante pour nos vies et nos sociétés. Il aura fallu se réinventer, trouver des solutions à des situations exceptionnelles. Dans les entreprises, l'Éducation ou la Santé, la mobilisation des ressources informatiques aura été maximale. Nos infrastructures auront ployé, tangué, parfois presque craqué, mais au final, cela aura tenu.

Passez à nftables, le « nouveau » firewall de Linux

Magazine
Marque
Linux Pratique
Numéro
122
Mois de parution
novembre 2020
Domaines
Résumé

Le firewall est un élément important pour sécuriser un réseau. Il est prouvé que la sécurité par l’obscurantisme ne fonctionne pas. Ce n’est donc pas une bonne idée d’utiliser une boîte noire en priant pour que tout se passe bien. Un bon firewall est donc installé sur un système d’exploitation libre. Linux fait évoluer le sien d’iptables vers nftables. Nous montrons dans cet article comment débuter avec la nouvelle mouture.

Répondez aux problématiques de sécurité d’accès avec OpenSSH

Magazine
Marque
Linux Pratique
HS n°
Numéro
49
Mois de parution
novembre 2020
Domaines
Résumé

Notre infrastructure est désormais stable et sécurisée tant au niveau système que réseau. Nous allons pouvoir étudier de manière un peu approfondie un logiciel particulier : OpenSSH. Ce démon réseau nous permet de nous connecter en toute sécurité sur nos serveurs via le protocole SSH. Son développement a commencé il y a plus de 20 ans chez nos amis d’OpenBSD. La liste de ses fonctionnalités est d’une longueur impressionnante. Nous allons en parcourir ensemble quelques-unes qui, je l’espère, nous permettront d’améliorer tant notre sécurité que notre productivité quotidienne.

Définissez l'architecture de vos serveurs et installez-les

Magazine
Marque
Linux Pratique
HS n°
Numéro
49
Mois de parution
novembre 2020
Domaines
Résumé

Dans cet article, nous réfléchirons aux besoins de sécurité auxquels nos serveurs devront répondre. Il sera d’ailleurs plus question d’architecture que de serveur personnel. Pourquoi cela ? Car nos besoins vont à coup sûr évoluer dans le temps. L’approche la plus pérenne sera donc de mener une réflexion basée sur des services et non sur un serveur unique. Nous allons aussi nous attacher à assurer la résilience de nos services de base. Nos choix d’architecture auront pour objectif de pouvoir mieux détecter, contrer et éventuellement réparer les dommages causés par une attaque informatique. Nous pourrons par exemple restaurer nos services si un attaquant réussissait à prendre le contrôle du serveur. Notre plan de bataille commencera par la définition des grandes lignes de notre infrastructure, puis par la sélection de nos fournisseurs. Nous déploierons ensuite le serveur avec un premier palier de sécurisation système.