Catégorie : Administration système     Tags : , , ,      

    Ton phacochère [1] familier, bien que très sympathique, continue de faire quelques bêtises dans ta maison, bouffer les meubles, vider sa gamelle un peu partout, voire embêter tes autres colocataires.
    Ne voulant pas te résoudre à l’enfermer dans une niche (chroot) trop étroite, tu décides de lui construire un enclos qui lui sera dédié et dans lequel il pourra faire ce que bon lui semble sans nuire à son entourage (continue to be root).

    Pré-requis

    • un terrain propice (avoir un FreeBSD sous la main, être root dessus) ;
    • un peu d’espace disque, car on va dupliquer tout le userland dans l’enclos ;
    • avoir les sources dans /usr/src.

    Avant d'envisager la construction

    Avant de pouvoir configurer son enclos (jail), il faut déjà préparer le terrain tout autour (configurer le serveur qui va accueillir les jails pour que les daemons n’écoutent plus sur toutes les IP).
    Donc, tout autour de l’emplacement de son futur enclos, on fixe les branches qui dépassent, on ramasse les feuilles mortes, on passe un coup de râteau et on laisse un emplacement le plus nickel possible.

    • sshd
      Utilisez sshd_flags=”-oListenAddress=Public_IP” dans votre fichier /etc/rc.conf ou modifiez /etc/ssh/sshd_config (et redémarrez le daemon sshd par /etc/rc.d/sshd restart)
    • sendmail

    Ajoutez DAEMON_OPTIONS(`Addr=Public_IP’) à votre fichier de macro sendmail (fichier mc)

    • inetd

    Si vous utilisez inetd, il faut ajouter inetd_flags=”-a Public_IP” à votre /etc/rc.conf (attention à bien reprendre les flags existants).

    • named

    Utilisez la directive listen-on { Public_IP; }; dans votre fichier de configuration named.conf.

    • apache

    Utilisez la directive Listen Public_IP:80 dans votre /usr/local/etc/httpd.conf

    • etc.

    Idem pour les autres daemons écoutant sur toutes les IP.

    Un enclos en kit

    Tu as acheté ton enclos au même endroit que ton abri de jardin et, bien aimablement, le fabricant a fourni une aide minimale au montage des différents éléments ; pourtant, tout n’est pas aussi simple que chez Ikea. Tu n’auras pas de notice imprimée recto-verso t’expliquant ce qu’est une vis, mais cela ne signifie pas qu’il n’y a pas de documentation !
    Extrait de la page de man de jail [2]

    EXAMPLES
    Setting up a Jail Directory Tree
    To set up a jail directory tree containing an entire FreeBSD
    distribution, the following sh(1) command script can be used:
    D=/here/is/the/jail
    cd /usr/src
    mkdir -p $D
    make world DESTDIR=$D
    make distribution DESTDIR=$D
    mount_devfs devfs $D/dev

    Si tu as compilé ton système récemment, tu peux remplacer make world DESTDIR=$D par make installworld DESTDIR=$D ce qui te fera économiser tout le temps de la compilation.
    Une méthode plus Gruik consiste à monter une image ISO de FreeBSD et à extraire l’environnement de base comme s’il s’agissait d’une installation d’un système :

    # ggatel create 6.2-RELEASE-i386-disc1.iso
    ggate0
    # mount -t cd9660 /dev/ggate0 /mnt
    # cd /mnt/6.2-RELEASE/base
    # mkdir -p /home/jails/gcujail
    # cat base.?? | tar --unlink -vxpzf - -C /home/jails/gcujail

    On va créer manuellement le /dev/* du jail et y "entrer" :

    # mount_devfs devfs /home/jails/gcujail/dev
    # jail -l -U root /home/jails/gcujail gcujail 127.0.0.1 /bin/csh

    On regarde un peu dans quel environnement on se retrouve :

    gcujail# uname -a
    FreeBSD gcujail 7.0-CURRENT FreeBSD 7.0-CURRENT #33: Sat Mar 17 19:35:45 CET 2007 root@stealth.domain.tld:/usr/obj/usr/src/sys/STEALTH i386
    gcujail# ls -al
    -rw-r--r-- 2 root wheel 801 Jan 12 07:42 .cshrc
    -rw-r--r-- 2 root wheel 251 Jan 12 07:42 .profile
    -r--r--r-- 1 root wheel 6196 Jan 12 07:42 COPYRIGHT
    drwxr-xr-x 2 root wheel 1024 Jan 12 07:41 bin
    drwxr-xr-x 5 root wheel 512 Jan 12 07:42 boot
    [snip]
    gcujail# mount
    /dev/ad0s1f on / (ufs, local, soft-updates)

    On s’aperçoit que le système dans le jail hérite de la version du kernel du serveur hôte malgré le userland "décalé" et que la sortie de la commande mount ne montre que la partition accueillant le jail.
    De même, depuis le jail, la commande uptime montre le résultat du serveur hôte et pas du jail en lui-même.
    Pour vous en convaincre, créez le fichier /etc/rc.local contenant

    echo `date` >> /root/boot.log

    dans le jail ; amusez-vous à faire plusieurs reboot et regarder le fichier de log et l’uptime.
    Pour le moment, le user root du jail voit tout /dev à l’identique de ce qu’il se trouve sur le serveur hôte, ce qui peut être très dangereux si vous n’avez pas confiance dans le root du jail, car il a accès à tous les disques et partitions, à la configuration de vos règles de firewall...

    Et la barrière électrique ?

    Dans un jail correctement configuré comme plus loin dans l’article, le root du jail ne peut pas configurer son propre firewall et, par conséquent, il ne peut pas choisir et setter ses rules.

    # pfctl -s rules
    pfctl: /dev/pf: No such file or directory

    Toute la configuration firewall se fait "au-dessus" du jail, sur le serveur hôte.
    Configuration par défaut

    Le système FreeBSD comporte une configuration par défaut et des exemples pour configurer votre/(vos) jail(s).
    Ces informations se trouvent dans /etc/defaults/rc.conf qui est lu par les scripts de démarrage ; toutes les modifications doivent se faire dans /etc/rc.conf.
    Voici les paramètres communs à tous les jails :

    ##############################################################
    ### Jail Configuration #######################################
    ##############################################################
    jail_enable="NO" # Set to NO to disable starting of any jails
    jail_list="" # Space separated list of names of jails
    jail_set_hostname_allow="YES" # 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

    Et voici la liste des paramètres spécifiques à un jail qui peuvent être repris pour la configuration de vos jails :
    Voir Figure 1,

    Configurons notre enclos

    Voici ce que j’ai mis dans le /etc/rc.conf du serveur hôte ; l’utilisation de chaque variable sera détaillée plus loin.

    # jail
    jail_enable="YES"
    jail_list="gcujail"
    # Emplacement du jail et son hostname
    jail_gcujail_rootdir="/home/jails/gcujail"
    jail_gcujail_hostname="gcujail.gcu.info"
    # ip du jail et interface qui portera l'alias
    jail_gcujail_ip="192.168.0.10"
    jail_gcujail_interface="bge0"
    # on veut un /dev restreint dans le jail
    jail_gcujail_devfs_enable="YES"
    jail_gcujail_devfs_ruleset="devfsrules_jail"
    # l'option -J permettra d'avoir des informations sur le jail
    jail_gcujail_flags="-l -U root -s 1 -J /var/run/jail_gcujail.jid"

    Dans le rc.conf du jail, on lui indique de démarrer sshd comme d’habitude :

    sshd_enable="YES"
    sendmail_enable="NONE"

    Apparemment, il n’est plus indispensable de commenter adjkerntz -a dans /etc/crontab du système jailé.
    Démarrons ce jail et regardons ce qui est vu du serveur hôte.

    # /etc/rc.d/jail start gcujail
    Configuring jails:.
    Starting jails: gcujail.gcu.info.
    # ifconfig bge0
    bge0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
    options=98<VLAN_MTU,VLAN_HWTAGGING,VLAN_HWCSUM>
    [snip]
    inet 192.168.0.10 netmask 0xffffffff broadcast 192.168.0.10
    # mount
    [snip]
    devfs on /home/jails/gcujail/dev (devfs, local)

    Ce qu’il s’est produit :

    • l’alias IP 192.168.0.10 est automatiquement ajouté sur l’interface précisée par jail_gcujail_ip ;
    • devfs s’occupe de monter le /dev du jail au démarrage de celui-ci ;
    • les devices visibles dans le /dev du jail ont réduit comme peau de chagrin et ne permettent plus d’outrepasser les devices sur le serveur hôte (faites un ls pour vérifier).

    Voir Figure 2

    Vous aurez remarqué que le jail est démarré en securelevel [3] à 1 grâce à -s 1 de la variable jail_gcujail_flags.

    Les logs

    Activons les logs de la console dans le jail (fichier /home/jails/gcujail/etc/syslog.conf) :

    console.info;*.err;kern.warning;auth.notice /var/log/console.log

    Créons le fichier en question et redémarrons le jail :

    # touch /home/jails/gcujail/var/log/console.log
    # /etc/rc.d/jail restart

    Ce qui aura pour effet de créer un fichier /var/log/jail_gcujail_console.log sur le serveur hôte reprenant les logs de la console.

    Remplir l'enclos

    Afin d’économiser un peu d’espace disque, il vous semble évident que vous allez limiter au strict minimum les informations dupliquées sur le serveur hôte ainsi que dans votre (vos) jail(s).
    Typiquement, on partage /usr/src et /usr/ports :

    # mount -t nullfs -o ro /usr/src /home/jails/gcujail/usr/src
    # mount -t nullfs -o ro /usr/ports /home/jails/gcujail/usr/ports
    # mount | grep nullfs
    /usr/src on /home/jails/gcujail/usr/src (nullfs, local, read-only)
    /usr/ports on /home/jails/gcujail/usr/ports (nullfs, local, read-only)

    Il est possible d’ajouter ces points de montage dans le /etc/fstab du serveur hôte afin que le jail y ait accès de manière permanente, mais attention, ces répertoires peuvent être supprimés depuis le jail !
    Pour plus de sécurité, il est recommandé de monter /usr/src et /usr/ports/ en read-only dans le jail et de modifier la manière dont sont compilés les ports à partir du jail (pour pouvoir utiliser un /usr/ports en RO).
    Si vous devez gérer plusieurs enclos, il est préférable de mettre en place un export NFS en read-only de ces répertoires vers les jails, ce qui évitera les points de montage en nullfs :

    # mkdir -p /usr/obj/portsbuild /usr/obj/distfiles

    Et on édite le /etc/make.conf du jail pour y ajouter les lignes suivantes :

    WRKDIR=/usr/obj/portsbuild
    DISTDIR=/usr/obj/distfiles

    Il suffit d’ajouter les ports dans le jail comme d’habitude. Ceci aura pour inconvénient d’ignorer le contenu de /usr/ports/distfiles ; n’hésitez pas à en recopier les fichiers s’ils existent, ce qui évitera de perdre de la bande passante et du temps.
    Pensez à faire régulièrement le ménage dans /usr/obj/distfiles du jail sans quoi de l’espace disque sera perdu pour rien.

    Sécuri-clos

    Au cours de l’installation du jail, tu as constaté qu’il tenait sur une seule partition, ce qui est assez gênant quand tu veux avoir des points de montage avec des droits différents.
    Par exemple, j’ai pris pour habitude d’utiliser un /tmp de taille fixe, monté en RAM, avec des droits noexec et nosuid.
    Habituellement, je déclare dans /etc/rc.conf les lignes suivantes :

    tmpmfs="YES"
    tmpsize="512m"
    tmpmfs_flags="-S -o noexec,nosuid"

    qui ont pour résultat :

    # mount | grep tmp
    /dev/md0 on /tmp (ufs, local, noexec, nosuid)

    Mais cela ne fonctionne pas dans gcujail tout simplement parce que les commandes mdconfig n’ont pas accès aux devices /dev/md* depuis le jail !
    Les ajouter serait une fausse bonne idée, puisque cela donnerait accès aux devices md* appartenant au serveur hôte depuis l’intérieur du jail.
    Oh, tu peux essayer de bricoler le /etc/fstab du jail, si tu arrives à quelque chose de concluant tu es prié d’écrire à Pinpin (ou à l’auteur).
    La solution, peu gracieuse, trouvée pour l’instant, est la suivante :

    • sur le serveur hôte, on crée un fichier vide d’une taille fixe :
    # dd if=/dev/zero of=/home/jails/gcujail.tmp bs=1m count=512
    512+0 records in
    512+0 records out
    536870912 bytes transferred

    Edition du fichier /etc/fstab.gcujail (qui sera pris par défaut par le script jail) :
    Voir Figure 3

    et on ajoute la gestion du mount dans le fichier /etc/rc.conf du serveur hôte pour ce jail :

    jail_gcujail_mount_enable="YES"

    Par défaut, le fichier fstab du jail pris en compte par la variable jail_gcujail_fstab sera /etc/fstab.gcujail.
    On redémarre le jail :

    # /etc/rc.d/jail restart
    # mount | grep md
    /dev/md1 on /home/jails/gcujail/tmp (ufs, local, noexec, nosuid)

    Le /tmp de notre jail est bien d’une taille limitée et monté avec des droits moins permissifs.

    Note
    Un inconvénient de cette méthode est que bien qu’un /etc/rc.d/jail stop démonte le /tmp du jail, cela ne libère pas le device md qui y était associé et il faut le faire à la mimine depuis le serveur hôte !

    Quota-clos

    Jusqu’à présent, ton phacochère est tout seul dans son enclos. Il peut le décorer comme il lui plaît et ajouter ce dont il a besoin, mais, surtout, il peut continuer à prendre tout l’espace disponible dans son enclos.
    Il y a au moins deux solutions pour résoudre ce problème :

    • mettre les répertoires accueillant les jails dans des partitions physiques et donc de taille fixe ;
    • utiliser l’astuce d’un filesystem sur un fichier comme ce qu’on a fait avec /home/jails/gcujail.tmp, ce système de fichiers étant monté depuis le système hôte avant le démarrage du jail.

    Manager plusieurs enclos

    Divers programmes sont disponibles dans les ports afin de manager plusieurs jails plus facilement, liste évidemment non exhaustive :

    # make search name=jail | grep -E "^Port|^Path|^Info"
    Port: jailaudit-1.2
    Path: /usr/ports/security/jailaudit
    Info: Script to generate portaudit reports for jails
    Port: ezjail-2.0.1
    Path: /usr/ports/sysutils/ezjail
    Info: A framework to easily create, manipulate and run FreeBSD jails
    Port: jailadmin-1.8_2
    Path: /usr/ports/sysutils/jailadmin
    Info: A system for managing a set of named jails
    Port: jailctl-0.71
    Path: /usr/ports/sysutils/jailctl
    Info: Jail management tool
    Port: jailer-1.1.2
    Path: /usr/ports/sysutils/jailer
    Info: Manage FreeBSD jail startup, shutdown and console
    Port: jailuser-1.9_1
    Path: /usr/ports/sysutils/jailuser
    Info: Builds a chrooted environment
    Port: jailutils-1.0
    Path: /usr/ports/sysutils/jailutils
    Info: Several utilities for managing jails
    Port: p5-BSD-Jail-Object-0.02
    Path: /usr/ports/sysutils/p5-BSD-Jail-Object
    Info: An object oriented perl interface to jail(2)

    Pour une gestion plus facile des jails depuis le serveur hôte, je conseille l’installation des ports jailadmin et jailutils ; l’upgrade des enclos se fait de la même manière qu’un serveur FreeBSD (y compris pour le mergemaster) sauf qu’on change la variable $DESTDIR pour pointer dans le répertoire du jail à mettre à jour.

    Figure 1

    #
    # To use rc's built-in jail infrastructure create entries for
    # each jail, specified in jail_list, with the following variables.
    # NOTES:
    # - replace 'example' with the jail's name.
    # - except rootdir, hostname and ip, all of the following variables may be made
    #   global jail variables if you don't specify a jail name (ie. jail_interface).
    #
    #jail_example_rootdir="/usr/jail/default"       # Jail's root directory
    #jail_example_hostname="default.domain.com"     # Jail's hostname
    #jail_example_ip="192.168.0.10"                 # Jail's IP number
    #jail_example_interface=""                      # Interface to create the IP alias on
    #jail_example_exec_start="/bin/sh /etc/rc"              # command to execute in jail for starting
    
    #jail_example_exec_afterstart0="/bin/sh command"        # command to execute after the one for
                                                            # starting the jail. More than one can be
                                                            # specified using a trailing number
    #jail_example_exec_stop="/bin/sh /etc/rc.shutdown"      # command to execute in jail for stopping
    #jail_example_devfs_enable="NO"                 # mount devfs in the jail
    #jail_example_fdescfs_enable="NO"               # mount fdescfs in the jail
    #jail_example_procfs_enable="NO"                # mount procfs in jail
    #jail_example_mount_enable="NO"                 # mount/umount jail's fs
    #jail_example_devfs_ruleset="ruleset_name"      # devfs ruleset to apply to jail
    #jail_example_fstab=""                          # fstab(5) for mount/umount
    #jail_example_flags="-l -U root"                # flags for jail(8)

    Figure 2

    # jls
       JID  IP Address      Hostname                      Path
         6  192.168.0.10    gcujail.gcu.info              /home/jails/gcujail
    # ps auxwww | grep J
    root     2392  0.0  0.1  1376  1052  ??  SsJ   8:06PM   0:00.00 /usr/sbin/syslogd -s
    root     2448  0.0  0.3  3524  3084  ??  IsJ   8:06PM   0:00.00 /usr/sbin/sshd
    root     2455  0.0  0.1  1388  1064  ??  IsJ   8:06PM   0:00.00 /usr/sbin/cron -s

    Figure 3

    # Device Mountpoint FStype Options Dump Pass#
    md /home/jails/gcujail/tmp mfs rw,-S,noexec,nosuid,-F/home/jails/gcujail.tmp 2 0

    Conclusion

    Et voici un petit tour d’horizon sur les jails avec, je l’espère, une présentation qui sort un peu des howtos classiques qu’on trouve sur différents sites web.

    Références
    [1] http://fr.wikipedia.org/wiki/Phacochère
    [2] http://www.freebsd.org/cgi/man.cgi?query=jail&sektion=8
    [3]
    http://www.freebsd.org/cgi/man.cgi?query=securelevel&sektion=8

    Posté par SClo (sclo) | Signature : Stéphane Clodic « KingBug » | Article paru dans Creative Commons License

    Laissez une réponse

    Vous devez avoir ouvert une session pour écrire un commentaire.


    • Il y a actuellement

    • 666 articles/billets en ligne.