Confinement de processus
Date de publication : 12/01/2007
Par
julp (Autres articles)
Une jail (ou prison en français) est un système de confinement de processus qui
permet d'exécuter un processus dans un sous-environnement virtuel complet qui
n'a pas accès au système principal. En emprisonnant les programmes peu sûrs, les
risques de compromission sont donc limités.
Cet article, destiné à FreeBSD 5.0 et versions supérieures, vous aidera à mettre
en place un tel confinement comprenant une étape facultative : la possibilité
de lui limiter l'espace disque en l'enfermant dans un fichier.
1. Présentation
2. Utilisation de pseudo-devices (étape facultative)
2.1. Principe
2.2. Création du fichier
2.3. Initialisation du système de fichier
2.4. Opération de montage/démontage
2.5. Augmenter la taille du fichier
3. Mise en oeuvre de la jail
3.1. Installation de la jail
3.2. Configuration de la jail
3.3. Configuration du système principal
3.3.1. Les adresses IP
3.3.2. Le démarrage des jails
3.3.3. Les variables de la MIB
4. Utilisation avancée de la jail
4.1. Mise à jour d'une jail
4.2. Comment gérer les ports avec les jails ?
4.2.1. Méthode avec accès en lecture et écriture sur le système de ports
4.2.2. Méthode avec accès en lecture seule sur le système de ports
5. Interaction avec la jail
5.1. A distance
5.2. Depuis le système principal
6. Conclusion
6.1. Epilogue
6.2. Remerciements
1. Présentation
Basé sur la fonction chroot, le mécanisme jail offre le principe
d'emprisonnement de processus. Son intérêt réside dans le fait
qu'il va beaucoup plus loin car il reproduit un environnement
complet au sein d'un environnement parent.
Mettre en place une jail s'avère utile et efficace pour confiner des
services ou des utilisateurs auxquels on n'accorde aucune confiance ou qui
présentent un certain risque vis-à-vis de la stabilité ou de l'intégrité
du système. Une prison consiste en un environnement virtuel avec ses
propres fichiers de configuration, une gestion des utilisateurs séparée,
le tout rattaché à une adresse IP sous forme d'un alias. Par ailleurs,
un processus enfermé dans une jail est comme derrière une glace sans
tain : il évolue librement mais ne peut ni agir ni voir au-delà de cet
environnement restreint alors qu'inversement le système principal,
le peut. Dans le cas d'une attaque, l'intrus gagnerait un accès local par
un exploit distant pour ensuite obtenir un accès root par un exploit
local mais se verrait cantonné à la prison qu'il a réussi à infiltrer.
L'utilisation des jails ne se limite pas au renforcement de la sécurité
mais peut s'avérer fort utile pour héberger de façon temporaire des
services (en cas de tests ou de pannes notamment).
2. Utilisation de pseudo-devices (étape facultative)
2.1. Principe
Pour plus de sécurité mais aussi pour limiter la taille occupée par
une jail, il est possible d'utiliser des pseudo-devices dont le but
est de traiter un fichier comme un device. En d'autres termes, il
s'agit de manipuler un fichier comme s'il s'agissait d'une partition.
L'intérêt de cette étape est de pouvoir limiter l'espace disque
associé à une prison et de vous assurer qu'elles ne satureront pas
celui qui est disponible pour le système principal. Il vous sera
également aisé de vous en débarrasser (en cas de compromission par
exemple).
2.2. Création du fichier
Pour créer un fichier d'une taille prédéfinie, nous utilisons la
commande truncate ou dd comme suit :
truncate -s 200M /usr/jails/jail1.dsk
dd if=/dev/zero of=/usr/jails/jail1.dsk bs=1k count=200k
|
 |
Concernant la taille, il faut déjà compter un peu plus de 150Mo pour
le système de base de votre jail.
|
2.3. Initialisation du système de fichier
Pour pouvoir utiliser ce fichier comme un device, il faut créer le
système de fichier. Pour cela, nous procédons ainsi :
2.4. Opération de montage/démontage
Pour monter le fichier :
mdconfig -a -t vnode -f /usr/jails/jail1 -u 0
mount /dev/md0c /mnt
|
Pour démonter le fichier :
Automatisons les opérations de montage et démontage de tels points
via /etc/fstab. Pour cela, ajoutez une nouvelle ligne sur le
modèle suivant :
/dev/md0 /jails/jail1 mfs rw,-PF/usr/jails/jail1.dsk 0 0
|
 |
Vous devez impérativement appliquer le patch suivant
à mdmfs qui permet d'ajouter l'option -P indiquant au système de ne
pas recréer le système de fichier (sinon vous perdez toutes vos données
à chaque redémarrage, autant dire que c'est gênant). Vous serez
probablement obligés de contrôler sa bonne application et d'appliquer
manuellement ce qui ne l'a pas été. Puis pour recompiler mdmfs :
cd /usr/src/sbin/mdmfs && make && make install
Cette option a été ajoutée en début d'année 2006 (correspondant à la
révision 1.26 de mdmfs), par conséquent les versions récentes de
FreeBSD ne sont pas concernées (la commande mdmfs -h ou
bien man mdmfs vous permettront d'en prendre connaissance).
|
2.5. Augmenter la taille du fichier
Il est tout à fait possible d'augmenter la taille du fichier d'accueil
de la jail sans perte à l'aide de la commande growfs. En voici
la procédure :
umount /jails/jail1
mdconfig -a -t vnode -f /usr/jails/jail1.dsk -u 0
dd if=/dev/zero of=/usr/jails/jail1.dsk bs=1k count=50k seek=200k
truncate -s +50M /usr/jails/jail1.dsk
growfs -y /dev/md0
|
3. Mise en oeuvre de la jail
A titre d'exemple, deux jails seront mises en place, voici les paramètres
que nous utiliserons dans la suite de cet article les concernant :
| |
Adresse IP |
Chemin utilisé comme racine |
Nom d'hôte |
| Système principal |
192.168.100.70 |
non concerné |
non montré dans l'exemple |
| Jail "ldap1" |
192.168.100.71 |
/jails/ldap1 |
ldap1.developpez.com |
| Jail "ldap2" |
192.168.100.72 |
/jails/ldap2 |
ldap2.developpez.com |
3.1. Installation de la jail
L'installation du système de la jail est relativement simple puisque
ce processus reprend l'étape d'installation du monde, voyez par
vous-même :
 |
Vous devez préalablement avoir recompilé le monde ne serait-ce
qu'une fois.
|
3.2. Configuration de la jail
L'essentiel de la configuration de la jail passe par son
fichier /etc/rc.conf où nous n'activons que le nécessaire,
désactivons tout ce qui est lancé par défaut et réajustons les
paramètres de certains démons :
rpcbind_enable="NO"
network_interfaces=""
hostname="ldap1.mon_domaine.com"
sendmail_enable="NONE"
syslogd_flags="-ss"
|
Enfin, n'omettez pas de configurer des fichiers qui peuvent s'avérer
utiles comme /etc/resolv.conf.
3.3. Configuration du système principal
3.3.1. Les adresses IP
Une jail fonctionne avec une IP différente du système principal.
Par conséquent il faut attribuer une IP supplémentaire à la carte
réseau de la machine, c'est ce qu'on appelle l'IP aliasing. Pour
la configurer de manière permanente, nous la déclarerons dans le
fichier /etc/rc.conf comme suit :
ifconfig_ed0="inet 192.168.100.70 netmask 255.255.255.0"
ifconfig_ed0_alias0="inet 192.168.100.71 netmask 255.255.255.255"
ifconfig_ed0_alias1="inet 192.168.100.72 netmask 255.255.255.255"
|
 |
FreeBSD présente la particularité pour les alias sur les cartes
réseau de devoir mettre comme masque réseau 255.255.255.255 si
l'alias IP se situe dans le même réseau que l'adresse principale.
|
3.3.2. Le démarrage des jails
Afin de lancer et arrêter vos jails de façon automatique au
démarrage/arrêt de la machine, il faut une fois de plus modifier
le contenu de votre fichier /etc/rc.conf :
jail_enable="YES"
jail_list="ldap1 ldap2"
jail_ldap1_hostname="ldap1.developpez.com"
jail_ldap1_ip="192.168.100.71"
jail_ldap1_rootdir="/jails/ldap1"
jail_ldap1_exec="/bin/sh /etc/rc"
jail_ldap1_devfs_enable="YES"
jail_ldap2_hostname="ldap2.developpez.com"
jail_ldap2_ip="192.168.100.72"
jail_ldap2_rootdir="/jails/ldap2"
jail_ldap2_exec="/bin/sh /etc/rc"
jail_ldap2_devfs_enable="YES"
|
Il vous sera également possible de les arrêter ou de les relancer
de manière très simple à l'aide du script /etc/rc.d/jail :
-
Démarrer les jails ldap1 et ldap2 :
/etc/rc.d/jail start ldap1 ldap2
|
-
Redémarrer la jail ldap2 :
/etc/rc.d/jail restart ldap2
|
-
Stopper toutes les jails :
Vous pouvez toutefois lancer une jail manuellement avec la
commande suivante sans avoir à renseigner /etc/rc.conf :
jail -l -U root <racine de la prison> <nom de la prison> <ip de la prison> <commande (pour la lancer : /bin/sh /etc/rc)>
|
3.3.3. Les variables de la MIB
Voici une liste exhaustive des variables de la MIB qui concerne
les jails et les implications liées à chacune d'elles en fonction
de leurs valeurs :
-
security.jail.allow_raw_sockets : la valeur 1 autorise
l'utilisation des utilitaires comme ping ou traceroute.
A l'inverse, une valeur nulle les interdit.
-
security.jail.enforce_statfs (FreeBSD 6) : cette entrée
concerne le comportement des appels systèmes statfs,
fstatfs, getfsstat et fhstatfs vis à vis de la jail.
Ainsi avec la valeur nulle, la jail a accès à tous les
points de montage sans restriction, en revanche, fixée à
1 seuls les points de montage liés à la jail sont visibles
et le chemin de la racine de la prison est supprimé du
début de ceux-ci. La valeur 2 (par défaut) restreint
l'utilisation des appels systèmes précédents aux points
de montage situés dans la jail. Une illustration sera
plus claire :
-
Avec security.jail.enforce_statfs égal à 0 :
[root@ldap1 /]# df -h
Filesystem Size Used Avail Capacity Mounted on
/dev/ad0s1a 496M 57M 399M 13% /
devfs 1.0K 1.0K 0B 100% /dev
/dev/ad0s1e 496M 15M 441M 3% /tmp
/dev/ad0s1f 25G 3.8G 19G 17% /usr
/dev/ad0s1d 1.3G 90M 1.1G 8% /var
/dev/ad1s1d 58G 14M 53G 0% /usr/home
procfs 4.0K 4.0K 0B 100% /proc
devfs 1.0K 1.0K 0B 100% /usr/jail/dev
|
-
Avec security.jail.enforce_statfs égal à 1 :
[root@ldap1 /]# df -h
Filesystem Size Used Avail Capacity Mounted on
/dev/ad0s1f 25G 3.8G 19G 17% /
devfs 1.0K 1.0K 0B 100% /dev
|
-
Avec security.jail.enforce_statfs égal à 2 :
[root@ldap1 /]# df -h
Filesystem Size Used Avail Capacity Mounted on
/dev/ad0s1f 25G 3.8G 19G 17% /
|
security.jail.getfsstatroot_only (FreeBSD 5.3, 5.4, 5.5) : même
effet que ci-dessus mais la valeur 2 n'est pas disponible.
-
security.jail.set_hostname_allowed : autoriser (valeur 1)
ou interdire (valeur 0, recommandée) à la prison de modifier
le nom d'hôte qui lui est associé.
-
security.jail.socket_unixiproute_only : la valeur 1 limite
la jail à n'avoir accès qu'à la partie de la pile des
protocoles réseau qui lui est nécessaire (minimale :
sockets locales et de routage, adresse IP version 4).
Pour autoriser l'accès à d'autres domaines, utilisez la
valeur zéro (réservée aux cas particuliers).
-
security.jail.sysvipc_allowed : cette entrée détermine si
la communication entre processus est partagée entre l'hôte
et les jails. La valeur zéro (par défaut) l'interdit et la
valeur 1 l'autorise (fortement déconseillé).
-
security.jail.chflags_allowed (FreeBSD 6) : avec une
valeur non nulle, l'utilisateur privilégié de la prison
(root) pourra manipuler les attributs accolés aux fichiers.
Par contre, la valeur nulle (zéro) interdit de mettre ou
de supprimer les attributs à cet utilisateur : seul
l'utilisateur privilégié du système principal pourra
agir sur ces drapeaux.
Vous trouverez ci-dessous les valeurs les plus restrictives pour
toutes les variables de la MIB concernant les jails. Ajoutez
celles-ci dans le fichier /etc/sysctl.conf de votre
système principal :
security.jail.set_hostname_allowed=0
security.jail.socket_unixiproute_only=1
security.jail.sysvipc_allowed=0
security.jail.allow_raw_sockets=0
security.jail.enforce_statfs=2
security.jail.chflags_allowed=0
|
4. Utilisation avancée de la jail
4.1. Mise à jour d'une jail
Inutile de télécharger à nouveau, stocker et recompiler les sources
du système pour chaque jail. Vous économiserez ainsi plus de 300 Mo
par jail et du temps. En effet, il est bien plus simple de mettre à
jour les différentes jails depuis le système principal. Cela ne demande
plus qu'une seule compilation du système, une seule mise à jour des
sources, ... Comment faire la mise à jour donc ? C'est bien simple,
on procède à peu près comme l'installation de la jail avec quelques
commandes supplémentaires pour la mise à jour, ce qui nous donne :
On pourra éventuellement automatiser la mise à jour à l'aide d'un
script, notamment lorsque plusieurs jails sont présentes sur un même
système.
4.2. Comment gérer les ports avec les jails ?
Encore une fois, il serait vite ingérable de stocker les ports
(qui représentent au passage 370 Mo) sur chaque jail. Surtout
qu'il faut régulièrement les mettre à jour. La solution consiste
donc à utiliser les ports du système principal.
4.2.1. Méthode avec accès en lecture et écriture sur le système de ports
Pour accéder en lecture et écriture aux ports le temps de
l'installation ou mise à jour des logiciels tiers installés,
nous utiliserons le système de fichier nullfs qui permet de
dupliquer une partie d'un système de fichier afin qu'elle soit
vue par un chemin différent.
kldload /boot/kernel/nullfs.ko
mount_nullfs -o rw /usr/ports /jails/ldap1/usr/ports
cd /usr/ports/sysutils/portupgrade
make install
umount /jails/ldap1/usr/ports
|
Cette méthode convient parfaitement pour les environnements de
test, c'est à dire pour envisager des mises à jour de certains
logiciels qui peuvent s'avérer épineux (exemple expérimenter la
migration de MySQL 4.0 vers une version 4.1 ou supérieure). En
effet, l'accès en lecture et écriture sur l'hôte n'est pas
recommandé lorsque les jails sont utilisées à des fins
sécuritaires.
4.2.2. Méthode avec accès en lecture seule sur le système de ports
Cette approche est fortement similaire à la précédente puisque le
système de ports est exporté en lecture seule :
Il devient alors nécessaire de redéfinir les répertoires de
travail sur la jail, ceux du système étant inaccessibles en
écriture, comme par exemple /usr/ports/disfiles/ qui
accueille les sources téléchargées. Pour cela nous modifions
/etc/make.conf de chaque jail pour changer ceux-ci :
WRKDIRPREFIX=/var/tmp
PORTS_INDEX=/var/tmp/INDEX
DISTDIR=/var/tmp/distfiles
|
L'utilitaire portupgrade et ses confrères nécessitent
également une reconfiguration pour s'y adapter. Il nous faut
donc modifier /usr/local/etc/pkgtools.conf tel que :
ENV['PORTSDIR'] ||= '/usr/ports'
# <Ajouts>
ENV['PORTS_DBDIR'] ||= '/var/ports/db'
ENV['PORTS_INDEX'] ||= ENV['PORTS_DBDIR'] + '/INDEX'
ENV['PKG_DBDIR'] ||= '/var/db/pkg'
# </Ajouts>
ENV['PACKAGES'] ||= ENV['PORTSDIR'] + '/packages'
ENV['PKG_PATH'] ||= ENV['PACKAGES'] + '/All'
ENV['PKG_BACKUP_DIR'] ||= ENV['PKG_PATH']
|
Ce procédé présente l'inconvénient de requérir plus d'espace
disque (quantité qui varie en fonction des ports à installer).
Il vous sera peut être nécessaire d'effectuer des nettoyages
réguliers.
 |
Pour pouvoir effectuer la mise à jour de vos logiciels sur chaque
jail via portupgrade, il vous faudra installer ce dernier sur
chacune d'entre elles.
|
5. Interaction avec la jail
5.1. A distance
Si vous envisagez d'administrer ou accéder à la jail essentiellement
à distance, orientez-vous vers SSH.
5.2. Depuis le système principal
En revanche, si vous comptez administrer la jail uniquement depuis
votre système principal, utilisez les programmes fournis par jailutils :
cd /usr/ports/sysutils/jailutils
make install clean
|
Jailutils regroupe :
- jps : liste les processus d'une jail
- jid : obtenir l'identifiant d'une jail
- jstart : démarre une jail de façon sécurisée
- jkill : stoppe une jail
- jails : liste les jails en activité
- injail : permet de déterminer si un processus fonctionne dans une jail
Sont également déjà présents sur votre système :
- jexec : exécute une commande dans une jail
- jls : liste les jails en fonctionnement ainsi que leur propriétés (identifiant, adresse IP, nom d'hôte et chemin racine)
 |
Je vous déconseille fortement, de manipuler (surtout en édition ou
bien avec les commandes capables de suivre les liens symboliques)
les fichiers d'une jail depuis votre système principal. Cela est
tentant afin de gagner du temps mais ce n'est pas forcément le
cas. Je m'explique, si vous avez la malchance de manipuler un fichier
qui est en réalité un lien symbolique, ce dernier pointera sur un
fichier de votre système principal au lieu de la jail. Préférez donc
l'utilisation de la commande jexec quitte à utiliser des alias par
exemple pour vous simplifier la vie.
|
6. Conclusion
6.1. Epilogue
Quelque soit l'utilisation que vous comptez faire des jails, vous êtes,
à l'issue de cet article, en mesure de créer, configurer une prison
selon le niveau de sécurité désiré, la mettre à jour ou encore
installer des logiciels tiers à l'aide du système de logiciels portés.
Peu de systèmes offrent une fonctionnalité aussi poussée et je ne
peux qu'encourager les heureux possesseurs de FreeBSD à mettre en
oeuvre celle-ci au moins une fois pour en comprendre l'intérêt ainsi
que les rouages.
6.2. Remerciements
Je remercie
jc_cornic pour sa relecture attentive.


Copyright © 2007 julp. Aucune reproduction, même partielle, ne peut être faite
de ce site et de l'ensemble de son contenu : textes, documents, images, etc
sans l'autorisation expresse de l'auteur.
Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E
de dommages et intérêts.
Cette page est déposée à la
SACD.