Jail FreeBSD
Un article de Diablotins.org.
|
Confiner des processus, ou comment mettre un autre FreeBSD dans votre FreeBSD.
Une «Jail» est, comme son nom l'indique, un endroit où l'on va confiner (emprisonner) des processus afin qu'ils n'empiètent pas sur le territoire de leur hôte.
Ce document se propose d'en expliquer le principes et la mise en œuvre dans de multiples cas, tel que des services chrootés dans des environnements clos et restreints, ou des machines virtuelles.
La commande jail (8) et l'appel système associé jail (2) existent depuis FreeBSD 4.0.
Le système utilisé lors de la rédaction est un FreeBSD 6.2; la branche VII ne semble pas présenter de différences.
Sommaire |
Introduction
Le modèle Unix des droits est simple mais rapidement insuffisant pour faire face à des situations complexes où l'on doit déléguer certains droits d'administrations.
L'ajout d'un contrôle d'accès fin améliore les choses, mais au prix de la complexité de l'administration et de l'implémentation.
Les Jails permettent de partager l'environnement tout en gardant le modèle simple des droits Unix.
Dans une Jail, les utilisateurs sont confinés dans leur prison, le super-utilisateur (root) conserve son rôle mais ses actions y sont limitées.
La solution des jails
Cette solution partage l'environnement général,
-les systèmes de fichiers, les ressources réseaux, etc. -
entre les processus.
L'environnement est divisé en :
- Processus.
Un processus emprisonné et ses descendant ne peuvent pas sortir de leur prison.
Un processus emprisonné ne peut pas agir sur un processus hors de sa prison.
Root reste un utilisateur privilégié mais ses droits sont très fortement limités :
- interdiction de créer des nœuds de périphériques.
- pas de possibilité de monter / démonter un système de fichier.
- pas de possibilité de modifier les routes réseaux.
- etc...
En résumé, seules les actions impactant la Jail sont autorisées.
- Système de fichiers.
Seule l'arborescence de la prison est visible (comme chroot).
- Réseau.
Chaque Jail est attachée à une adresse IP(v4) et les processus emprisonnés ne peuvent que s'attacher à cette adresse.
En cas d'utilisation de raw socket (interdites par défaut), les adresses IP sont forcées.
Ces limitations ne sont implémentées que pour les sockets IPv4 (ou locales), tout autre domaine est interdit.
[source: <http://docs.freebsd.org/44doc/papers/jail/jail.html>]
Interlude
Exécution d'une jail
Cet exemple lance un shell (sh) dans une jail sur /rescue (les binaires dans /rescue sont liés statiquement), l'adresse IP est 192.168.2.1 et le nom d'hôte "roxette-1". Il nous faut une adresse IP pour la jail, nous utilisons un alias sur une interface ici lo0 :
# ifconfig lo0 alias 192.168.2.1 netmask 0xffffffff
Il nous faut aussi les nœuds de périphériques (devfs) dans le système de fichier de la jail, comme pour un chroot.
# mkdir /rescue/dev # mount -t devfs dev /rescue/dev
On lance sh dans une prison.
# jail /rescue roxette-1 192.168.2.1 sh (à partir de ce point, nous sommes dans la prison) # ./ls on est à la racine (ie chrooté dans /rescue) # ./ps PID TT STAT TIME COMMAND 53606 p4 SJ 0:00.00 sh 53610 p4 R+J 0:00.00 ./ps (on notera que les processus root tournant sur l'hôte principal n'apparaissent pas). Le 'J' dans la colonne STAT indique que le processus est emprisonné. Comment s'appelle-t-on ? # ./hostname roxette-1 Testons le confinement de root : # ./mount /dev/ad0s3a on / (ufs, local, noatime) # ./umount /dev/ad0s3a umount: unmount of / failed: Operation not permitted
La prison vue de l'hĂ´te
Ici nous somme root mais sur l'hĂ´te (ie pas dans la jail).
jls(8) permet de lister les jails actives et leur 'JID' :
# jls
JID IP Address Hostname Path
9 192.168.2.1 roxette-1 /rescue
Les processus jailés sont également marqués 'J' avec ps :
# ps PID TT STAT TIME COMMAND 1467 v0 Is+ 0:00,00 /usr/libexec/getty Pc ttyv0 [...] 53629 p4 I+J 0:00,00 /sh (On notera que les processus root tournant en jail sont visibles).
jexec(8) permet de lancer un processus dans une jail existante Ă partir de l'hĂ´te :
# jexec 9 ./ps PID TT STAT TIME COMMAND 53629 p4 I+J 0:00.00 /sh 53705 p7 R+J 0:00.00 ./ps
Maintenant retournons dans notre sh emprisonné et quittons le shell.
# exit (lĂ on retourne Ă l'hĂ´te) # jls
La jail est détruite automatiquement. Une jail est détruite lorsque plus aucune ressource ne l'utilise (par refcounting). Ça peut parfois être long, par exemple lorsque une socket TCP (jailée) est toujours active.
Utilisations
Le petit exemple précédent montre les caractéristiques de jail(8). On peut heureusement faire des choses plus utiles. Jail permet de mettre en œuvre des machines virtuelles FreeBSD complètes, ou bien de confiner un service particulier à la manière de chroot, mais en mieux.
Machines virtuelles
Il faut bien noter que jail n'est pas une vraie virtualisation, il n'y a pas plusieurs machines virtuelles qui se partagent un même matériel. Jail n'effectue qu'un confinement des processus, il n'y a qu'un système (un seul noyau). La virtualisation est seulement -euh- virtuelle.
L'implémentation de jail est simple, lorsqu'un processus est jailé, une structure "prison" contenant les données de la jail est créée et liée au processus et à ses descendants. Il n'y a pas moyen de modifier cette structure après la création. Ensuite un chroot est effectué à la racine de la prison. Le confinement est réalisé par des tests dans le noyau. Le surcoût en terme de puissance est donc extrêmement faible.
Par exemple pour un processus jailé, la possibilité d'envoyer un signal est limité à un processus de la même jail, cela est fait par un simple test « prison_check() »
sys/kern/kern_proc.c int cr_cansignal(struct ucred *cred, struct proc *proc, int signum) { int error; PROC_LOCK_ASSERT(proc, MA_OWNED); /* * Jail semantics limit the scope of signalling to proc in the * same jail as cred, if cred is in jail. */ error = prison_check(cred, proc->p_ucred); if (error) return (error); [...]
Isoler un service
Ici, seul FreeBSD peut proposer ce service. Là où sur la majorité des systèmes UNIX, on ne peut que chrooter le service sensible ; sur FreeBSD on va pouvoir le confiner, assurant ainsi un niveau de sécurité plus élevé. Le mécanisme peut être mis en œuvre sur beaucoup de services.
Nous en verrons divers exemples et réalisations. Les cas les plus intéressants sont bien sûr les accès SSH, FTP, les services comme un DNS, et tout services à ressources closes. Nous verrons les différences de mise en œuvre de chaque cas.
Mise en œuvre
Ce chapitre va exposer la commande Jail, et les contraintes de configuration qu'elle entraîne dans le cas le plus général. Nous allons voir que l'utilisation de Jail impose des règles de configuration de l'hôte strict au niveau réseau.
Nous commencerons par voir l'aspect topologique, puis la configuration du système et des services obligatoires. D'une manière générale et je le redirais, il doit y avoir un minimum de services qui tournent sur l'hôte.
Topologies
On considérera pour notre document une machine physique ayant deux interfaces réseaux : xl0 et xl1 (ces noms de devices sont ceux des cartes réseaux typiques de 3COM 3cXXX). Il est intéressant quelque soit le type de jail que l'on veut mettre en œuvre d'avoir deux interfaces Ethernet sur la machine hôte, nous verrons pourquoi dans le chapitre sur la sécurisation de la Jail depuis l'hôte. L'hôte aura pour IP : 192.168.1.1 sur le réseau 1. Les jails prendront IP sur le réseau 2. (Deux réseaux physiques peuvent êtres mis en place améliorant ainsi la sécurité) D'où pour une première Jail : L'IP sera 192.168.2.1.
L'utilisation d'une interface physique n'est pas obligatoire, on peut très bien utiliser des alias IP sur une interface logique, par exemple lo0.
L'hĂ´te
(Ici, encore, et comme dans la majeur partie du reste de cette documentation, il est important de bien maîtriser la configuration de FreeBSD, et donc je vous renvoie a la documentation sur la configuration de FreeBSD)
Pour rappel, le processus d'initialisation de FreeBSD s'appelle RC et est configuré par l'intermédiaire du fichier /etc/rc.conf.
Voici les lignes qu'il faut modifier au minimum (si vous avez suivi la procédure de configuration et d'installation prescrite).
# vi /etc/rc.conf -- [...] inetd_flags= "-wW -a 192.168.1.1" sendmail_enable= "NO" syslogd_flags="-s" [...]
Nous allons détailler chaque ligne modifiée ou ajoutée à rc.conf. La page de man de jail(8) décrit plus en détail la procédure dans le paragraphe «Setting up the Host Environment».
Inetd
Par défaut les démons de l'hôte écoutent sur toutes les IP, il faut donc les configurer pour qu'ils n'écoutent que sur leur IP qui n'est pas attribuée à une jail.
inetd_flags= "-wW -a 192.168.1.1"
Le flag passé à INetd l'oblige à n'écouter que sur l'IP réel de la première interface et non sur les alias ou l'adresse de la deuxième interface que l'on réservera aux jails de notre système.
Et si on n'utilise pas INetd, il vaut encore mieux l'arrĂŞter.
#inetd_enable="YES" commentez la ligne
Sendmail
Pour Sendmail, soit on coupe le démon, soit on modifie sa configuration. (Dans cette documentation on ne verra pas comment faire cette configuration) On ne chargera pas le démon.
sendmail_enable= "NO"
Syslogd
Syslogd reçoit le flag -s qui lui indique de travailler en mode sécurisé, c'est-à -dire qu'il ne journalise plus les machines distantes. Il est important de faire travailler syslogd en mode sécurisé sur l'hôte, une machine spécifique par réseau doit réaliser la tâche de regrouper les logs venant des autres machines.
syslogd_flags="-s"
Réseau
Il nous faut maintenant créer un alias IP pour notre Jail. (Exemple pour un serveur Intel ISC ou Dell POWER EDGE) Device : xlX La commande manuelle est :
# ifconfig xl0 inet 192.168.1.1 netmask 255.255.255.0 # ifconfig xl1 inet 192.168.2.1 netmask 255.255.255.0 # ifconfig xl1 inet alias 192.168.2.2 netmask 255.255.255.255 [...]
Pour que cela soit fait automatiquement au démarrage :
# vi /etc/rc.conf -- [...] # carte ethernet 1 hote ifconfig_xl0="inet 192.168.1.1 netmask 0xffffff00" #carte ethernet 2 (jails) ifconfig_xl1="inet 192.168.2.1 netmask 0xffffff00" ifconfig_xl1_alias0="inet 192.168.2.2 netmask 0xffffffff" ifconfig_xl1_alias1="inet 192.168.2.3 netmask 0xffffffff"
(Pour plus d'informations voir le man de ifconfig et de rc.conf et la documentation sur l'installation de FreeBSD et sa configuration. )
Configuration des démons standard
Aller Ă l'essentiel
Il ne faut faire tourner qu'un minimum de démons sur la machine hôte, pour être précis seul SSH devrait tourner.
SSH
Pour sshd, le principe est le même que pour inetd, il ne doit écouter que sur l'IP de l'hôte. Dans le fichier de conf de sshd, /etc/ssh/sshd_config, on ajoute :
# vi /etc/ssh/sshd_config -- [...] ListenAddress 192.168.1.1 [...]
Routes
Vous devez alors vérifier si il n'existe pas de route existante entre vos jails du réseau 2 et votre hôte du réseau 1, pour cela il y a deux choses à faire :
- Vérifier qu'il n'a pas de forward entre les deux interfaces réseaux ethernet :
Tapez :
# sysctl net.inet.ip.forwarding
Si la variable est Ă 1, alors passez la Ă 0 en tapant :
# sysctl net.inet.ip.forwarding=0
Et vérifiez l'absence d'un gateway_enable="YES" dans /etc/rc.conf ou la mise à un dans /etc/sysctl.conf.
- Vérifier les routes via la commande :
# netstat -rn
S'il existe des routes entre les deux réseaux, supprimez les avec la commande : route delete
Suppression de messages d'erreurs ARP
Dans le cas où les Jails sont dans le même réseau, les deux interfaces vont répondre l'une pour l'autre aux requêtes ARP sans que ce soit réellement un problème, mais FreeBSD va journaliser ces erreurs ARP, au risque de miner le fichier journal /var/log/messages Pour les supprimer il faut cette fois-ci forcer à 0 la variable
# sysctl -w net.link.ether.inet.log_arp_wrong_iface=1 # echo "net.link.ether.inet.log_arp_wrong_iface=1" >> /etc/sysctl.conf
Une machine virtuelle
Ici, l'objectif est de créer une machine virtuelle similaire à l'hôte. Un utilisateur d'une de ces machines virtuelles utilise donc un système FreeBSD complet mais confiné dans une prison. Dans le cas où l'utilisateur est root, ses droits sont en outre fortement limités.
Le principe est simple. Lorsqu'un système FreeBSD démarre, après le lancement de init, il exécute le script /etc/rc. Le script rc poursuit l'initialisation de la machine et le lancement des démons en suivant la configuration données par /etc/rc.conf. Ici on fait la même chose sauf que ce script rc est lancé dans une jail.
À la racine de la jail, il faut recopier le système FreeBSD complet (la base). Cela se fait par un make installworld. Si on ne dispose pas d'un monde déjà compilé il faudra le faire avant (voir le Handbook pour la compilation du monde : make buildworld).
Construction
La jail aura pour IP 192.168.2.1. Par convention, la racine d'une jail est souvent son adresse IP. La racine sera /jails/192.168.2.1
# mkdir /jails/192.168.2.1 # cd /usr/src # make installworld DESTDIR=/jails/192.168.2.1 # make distribution DESTDIR=/jails/192.168.2.1
L'arborescence créée :
# cd /jails/192.168.2.1 # ls .cshrc bin/ etc/ media/ rescue/ sys@ var/ .profile boot/ lib/ mnt/ root/ tmp/ COPYRIGHT dev/ libexec/ proc/ sbin/ usr/
On songe à garder une note dans la jail de la date de création et de la version du système utilisé pour la construire. C'est utile lors des mises à jours. Par convention perso :
# echo `date` `uname -a` > /jails/192.168.2.1/etc/VERSION
On fait une configuration grossière de la jail comme l'indique "man 8 jail":
# vi /jails/192.168.2.1/etc/rc.conf sendmail_enable="NONE" rpcbind_enable="NO" network_interfaces=""
un fstab vide :
# touch /jails/192.168.2.1/etc/fstab
fuseau horaire
# echo "Europe/Paris" > /jails/192.168.2.1/etc/timezone
crontab système, adjkerntz a enlever
# vi jails/192.168.2.1/etc/crontab
(optionnel) recopie des configs perso :
/etc/csh.cshrc /root/.cshrc /etc/make.conf /etc/login.conf ...
ATTENTION : LA CONFIGURATION N'EST PAS TERMINÉE !
Il faut aussi configurer les mots de passes utilisateurs (en particulier celui de root), les aliases mails et toutes ces sortes de choses. La méthode est la même que pour l'hôte principal et doit être effectuée avec le même soin. S'il y a plusieurs jails, modifier les heures des crons "periodic" peut aussi être utile (ils démarrent tous à 3h00 par défaut).
Exécution
Les scripts de démarrage "rc" permettent d'automatiser le lancement des jails, y compris le montage des systèmes de fichiers spéciaux comme devfs. Il suffit de le paramétrer dans /etc/rc.conf :
/etc/rc.conf
# alias IP sur xl1 pour la jail "test1"
ifconfig_xl1_alias0="inet 192.168.2.1 netmask 255.255.255.255"
##############################################################
### Jail Configuration #######################################
##############################################################
jail_enable="YES" # Set to NO to disable starting of any jails
jail_list="test1" # Space separated list of names of jails
jail_set_hostname_allow="NO" # Allow root user in a jail to change its
# hostname
jail_socket_unixiproute_only="YES" # Route only TCP/IP within a jail
jail_sysvipc_allow="NO" # Allow SystemV IPC use from within a jail
jail_stop_jailer="NO" # Only stop jailer. Requires jail_*_exec be
# set to use sysutils/jailer port to start
# the jail.
# To use rc's built-in jail infrastructure create entries for
# each jail, specified in jail_list, with the following variables.
# ----------------------------------------------------------------------
# test
jail_test1_rootdir="/jails/192.168.2.1" # Jail's root directory
jail_test1_hostname="roxette-21" # Jail's hostname
jail_test1_ip="192.168.2.1" # Jail's IP number
jail_test1_exec="/bin/sh /etc/rc" # commands to execute in jail
jail_test1_devfs_enable="YES" # mount devfs in the jail
jail_test1_fdescfs_enable="NO" # mount fdescfs in the jail
jail_test1_procfs_enable="NO" # mount procfs in jail
jail_test1_devfs_ruleset="devfsrules_jail" # devfs ruleset to apply to
# jail
Nous avons configuré une jail "test1", d'adresse IP 192.168.2.1, sur la racine qui nous avons précédement construite. Le paramètre devfs_ruleset="devfsrules_jail" est important : le devfs monté sur la jail ne contiendra que les fichiers spéciaux strictements indispensables. Autoriser des périphériques ici pourrait avoir de graves conséquences sur la sécurité de l'hôte.
La jail est lancée ou arrêtée par le script /etc/rc.d/jail
# /etc/rc.d/jail start test1
(si aucun nom de jail n'est spécifié, le script agit sur toutes les jails)
# jls
JID IP Address Hostname Path
3 192.168.2.1 roxette-21 /jails/192.168.2.1
# /etc/rc.d/jail stop test1
# jls
on la relance
# /etc/rc.d/jail start test1
# jls
JID IP Address Hostname Path
4 192.168.2.1 roxette-21 /usr/jails/192.168.2.1
Et on rentre dans la jail (id = 4)
# jexec 4 csh [ ici on est dans la prison ] Jetons un œil : # ls /dev fd ptyp0 ptyp3 ptyp6 ptyp9 ptypc stderr ttyp0 ttyp3 ttyp6 ttyp9 ttypc zero log ptyp1 ptyp4 ptyp7 ptypa ptypd stdin ttyp1 ttyp4 ttyp7 ttypa ttypd null ptyp2 ptyp5 ptyp8 ptypb random stdout ttyp2 ttyp5 ttyp8 ttypb urandom
Grâce au jeu de règles spécifié dans /etc/rc.conf ("devfsrules_jail)", il n'y a que le strict nécessaire. En particulier aucun périphérique matériel n'est accessible, kmem est absent, etc.
#Â mount /dev/ad0s3f on / (ufs, local, noatime, soft-updates)
Configurons rapidement un accès ssh pour se loguer à travers le réseau et non pas à partir de l'hôte principal.
# echo sshd_enable=\"YES\" >> /etc/rc.conf #Â /etc/rc.d/sshd start Generating public/private rsa1 key pair. Your identification has been saved in /etc/ssh/ssh_host_key. Your public key has been saved in /etc/ssh/ssh_host_key.pub. [...] Starting sshd.
Et voilà ! Il ne reste plus qu'à créer des comptes utilisateurs, permettre le login par ssh si vous souhaitez que l'on puisse se connecter dans la jail directement (avec jexec on peut rentrer dans une jail à partir de l'hôte). Vous pouvez installer des ports, exactement comme sur l'hôte principal.
Il est possible d'utiliser un autre moyen pour se loguer mais ssh est le plus sécurisé.
Mise Ă jour
Le monde utilisé par une jail doit être maintenu synchro par rapport au monde de l'hôte principal et du noyau.
La mise Ă jour s'effectue exactement comme la mise Ă jour de l'hĂ´te.
# cd /usr/src # mergemaster -p -D /jails/192.168.2.1 # make installworld DESTDIR=/jails/192.168.2.1 # mergemaster -D /jails/192.168.2.1
Il est conseillé d'arrêter la jail durant cette procédure. Il n'est pas possible d'effectuer la mise à jour depuis la jail, make installworld doit changer des ACL et cela n'est pas autorisé par défaut.
Ports
Là encore il faut voir la jail comme une machine virtuelle et la méthode ne diffère pas de la méthode habituelle : cvsup / portsnap de l'arbre des ports, make install, pkg_add, portupgrade, etc...
Certains logiciels peuvent ne pas fonctionner dans une jail, parce qu'ils nécessitent l'accès à un périphérique (ex: cdrecord) ou à une autre ressource inaccessible (raw socket par exemple). Dans ce cas il faut voir au cas par cas l'ajout des nœuds de périphériques dans le /dev de la jail ou s'il est possible de modifier les limitations imposées aux jails : il y a une option pour autoriser les raw sockets par exemple.
Dans tous les cas c'est à l'administrateur de l'hôte principal de décider.
Isoler un service
Dans de nombreux cas on voudra seulement isoler un service, ou créer un mini système pour des utilisations très spécifiques.
(Nous verrons le cas d'un accès SSH sécurisé et limité). L'usage de tels procédés à deux avantages :
- Le premier est d'isoler complètement le service de la machine hôte.
- Le second est de permettre une disponibilité réduite de commandes dans la Jail, et la suppression des commandes les plus sensibles sans limiter la maintenabilite de la structure de service en elle-même. On choisit les commandes que l'on veut.
Précautions
On aperçoit déjà la complexité de mise en oeuvre de telles structures.
D'une manière générale, plus le système à isoler a de dépendances quelconques vers différentes ressources, plus sa mise en jail devient difficile.
Il n'est pas possible de lancer des services qui accèdent à des fichiers sans quelques précautions. Il faut évidement que les fichiers soient dans l'arborescence chrooté. Sinon il ne sera pas possible d'y accéder, ils seront même entièrement invisibles dès le lancement de la Jail.
Méthode
D'une manière générale, on peut tracer un modèle structurel pour mettre en œuvre un service sous Jail. La partie suivante va décrire non pas les éléments à mettre en œuvre, car il est impossible d'en dresser une liste, et elle est même dépendante du service à enfermer. Mais va décrire les méthodes et outils pour la réalisation de l'édifice, car il s'agit bien ici d'une construction, on va installer le service morceau par morceau.
La méthode est basée sur une progression de proche en proche, de lien en lien, d'assemblage et de réassemblage empirique, régit par les règles de structures du système.
On voit se profiler la démarche à suivre, nous allons reconstruire l'arborescence de FreeBSD dans un espace disque que l'on va chrooter.
Dans la mesure du possible, il va falloir essayer de créer le service statiquement, ou rapatrier les bibliothèques et les poser dans le répertoire où le binaire les attend relativement au point de chroot.
Les outils
Les outils les plus utiles pour notre réalisation sont :
- which/whereis : qui sert Ă localiser un binaire dans le $PATH.
- locate : qui permet la recherche de fichier. (cette commandes implique une base locate a jour : voir Handbook sur locate.updatedb)
- ldd(1) : qui liste les dépendances d'un binaire exécutable.
- cp/mv/? : toutes les commandes de manipulation des fichiers.
- Utilisateurs#Cr.C3.A9ditschown/chmod : toutes les commandes de manipulation des droits et de possession de fichier.
- DESTDIR, que soit pour un port ou le monde
make install DESTDIR=/usr/home/jails/MonService
va tout installer à partir de «/usr/home/jails/MonService/»
Compilation des outils et des binaires du service ou nécessaire au service
Pour la création du service, si le port FreeBSD, n'existe pas, ou si pour une raison quelconque vous devez ou voulez compiler le programme vous-même, les méthodes à suivre seront souvent similaire.
Vous devrez configurer le Makefile, en changeant le préfix, (emplacement de dépôts de répertoires), préciser le linkage statique du binaire, et s'assurer du répertoire des fichiers de configuration. Toutes ses opérations se feront le plus souvent depuis le script Shell :
# ./configure
Grâce à des paramètres tel que :
- --prefix-cmd=
- pour préciser le chemin d'une commande utile
- --prefix-bin=
- pour préciser le chemin des binaires.
- --config-dir=
- pour le chemin des fichiers de configuration
- --static
- pour linker le binaire en statique.
Remarque : pour les répertoires, il faut bien penser que depuis la jail, la racine est le point de chroot, donc si la Jail est montée depuis /jails/192.168.2.1/ , le répertoire /jails/192.168.2.1/etc de l'hôte, correspond au répertoire /etc dans la Jail.
Politique sur la structure de l'arborescence d'une jail de service
Dans ce domaine, mes conseils n'ont pas valeurs de références mais de mises en garde.
Je ne peux que vous pousser à conserver la structure des répertoires d'une machine FreeBSD (voir man hier), ne cherchez pas la complication.
Je ne suis pas sûr que changer les emplacements des fichiers de configurations ou des binaires pour des raisons de sécurité soit nécessaire. L'aspect atypique d'une jail en terme de structure est déjà suffisant. Ne vous compliquez pas trop la tâche, à vous et aux personnes qui devront maintenir et faire évoluer le service, mais jouez plutôt avec les fichiers pour vous assurez qu'il n'y a pas de trou.
Le but de la Jail n'est pas de cacher les fichiers de configuration du service, mais de restreindre l'univers des possibilités d'attaques d'un système en le laissant seul visible, et d'autre part voir ne veux pas dire modifier.
N'oubliez pas du fait du mécanisme de Jail, les acquis UNIX, et adoptez des règles rigoureuses sur le positionnement des droits sur les fichiers.
En voulant tromper le pirate en changeant les chemins des fichiers vous gagnerez certes du temps sur une attaque, mais Ă quel prix, de plus vous ne ferez que gagner du temps, vous n'empĂŞcherez pas l'attaque.
Avec le temps vous verrez que ce type de décisions engendrera du temps supplémentaire à la conception, à la maintenance, de gros soucis de mise à jour par des personnes tierces, et en plus un gros travail de documentation.
Mode opératoire
- Etape 1 : repérer les binaires et les fichiers de configuration de votre service, et en faire une liste.
- (Toutes les manipulations de fichiers doivent évidement être faites sous l'utilisateur root)
- Etape 2 : trouver les chemins de chaque fichier ainsi que les dépendances de chaque binaires, les librairies objets partagées, etc...
- (N'oubliez pas des outils comme sed et awk tout au long de ce processus).
- Etape 3 : recréer dans la Jail, l'arborescence où vous devez poser vos fichiers, dans la majorité des cas faites des répertoires immuables.
- Etape 4 : compiler et copier les programmes de type 'source standard'.
- (ATTENTION : si vous compiler une version d'un service disponible sur l'hôte, mais spécifique à la Jail, prenez garde de bien sauvegarder les fichiers de configurations de votre hôte.)
- Etape 5 : contrôler les droits sur les fichiers de votre Jail, faites des tests via la commande Jail, sur chacun des binaires exécutables pour vous assurer qu'il ne lui manque aucun composant, vous ne devez pas vous soucier des appels systèmes, votre Jail a évidement droit d'accès aux routines du noyau.
- Etape 6 : créer les scripts d'initialisation de votre Jail, tant interne qu'externe, nous en verrons plusieurs types pour des cas différent, mais le modèle de ces scripts est celui de RC : - boite à état pour le lancement depuis l'extérieur - séquence Shell depuis l'intérieur de la Jail.
Quelques exemples
Cas simple le DNS
Dans le cas du DNS, c'est relativement simple, il suffit de faire une installation de BIND dans un répertoire du type /data/jails/dns/
(Comme vous l'avez constaté, dans le cas d'un service, on donne pour nom à la Jail, le nom du service).
On recherche toutes les dépendances de named et de ndc :
- named est le démon du DNS
- ndc est le loader.
De base, le script rc /etc/rc.d/named peut chrooter (mais pas jailer) BIND et monter un système devfs à la racine du chroot. On pourra s'inspirer de ce script.
Cas complexe l'accès SSH
Deux scripts en Ruby sont utilisés : le premier permet de créer la jail, le second la lance.
Attention : ces scripts ont été écrit pour FreeBSD 4. Il faudra les adapter pour FreeBSD >= 5.
#!/usr/local/bin/ruby require 'ipaddr' puts 'Jail Installation and server initialisation' puts '-------------------------------------------' puts '' # initialisation data_path = String::new('/var/data') data_symlink = String::new('/data') jail_path = String::new("#{data_symlink}/jail") rc = IO::readlines("/etc/rc.conf").delete_if{|line| line !~ /ifconfig/} rc.map!{|line| line = /^ifconfig_.*\d+="inet\s+(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\s+netmask\s+(\d{1,3}\.){3}\d{\ 1,3}".*$/.match(line)[1]} jail_ip = IPAddr.new "#{rc[0]}" host_ip = IPAddr.new "#{rc[1]}" jail_net = jail_ip.mask(24) host_net = host_ip.mask(24) table_exe = Array::new(['ls','cp','sh','pwd','vi','cat','mv','file','bash','clear','dig','echo','which','id','grep\ ','cut','awk','perl','find','file','tar','gzip','diff','patch','md5','xargs','uniq','sort','sed','more','chmod','w\ c','test','touch']) list_config_file = Array::new(['/etc/termcap','/usr/share/misc/termcap','/usr/share/misc/magic']) # methode recursive d'install des dependances et des outils def install_in_jail(binary,jail_path) IO.readlines("|ldd #{binary} 2>&1").map!{|dep| dep=dep.split(/ /)[2]}.compact.delete_if {|x| x =~ /not/ }.each{|\ file_dep| system("mkdir -p #{jail_path}#{File.dirname(file_dep)}") unless File::exist?("#{jail_path}#{File.dirname(file_\ dep)}") system("cp #{file_dep} #{jail_path}#{File.dirname(file_dep)}") unless File::exist?("#{jail_path}#{file_dep}") install_in_jail(file_dep,jail_path) } system("mkdir -p #{jail_path}#{File.dirname(binary)}") unless File::exist?("#{jail_path}#{File.dirname(binary)}"\ ) system("cp #{binary} #{jail_path}#{File.dirname(binary)}") if not File::exist?("#{jail_path}#{binary}") end # création de la jail def create_jail_skeleton(data_path,jail_path,data_symlink) puts "* Building filetree for the jail." system("mkdir #{data_path}") if not File::exist?(data_path) system("ln -s #{data_path} #{data_symlink}") if not File::exist?(data_symlink) system("mkdir #{jail_path}") if not File::exist?(jail_path) end # copie des executables en liste avec les dependance dans le points de chroot def install_executable(table_exe,jail_path) puts "* Installation of the jail's executables." table_exe.each{|exe| puts " => AJout de #{exe} et de ses dépendances ..." if File::exist?(`which #{exe}`.chomp) then install_in_jail(`which #{exe}`.chomp,jail_path) else puts 'ERROR : command not found' end } end def create_ld_tools(jail_path) puts '* Installation of the ld tools and configuration files' system("mkdir #{jail_path}/libexec && cp /libexec/* #{jail_path}/libexec/") unless File::exist?("#{jail_path}/l\ ibexec") system("mkdir -p #{jail_path}/var/run && cp /var/run/ld*.so.hints #{jail_path}/var/run/") unless File::exist?("\ #{jail_path}/var/ru\ n") end def put_config(list_config_file,jail_path) puts '* Installation of arbitrary configuration files.' list_config_file.each{|config_file| puts " => AJout du fichier de configuration : #{config_file}" system("mkdir -p #{jail_path}#{File.dirname(config_file)}") unless File::exist?("#{jail_path}#{File.dirname(c\ onfig_file)}") system("cp #{config_file} #{jail_path}#{File.dirname(config_file)}") unless File::exist?("#{jail_path}#{confi\ g_file}") } end def make_temporary_path(jail_path) puts '* Building temporary paths.' system("mkdir #{jail_path}/tmp; chmod 1777 #{jail_path}/tmp") unless File::exist?("#{jail_path}/tmp") system("mkdir #{jail_path}/var/tmp; chmod 1777 #{jail_path}/var/tmp") unless File::exist?("#{jail_path}/var/tmp"\ ) end def put_script(jail_path) puts '* Installing jail managing script' system("mkdir -p /usr/local/bin/") unless File::exist?("/usr/local/bin/") myscript = open("/usr/local/bin/manage_jail",'w+') DATA.each{|line| myscript.puts line } myscript.close system("chmod 700 /usr/local/bin/manage_jail") end # exemple pour l'install du port MySQL def install_mysql(jail_path) puts '* Installing the mysql command in jail.' puts ' => Installing port.' if `pkg_info|grep mysql-client`.empty? system("cd /usr/ports/databases/mysql-client/; make install clean") if `pkg_info|grep mysql-client`.empty? puts ' => Installing binaries.' install_in_jail(`which mysql`.chomp,jail_path) end def create_sshd_config(jail_path) puts ' => make sshd configuraiton file' myconf = open("#{jail_path}/etc/ssh/sshd_config",'w+') myconf.puts('Port 23') myconf.puts('Protocol 2') myconf.puts('ListenAddress 0.0.0.0') myconf.puts('HostKey /etc/ssh/ssh_host_key') myconf.puts('HostKey /etc/ssh/ssh_host_dsa_key') myconf.puts('SyslogFacility AUTH') myconf.puts('PermitRootLogin no') myconf.puts('StrictModes yes') myconf.puts('RSAAuthentication yes') myconf.puts('PubkeyAuthentication yes') myconf.puts('AuthorizedKeysFile .ssh/authorized_keys') myconf.puts('RhostsRSAAuthentication no') myconf.puts('HostbasedAuthentication no') myconf.puts('IgnoreUserKnownHosts no') myconf.puts('IgnoreRhosts yes') myconf.puts('PasswordAuthentication no') myconf.puts('PermitEmptyPasswords no') myconf.puts('ChallengeResponseAuthentication yes') myconf.puts('UsePAM yes') myconf.puts('GatewayPorts no') myconf.puts('AllowTcpForwarding no') myconf.puts('X11Forwarding no') myconf.puts('PrintMotd yes') myconf.puts('PrintLastLog yes') myconf.puts('TCPKeepAlive yes') myconf.puts('UseLogin no') myconf.puts('UsePrivilegeSeparation yes') myconf.puts('PermitUserEnvironment no') myconf.puts('Compression yes') myconf.puts('UseDNS yes') myconf.puts('#Banner /some/path') myconf.puts('Subsystem sftp /usr/libexec/sftp-server') myconf.puts('PidFile /var/run/sshd.pid') myconf.puts('MaxStartups 10')def install_sshd(jail_path) myconf.close end def install_sshd(jail_path) puts '* Installing the sshd daemon in jail.' puts ' => Installing binaries.' install_in_jail(`which sshd`.chomp,jail_path) puts ' => Installing configuration.' system("mkdir -p #{jail_path}/etc/ssh") unless File::exist?("#{jail_path}/etc/ssh") system("cp /etc/ssh/moduli #{jail_path}/etc/ssh") unless File::exist?("#{jail_path}/etc/ssh/moduli") system("/usr/bin/ssh-keygen -t rsa1 -b 1024 -f #{jail_path}/etc/ssh/ssh_host_key -N ''") unless File::exist?("#{\ jail_path}/etc/ssh/ssh_host_key") system("/usr/bin/ssh-keygen -t dsa -f #{jail_path}/etc/ssh/ssh_host_dsa_key -N ''") unless File::exist?("#{jail_\ path}/etc/ssh/ssh_host_dsa_key") system("/usr/bin/ssh-keygen -t rsa -f #{jail_path}/etc/ssh/ssh_host_rsa_key -N ''") unless File::exist?("#{jail_\ path}/etc/ssh/ssh_host_rsa_key") create_sshd_config(jail_path) unless File::exist?("#{jail_path}/etc/ssh/ssh/sshd_config") system("mkdir -p #{jail_path}/var/empty") unless File::exist?("#{jail_path}/var/empty") end def start_pseudo_fs(jail_path) puts '* Starting pseudo FS.' puts ' => proc in host.' unless File::exist?("/proc") system("mkdir /proc") unless File::exist?("/proc") system("echo 'proc /proc procfs rw 0 0' >> /etc/fstab") if `grep ' /proc' /etc/fstab`.empty? system("mount /proc") if `mount |grep '/proc '`.empty? puts ' => dev in host.' unless File::exist?("#{jail_path}/dev") system("mkdir #{jail_path}/dev") unless File::exist?("#{jail_path}/dev") system("echo 'dev #{jail_path}/dev devfs rw 0 0' >> /etc/fstab") if `grep #{jail_path}/dev /etc/fstab`.empty? system("mount #{jail_path}/dev") if `mount |grep '#{jail_path}/dev '`.empty? puts ' => proc in jail.' unless File::exist?("#{jail_path}/proc") system("mkdir #{jail_path}/proc") unless File::exist?("#{jail_path}/proc") system("echo 'proc #{jail_path}/proc procfs rw 0 0' >> /etc/fstab") if `grep #{jail_path}/proc /etc/fstab`.empty\ ? system("mount #{jail_path}/proc") if `mount |grep '#{jail_path}/proc '`.empty? end def install_pam(jail_path) puts '* Installing pam' puts ' => Puts libraries module PAM.' install_in_jail("/usr/lib/pam_unix.so",jail_path) puts ' => Puts configuration files.' system("mkdir -p #{jail_path}/etc/pam.d") unless File::exist?("#{jail_path}/etc/pam.d") if not File::exist?('#{jail_path}/etc/pam.d/sshd') then sshd_pam = open("#{jail_path}/etc/pam.d/sshd",'w') sshd_pam.puts('auth required pam_unix.so no_warn try_first_pass') sshd_pam.puts('account required pam_unix.so') sshd_pam.puts('session required pam_unix.so') sshd_pam.puts('password required pam_unix.so no_warn try_first_pass') sshd_pam.close end end def activate_syslog_in_jail(jail_path) puts '* Activate syslogd in jail.' puts ' => add in rc.' system("echo 'syslogd_enable=\"YES\"' >> /etc/rc.conf") if `grep 'syslogd_enable' /etc/rc.conf`.empty? system("echo 'syslogd_program=\"/usr/sbin/syslogd\"' >> /etc/rc.conf") if `grep 'syslogd_program' /etc/rc.conf`.\ empty? system("echo ' syslogd_flags=\"-s -p #{jail_path}/var/run/log\"' >> /etc/rc.conf") if `grep 'syslogd_flags' /etc\ /rc.conf`.empty? puts ' => reload syslogd' system("killall syslogd;syslogd -s -p #{jail_path}/var/run/log") end def tune_sysctl puts '* Tuning host Sysctl' sysctl_list = ['security.bsd.see_other_uids=0','net.inet.tcp.blackhole=1','net.inet.udp.blackhole=0','security.b\ sd.see_other_gids=0','security.jail.set_hostname_allowed=0','security.jail.allow_raw_sockets=1'] sysctl = open("/etc/sysctl.conf",'w') sysctl_list.each{|item| system("sysctl -b #{item}") sysctl.puts item } sysctl.close end def patch_sshd_config_host(host_ip) sshd_config = IO::readlines('/etc/ssh/sshd_config') sshd_config.map!{|line| if line =~ /^.*ListenAddress\s+(\d+\.){3}\d+.*$/ then line = "ListenAddress #{host_ip}" else line = line end } sshd_config.delete_if{|line| line =~ /^#/} sshd_config.delete_if{|line| line =~ /^\n/} dest = open('/etc/ssh/sshd_config','w') sshd_config.each{|line| dest.puts line } dest.close end def init_user_in_jail puts '* Initialising users on host and jail' system("/usr/local/bin/manage_jail cp") end def add_crontab_line puts '* adding task managing user in crontab' system("echo '0 0 * * * root /usr/local/bin/manage_jail convert >/dev/null 2>&1' >> /etc/crontab") if `grep '/us\ r/local/bin/manage_jail' /etc/crontab`.empty? end def put_freebsd_rc_loader puts '* Putting rc loader FreeBSD for the jail.' jail_rc = open("/usr/local/etc/rc.d/jail.sh",'w') jail_rc.puts('#!/bin/sh') jail_rc.puts('/usr/local/bin/manage_jail $1') jail_rc.close end # MAIN create_jail_skeleton(data_path,jail_path,data_symlink) install_executable(table_exe,jail_path) create_ld_tools(jail_path) put_config(list_config_file,jail_path) make_temporary_path(jail_path) put_script(jail_path) install_mysql(jail_path) install_sshd(jail_path) start_pseudo_fs(jail_path) install_pam(jail_path) activate_syslog_in_jail(jail_path) tune_sysctl patch_sshd_config_host(host_ip) init_user_in_jail add_crontab_line put_freebsd_rc_loader puts ' =*= jail OK' __END__
#!/usr/local/bin/ruby require 'ipaddr' param = ARGV[0] ID_LIMIT=500 data_root = "/data" data_jail = "#{data_root}/jail" rc = IO::readlines("/etc/rc.conf").delete_if{|line| line !~ /ifconfig/} rc.map!{|line| line = /^ifconfig_.*\d+="inet\s+(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\s+netmask\s+(\d{1,3}\.){3}\d{\ 1,3}".*$/.match(line)[1]} jail_ip = IPAddr.new "#{rc[0]}" host_ip = IPAddr.new "#{rc[1]}" jail_net = jail_ip.mask(24) host_net = host_ip.mask(24) case param when 'cp' then puts '* Adding in the jail path' system("cp /etc/master.passwd /etc/passwd /etc/spwd.db /etc/pwd.db #{data_jail}/etc") puts ' => Correction of the UNIX mode in jail' system("chmod 600 #{data_jail}/etc/master.passwd #{data_jail}/etc/spwd.db") puts ' =*= jail users OK' when 'start' if not File::exist?("#{data_jail}/var/run/sshd.pid") then puts '* Starting Jail' system("jail /data/jail omicron #{jail_ip} /usr/sbin/sshd") puts ' =*= Jail running OK' else puts ' =/= Jail already running NOK' end when 'stop' if File::exist?("#{data_jail}/var/run/sshd.pid") then puts '* Stopping Jail' pid = `cat #{data_jail}/var/run/sshd.pid`.chomp system("kill #{pid}") puts ' =*= Jail stopping OK' else puts ' =/= Jail not running NOK' end end
Options
Certaines caractéristiques des jails sont configurables par des sysctl à partir de l'hôte principal pour toutes les jails. Voir man jail.
security.jail.chflags_allowed : Permission de modifier les ACL par l'utilisateur root des jails. La permission dépend aussi du "niveau de sécurité" courant kern.securelevel
security.jail.allow_raw_sockets : Permission d'utiliser les raw sockets.
security.jail.enforce_statfs : Visibilité des points de montages. Dans l'exemple ci dessous, roxette est l'hôte et roxette-21 une jail.
# roxette:~# sysctl security.jail.enforce_statfs=0 security.jail.enforce_statfs: 1 -> 0 roxette-21:/# mount /dev/ad0s3a on / (ufs, local, noatime) devfs on /dev (devfs, local) /dev/ad0s3e on /tmp (ufs, local, noatime, soft-updates) /dev/ad0s3f on /usr (ufs, local, noatime, soft-updates) /dev/ad0s3d on /var (ufs, local, soft-updates) /dev/ad0s2 on /mnt/win (ntfs, local, noexec, nosuid, read-only) linprocfs on /usr/compat/linux/proc (linprocfs, local) devfs on /usr/jails/192.168.2.1/dev (devfs, local) # sysctl security.jail.enforce_statfs=1 security.jail.enforce_statfs: 0 -> 1 roxette-21:/# mount /dev/ad0s3f on / (ufs, local, noatime, soft-updates) devfs on /dev (devfs, local) # sysctl security.jail.enforce_statfs=2 security.jail.enforce_statfs: 1 -> 2 roxette-21:/# mount /dev/ad0s3f on / (ufs, local, noatime, soft-updates)
security.jail.sysvipc_allowed : Permission d'utiliser les IPC system V (inter processus communications).
security.jail.socket_unixiproute_only : Utilisation seule des domaines PF_LOCAL, PF_INET, PF_ROUTE à l'intérieur d'une jail.
security.jail.set_hostname_allowed : Permission de changer le nom d'hĂ´te.
Deux autres sysctl ont une valeur par jail, chaque jail peut posseder sa propre valeur : kern.securelevel et kern.hostname.
kern.securelevel : « Niveau de sécurité », le niveau de sécurité ne peut être qu'augmenté mais jamais diminué. Le niveau de sécurité limite certaines opérations. La page de man d'init fourni une description de ces niveaux, voir aussi security(7) et chflags(1).
L'aspect pratique concernant les jails est qu'il est possible d'utiliser un niveau plus élévé dans une jail que dans l'hôte : par exemple avec une jail tournant avec un securelevel >= 1 et un hôte tournant en <= 0, il sera possible de supprimer les ACL à partir de l'hôte tout en l'interdisant à partir de la jail. Notez que cela n'empêche pas d'ajouter des ACL.
Dans l'exemple ci dessous, roxette est l'hĂ´te et roxette-21 une jail.
roxette:~# sysctl security.jail.chflags_allowed=1 security.jail.chflags_allowed: 0 -> 1 roxette-21:/bin# sysctl kern.securelevel kern.securelevel: -1 /bin/rcp porte le flag schg, on peut le changer : roxette-21:/bin# ls -lo rcp -r-sr-xr-x 1 root wheel schg 18332 29 mar 21:57 rcp* roxette-21:/bin# chflags noschg rcp roxette-21:/bin# ls -lo rcp -r-sr-xr-x 1 root wheel - 18332 29 mar 21:57 rcp* roxette-21:/bin# sysctl kern.securelevel=2 kern.securelevel: -1 -> 2 roxette-21:/bin# chflags schg rcp roxette-21:/bin# ls -lo rcp -r-sr-xr-x 1 root wheel schg 18332 29 mar 21:57 rcp* roxette-21:/bin# chflags noschg rcp chflags: rcp: Operation not permitted
Ă€ partir du passage en securelevel=2 dans la jail, on a pu ajouter le flag schg Ă /bin/rcp mais on ne peut plus l'enlever.
Note : Avec security.jail.chflags_allowed=0, chflags est tout simplement interdit, il n'est pas possible de modifier les ACL quelque soit le securelevel en cours des jails.
Limites
Rien n'est parfait et les jails ont quelques limitations.
- Seul IPv4 est supporté, IPv6 est à l'étude ou à divers stades de développement (je crois).
- Il serait souhaitable de pouvoir limiter les IPC Ă une jail (avoir un security.jail.sysvipc_allowed par jail).
- Il n'est pas possible d'allouer des ressources UC par jail. Les processus sont schédulés normalement. Une jail qui exécute un programme de type "bombe fork" impactera l'ensemble. Il est toutefois possible de jouer sur les limites (voir limits(1)).
Astuces
Points de montages
PlutĂ´t que de recopier n fois les binaires ou l'arbre des ports, on peut utiliser des montages multiples en read-only. L'utilisation des montages unionfs est aussi possible mais unionfs est actuellement instable sous FreeBSD 6.
Le système de fichier nullfs permet de monter une arborescence existante sous une autre arborescence.
# mount_nullfs -o ro /usr/ports /jails/192.168.2.1/usr/ports # mount /usr/ports on /jails/192.168.2.1/usr/ports (nullfs, local, read-only) /etc/fstab peut-être utilisé pour monter le fs au démarrage : /usr/ports /jails/192.168.2.1/usr/ports nullfs ro 0 0
JAILER
sysutils/jailer est un utilitaire qui permet de lancer et d'arrêter une jail depuis celle-ci ou de l'extérieur. Il permet aussi d'éviter le problème de refcounting puisque la jail n'est pas terminée proprement dit, jailer arrête les processus de la jail mais reste actif.
Scripts
Il y a quelques utilitaires concernant les jails dans ports/sysutils.
J'utilise deux scripts pour l'installation et la mise à jour d'une jail que j'ai pompé chez http://www.the-labs.com et adapté à mon usage :
http://www.lamaiziere.net/private/jail_install
http://www.lamaiziere.net/private/jail_update
Conclusion
Les jails FreeBSD sont simples à mettre en œuvre, sans remise en question du schéma Unix traditionnel. Elles sont en outre proprement intégrées au système et disponibles "out of the box".
Elles apportent :
- Du buziness : certains hébergeurs proposent des serveurs semi-dédiés basés sur jail().
- De la sécurité : si un « méchant » parvient à compromettre un service jailé il aura du mal à aller plus loin. Mais ce n'est pas impossible, jail() a déjà eu des problèmes de sécurité (assez peu).
Comme chaque jail a son IP, il est facile de filtrer au niveau du parefeu.
On peut aussi faire des stats jails par jails, par exemple le trafic réseau par IP.
- De la facilité : qui a déjà eu à mettre à jour Perl (ou pire libtool ou gettext) sera bien content de pouvoir faire la mise à jour jail par jail, en n'interrompant que le strict minimum à chaque fois. Mieux il est facile de copier une jail, de la lancer et de faire des tests pour vérifier si cela fonctionne sans risquer de casser quelque chose.
- Du fun : Des tas de machines virtuelles à dispo pour des expérimentations de toutes sortes.
Les jails c'est bon, mangez-en.
Références
- Livre «The Design and Implementation of the FreeBSD Operating System.»
- http://docs.freebsd.org/44doc/papers/jail/jail.html (par les auteurs)
- http://www.the-labs.com/FreeBSD/JailTools/ (plutĂ´t pour FreeBSD 4, mais infos utiles)
- http://www.freebsddiary.org/jail-6.php
Évolutions
Ça bouge du coté des jails, des évolutions sont disponibles en 8-CURRENT et depuis peu en 7.1-STABLE : http://svn.freebsd.org/viewvc/base?view=revision&revision=185435
Y'a plein de bonnes choses !
- Plusieurs adresses IP pour une jail (voir mĂŞme aucune adresse IP)
- Support de IPv6
- Support de SCTP
- Possibilité d'affecter les processus d'une jail à des processeurs.
- Possibilité de faire tourner une jail 32 bits dans un hôte 64 bits.
