Archive for the 'FreeBSD' Category

Le jail express

Ou comment monter un jail en 2 – 2. On commence par topper une ISO de FreeBSD sur le host (système de base). Supposons que nous voulions installer un jail nommé “jigar” dans /jail/dtc. On va y mettre deux chose : le système de base FreeBi et les pages de man (une fois loggué dans le jail, c’est pratique de les avoir sous la main). Commencons par monter l’ISO :

mdconfig -a -t vnode -f ./FreeBSD-8.1-RELEASE-amd64-disc1.iso

Qui doit renvoyer un device (chez moi md0)

mount -t cd9660 /dev/md0 /mnt/iso

Mon shell root par défaut est sh (j’aime pô csh, je sais pas m’en servir ^^). On doit se placer dans le “set” a installer (base et manpages pour nous) :

cd /mnt/iso/8.1-RELEASE/base
DESTDIR=/jail/dtc ./install.sh

cd /mnt/iso/8.1-RELEASE/manpages
DESTDIR=/jail/dtc ./install.sh

Après c’est du classique, configurons le rc.conf du host :

#Alias avec l'ip du jail sur l'interface
ifconfig_igb0_alias0="inet <ip_host>"
syslogd_flags="-s -s"
sendmail_enable="NO"
inetd_flags="-wW -a <ip_host>"
rpcbind_enable="NO"
 
jail_enable="YES"
jail_list="jigar"
jail_set_hostname_allow="NO"
jail_socket_unixiproute_only="YES"
jail_procfs_enable="NO"
jail_devfs_enable="YES"
jail_exec_start="/bin/sh /etc/rc"
jail_devfs_ruleset="devfsrules_jail"
 
jail_nausica_flags="-n jigar"
jail_nausica_rootdir="/jail/dtc"
jail_nausica_hostname="jigar.garnett.fr"
jail_nausica_ip="ip_jigar"

Celui de “jigar” (/jail/dtc/etc/rc.conf) :

hostname="jigar.garnett.fr"
network_interfaces=""
keymap="fr.iso.acc"
sshd_enable="YES"
syslogd_flags="-s -s"
rpcbind_enable="NO"

Quelques post-actions :

touch /jail/dtc/etc/fstab
cp /etc/resolv.conf /jail/dtc/etc/
cp /jail/dtc/usr/share/zoneinfo/Europe/Paris /jail/dtc/etc/localtime
chroot /jail/nausica /bin/sh
#passwd
#exit

Et voila, c’est prêt !

UnixGarden : Jail et OpenVZ

Juste un post pour indiquer la mise en ligne ce jour d’un article soumis sous “creative commons” à Linux Magazine. Je trouve ce principe particulièrement intéressant de publier l’article sur le web librement accessible quelques mois après sa parution. Il est disponible ici.

Upgrade vers FreeBSD 8.0

Voila un petit mois que je n’ai rien posté sur ce blog. J’avais un peu la tête sous l’eau. J’ai donc passé mes serveurs FreeBSD hébergeant des jail en 8.0. Seulement, je me suis loupé dans la procédure d’upgrade. J’ai upgradé un jail en 8.0 puis en rappelant la commande freebsd-update j’ai omis le -b pour lui donner comme racine un jail donc il a mis à jour le système de base. Je n’ai pas voulu interrompre la procédure donc je l’ai laissé finir.

Le problème lorsque l’on utilise freebsd-update pour mettre à jour ses jails c’est qu’il se base sur la version renvoyée par uname. Si l’on met à jour le système de base avant les jails, alors freebsd-update lancé sur le jail considère que le système est déjà à jour. Pour s’en sortir, deux options :

1) Création d’un faux uname

On move /usr/bin/uname vers /usr/bin/uname.org et on se fait un petit script du style :

#!/bin/sh
/usr/bin/uname.org $* | sed s/"8.0-RELEASE"/"7.2-RELEASE-p4"/g

Ok c’est encore plus crade que du porno thaïlandais …

2) Copie d’un jail “master”

Directement inspiré d’un post trouvé ici. Cette méthode propose de disposer d’un master jail à répliquer. J’étais un peu dans cette configuration avec comme “master jail” celui que j’avais upgradé avant ma boulette. Les installations des différents jails étant assez homogènes (ferme de serveur FreeBSD / Apache / Trac / SVN) il me suffisait de répliquer ce jail et de recoller les data de /usr/local/[svn|www]-trac qui contiennent respectivement les instances subversion et Trac associées. Pour copier un jail, ne surtout pas faire un bête cp mais plutôt :

# cd /jail/masterjail
# tar -cpf - . | tar -C /jail/newjail -xpf –

Pour conserver les permissions, la nature du fichier (surtout les liens) etc. Quand on combine tar et ssh on obtient même un “master jail” deployable de façon sécurisée sur tous les serveurs partageant son architecture (uname -m). A noter que cette manipulation a quand même nécessité la recompilation du port www/apache22 sur le newjail.

Hé toi ! Oui toi la bas …

Sous FreeBSD, je cherchais comment utiliser le nom du jail à la place du JID dans la commande jexec. A priori d’après le man c’est possible :

     -n jailname
             The name of the jail, if given upon creation of the jail.  This
             is not the hostname of the jail.

Bingo, j’essaye :

jexec -n monjail '' ls

Ca pète le message d’erreur suivant :

jexec: Cannot identify jail.

je vérifie vingt fois le nom de mon jail et retente çamarchepas. Je décide donc de mater dans le man de jail (RTFM rulez) et je trouve ça :

     -n jailname  Assign and administrative name to the jail that can be used
                  for management or auditing purposes.  The system will not
                  enforce the name to be unique.

Une fois la ligne jail_monjail_flags=”-n monjail” ajoutée dans le rc.conf et le service jail relancé çamarchemieux.

Authentification Dovecot sous Postfix

Suite de l’histoire de Dovecot. Je reçois mes mails sur ma kimsufi. Je suis un homme un peu plus heureux. Le bonheur serait un peu plus complet si je pouvais émettre des mails de n’importe où grâce à un relai authentifié et chiffré. J’ai trouvé un début de solution sur le wiki de Dovecot mais il a fallu quand même d’autres étapes pour que ça marche. Tout d’abord, installation de Postfix (toujours sous FreeBi) avec les options de compilation suivantes :

# This file is auto-generated by 'make config'.
# No user-servicable parts inside!
# Options for postfix-2.6.3,1
_OPTIONS_READ=postfix-2.6.3,1
WITH_PCRE=true
WITH_SASL2=true
WITH_DOVECOT=true
WITHOUT_SASLKRB=true
WITHOUT_SASLKRB5=true
WITHOUT_SASLKMIT=true
WITH_TLS=true
WITHOUT_BDB=true
WITHOUT_MYSQL=true
WITHOUT_PGSQL=true
WITHOUT_OPENLDAP=true
WITHOUT_CDB=true
WITHOUT_NIS=true
WITHOUT_VDA=true
WITHOUT_TEST=true

Une fois cette installation effectuée, un petit coup de postfix_enable=”YES” dans le rc.conf et ça démarre. Attention quand même, il faut bien penser à désactiver Sendmail :

sendmail_enable="NO"
sendmail_submit_enable="NO"
sendmail_outbound_enable="NO"
sendmail_msp_queue_enable="NO"
 
postfix_enable="YES"

Je souhaite une configuration en “full” SSL (c’est à dire pas de START_TLS) sur le port 445 avec authentification. Pour avoir une instance chiffrée de Postfix sur le port 445, il faut ajouter ce service dans le main.cf.

smtps     inet  n       -       n       -       -       smtpd
  -o smtpd_tls_wrappermode=yes
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_client_restrictions=permit_sasl_authenticated,
                           permit_my_networks,
                           reject_unauth_destination

Le paramètres “smtpd_tls_wrappermode=yes” lie l’instance de smtpd invoquée au port 445 et surtout active le SSL (en mode enforcé). Si on veut forcer à tout prix le chiffrement SSL même sur le port 25 (par exemple depuis un réseau interne), il faut regarder du côté de la variable “smtpd_tls_security_level” qui propose trois niveaux : none (pas de chiffrement), may (si le client veut, on chiffre) et encrypt (quoiqu’il arrive, on chiffre). Le paramètre “smtpd_sasl_auth_enable=yes” active une authentification via la SASL (par défaut Postfix ne le fait pas). Cette primitive permet surtout de profiter de la cible “permit_sasl_authenticated” pour relayer les clients dument authentifiés. Au niveau de la configuration de Postfix, tout le reste se passe dans le main.cf. Il faut commencer par lui indiquer où trouver les certificats :

smtpd_tls_key_file = /usr/local/etc/ssl/smtps/server.key
smtpd_tls_cert_file = /usr/local/etc/ssl/smtps/server.crt

Ensuite on lui fixe quelques variables nécessaires au bon fonctionnement du service de messagerie :

mynetworks_style = host
myhostname = silky.garnett.fr
mydomain = garnett.fr 
mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain
unknown_local_recipient_reject_code = 550
mynetworks_style = host
mynetworks = 127.0.0.0/8
relayhost = [fqdn.demon.relai]

On notera juste que je fais relayer mon courrier par la machine fqdn.demon.relai, mon MTA n’est donc pas en frontal du net pour l’envoi de messages SMTP. Je ne connaissais pas non plus le “mynetworks_style = host” qui est bien pratique pour du vite fait bien fait. On doit ensuite activer la SASL de Dovecot :

smtpd_sasl_type = dovecot
smtpd_sasl_path = /var/spool/postfix/private/auth
smtpd_sasl_auth_enable = yes
smtpd_sasl_local_domain = $myhostname
smtpd_sasl_security_options = noanonymous
broken_sasl_auth_clients = yes
smtpd_recipient_restrictions = permit_sasl_authenticated,
                             permit_mynetworks,
                             reject_unauth_destination

Le paramètre “smtpd_sasl_type” donne le nom de la couche SASL à utiliser (ici dovecot, évidemment ;-) ). Le “smtpd_sasl_path” donne le chemin du fichier qui va permettre à Dovecot et Postfix de parler ensemble. Ce fichier doit absolument n’être utilisable que par l’utilisateur système postfix :

srw-rw----  1 postfix  postfix  0 Sep  2 08:19 /var/spool/postfix/private/auth

Pour éviter les connexions anonymes, il faut positionner “smtpd_sasl_security_options = noanonymous”. Enfin “broken_sasl_auth_clients = yes” permet de supporter les MUA de merde comme Outlook. Côté Postfix, on est paré ! Passons à Dovecot.

Pour Dovecot, la seule chose à faire est de préparer le socket de discussion entre Dovecot et Postfix (pour l’authentification). Dans le dovecot.conf :

socket listen {
    master {
      path = /var/run/dovecot/auth-master
      mode = 0600
    }
    client {
      path = /var/spool/postfix/private/auth
      mode = 0660
      user = postfix
      group = postfix
    }
}

Redémarrage de Dovecot et Postfix et il n y a plus qu’a dérouler ! Pour debugguer, un petit telnet en local sur le port 25 de votre machine devrait vous renvoyer les informations suivante (après avoir été poli et fait le ehlo) :

Trying 192.168.0.1...
Connected to silky.
Escape character is '^]'.
220 silky.garnett.fr ESMTP Postfix
ehlo silky.garnett.fr
250-silky.garnett.fr
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-STARTTLS
250-AUTH CRAM-MD5
250-AUTH=CRAM-MD5
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN

Voila, on notera que Postfix supporte bien évidemment la SASL standard et que donc toutes les fantaisies sont permises (par exemple avec Kerberos … en SSO … MMmmm … mon caleçon en est tout taché !). Bon courage and may the force be with you :-) !

Sécurité de Dovecot

Dans un cadre professionnel, j’ai du examiner les principaux mécanismes de sécurité de Dovecot. Dovecot est à la base un serveur IMAP (même si il propose un module POP3). Les variantes sécurisées IMAPS et POPS sont évidemment supportées. Elles intègrent le support de SSL pour authentifier le serveur auprès des clients et chiffrer la connexion. En effet, les protocoles de messagerie ont tendance à se reposer sur des authentification en clair. Commençons par installer Dovecot. J’ai décidé de faire ma configuration sur FreeBSD. L’installation est faite via les ports. Mes options de compilation sont les suivantes :

# This file is auto-generated by 'make config'.
# No user-servicable parts inside!
# Options for dovecot-1.2.3
_OPTIONS_READ=dovecot-1.2.3
WITH_KQUEUE=true
WITH_SSL=true
WITHOUT_IPV6=true
WITHOUT_POP3=true
WITH_LDA=true
WITHOUT_MANAGESIEVE=true
WITHOUT_GSSAPI=true
WITHOUT_VPOPMAIL=true
WITHOUT_BDB=true
WITHOUT_LDAP=true
WITHOUT_PGSQL=true
WITHOUT_MYSQL=true
WITHOUT_SQLITE=true

Comme d’habitude, il convient d’ajouter dovecot_enable=”YES” dans le rc.conf. L’essentiel de la configuration se fait dans le fichier dovecot.conf. Pour activer IMAPS :

protocols = imaps

Notre configuration va prendre un certificat autosigné côté serveur.

openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -out ./server.crt -keyout ./server.key

Cette commande génère une clé RSA de 2048 bits “server.key” et le certificat autosigné associé “server.crt”. Pour les déclarer dans Dovecot, il faut utiliser les primitives suivantes :

ssl_cert_file = /usr/local/etc/ssl/dovecot/server.crt
ssl_key_file = /usr/local/etc/ssl/dovecot/server.key

J’ai pour habitude des les placer dans /usr/local/etc/ssl/dovecot. Au niveau ACL du système de fichier, je retire les droits d’écriture sur la clé et le certificat pour tout le monde (user, group et other). Pour la clé, seul le propriétaire a le droit de lecture :

total 8
drwxr-xr-x  2 root  wheel   512 Aug 30 16:08 .
drwxr-xr-x  4 root  wheel   512 Aug 30 16:08 ..
-r--r--r--  1 root  wheel  1627 Aug 30 16:08 server.crt
-r--------  1 root  wheel  1675 Aug 30 16:08 server.key

Un aspect intéressant de Dovecot est qu’il utilise intensivement les principes de séparation et du moindre privilège. La séparation de privilèges implique un éclatement des processus pour idéalement tendre vers l’état suivant : 1 action = 1 processus système. Le moindre privilège implique que les droits du compte associé à chaque processus sont limités au strict minimum. En effet, une fois Dovecot démarré (et configuré) un seul processus tourne sous “root” :

root        61934  0.0  0.1  5652  1348  ??  SsJ  10:15PM   0:00.05 dovecot

Ce processus maitre sert uniquement à gérer les sockets réseaux liées à des ports priviligiés (ici imaps sur le 993) et à lancer le processus gérant l’authentification “dovecot-auth” ainsi que celui gérant le service IMAP jusqu’à ce que l’utilisateur s’authentifie “imap-login”. Le processus “imap-login” doit tourner sous un compte non privilégié (ici dovecot).

login_user = dovecot

Pour le processus “dovecot-auth” c’est moins clair. Dans notre configuration (détaillée par la suite) il n’est pas nécessaire d’utiliser le compte root. Un compte authdovecot a donc été crée.

authdovecot 62210  0.0  0.2  7828  1516  ??  SJ   10:48PM   0:00.01 dovecot-auth
authdovecot 62211  0.0  0.1  7828  1432  ??  SJ   10:48PM   0:00.00 dovecot-auth -w
dovecot     62212  0.0  0.3  9600  2584  ??  SJ   10:48PM   0:00.01 imap-login
dovecot     62213  0.0  0.3  9600  2584  ??  SJ   10:48PM   0:00.01 imap-login
dovecot     62214  0.0  0.3  9600  2584  ??  SJ   10:48PM   0:00.01 imap-login

Enfin le processus “imap” va gérer la session IMAP après connexion de l’utilisateur. Ce processus peut tourner sous deux identités :

  • Avec le compte système de l’utilisateur si celui-ci existe (notre cas).
  • Avec un compte générique pour toutes les boites (le plus souvent nommé vmail) dans le cas de destinataires virtuels. Ces destinataires n’ont pas d’existence au sens système du terme c’est à dire pas d’UID (on peut vivre sans UID ?).

Dans notre configuration, un utilisateur “nico” dédié au mail existe et son compte est bloqué. De cette manière, l’utilisateur dispose d’un UID et dovecot peut invoquer “imap” sous cette identité:

nico        69094  0.0  0.2  7708  2080  ??  SJ    7:20AM   0:00.01 imap [nico 193.XXX.XXX.XXX]

Pour dovecot, deux éléments composent un utilisateur : ses informations (login, uid etc.) et sa méthode d’authentification. Cette configuration se fait dans la section “auth default” du fichier dovecot.conf :

auth default {
  mechanisms = cram-md5 
  passdb passwd-file {
    args = /usr/local/etc/cram-md5.pwd
  }
  userdb passwd {
    args = blocking=yes
  }
  user = authdovecot
}

Le paramètre userdb donne la base des données des utilisateurs à utiliser. Par défaut Dovecot prend les comptes systèmes locaux (du moins ceux présentés par le service NSS où équivalent). Par exemple : si on a un annuaire LDAP avec des utilisateurs au format PosixAccount, on peut toujours utiliser la userdb par défaut (si NSS est bien configuré pour, of course !). La passdb contient les mots de passes chiffrés pour les utilisateurs. Par défaut, dovecot repose sur la PAM. Cette méthode possède un défaut majeur : le mot de passe circule en clair. Même avec le support de SSL, un man in the middle sauvage peut survenir (surtout sur un réseau local). La seule trace pour l’utilisateur sera la présentation d’un certificat invalide qu’il s’empressera d’accepter. Pour mitiger ce risque, il suffit de changer le mécanisme d’authentification (ici CRAM-MD5) :

mechanisms = cram-md5

Une fois cette modification effectuée, il faut se définir un fichier de mot de passe personnalisé. Dans notre exemple /usr/local/etc/cram-md5.pwd :

passdb passwd-file {
    args = /usr/local/etc/cram-md5.pwd
}

Les entrées de ce fichier sont au format ‘user:{algorithme}secret’. User correspond au nom d’utilisateur, algorithme renseigne sur la fonction de chiffrement appliquée et secret représente le mot de passe chiffré.

nico:{CRAM-MD5}**********

Cette configuration permet de limiter les droits de l’identité sous laquelle le processus “dovecot-auth” s’exécute. Deux point sont à prendre en compte : l’accès aux information utilisateur et l’authentification. Par défaut les utilisateurs ont le droit de récupérer la liste des comptes utilisateurs d’une machine (commande ‘getent passwd’). Coté authentification, La seule contrainte est que le compte système utilisé pour le processus ait accès en lecture sur le fichier pour faire les lookups.

-r--r-----   1 authdovecot  dovecot     80 Aug 31 19:45 cram-md5.pwd

Voila c’est fini ! Dans le prochain post, nous verrons comment s’appuyer sur l’authentification CRAM-MD5 de dovecot pour réaliser un service SMTP émetteur authentifié avec postfix.

Mise à jour d’un Jail FreeBSD au changement de version

Ajourd’hui passage des jails de 7.1 en 7.2. Je pensais pouvoir faire une mise à jour binaire par freebsd-update (ce que je fais d’habitude). Seulement pour le changement de version : samarchepa, freebsd-update ne met rien à jour dans les Jails. Du moins je ne connais pas de moyens d’y arriver. Du coup, j’ai opté pour la mise à jour recompilation.

Sur le système hôte :

# cd /usr/src
# make buildworld DESTDIR=/monjail
# mergemaster -p -D /monjail

Petite note sur mergemaster : la partie récente est a droite (r) tandis que la partie gauche c’est l’existant (l). Cette première commande initialise le /var/db/mergemaster.mtree du jail avec les fichiers “importants” (-p). Ce fichier va être utilisé par la suite pour installer automatiquement les fichiers de configuration du système de base qui n’ont pas étés modifiés par l’administrateur.

Si on le fait pas, mergemaster renvoi le message suivant au moment de l’auto-update :

Unable to find mtree database. Skipping auto-upgrade.

Ensuite on arrête le jail, on installe les mises à jour (programmes et fichiers de configuration) et enfin on redémarre :

# /etc/rc.d/jail stop monjail
# make installworld DESTDIR=/monjail
# mergemaster -i -U -D /monjail
# /etc/rc.d/jail start monjail

A executer dans le jail (soit par SSH, soit par jexec) :

# /usr/sbin/pwd_mkdb -d /etc -p /etc/master.passwd
# /usr/bin/cap_mkdb /etc/login.conf

Il n y a plus qu’à vérifier que tout est reparti.

Installation / Mutualisation de Trac (sous FreeBSD)

Un petit post pour donner un retour sur l’installation et administration de Trac. Ce projet propose d’habiller un dépôt subversion avec un wiki, une gestion de tickets etc. Le tout est réalisé en python (chouette une application web sans PHP). Dans un cadre professionnel, j’ai du mettre en œuvre une solution de gestion de versions pour différents projets. J’ai retenu subversion, trac et apache sous FreeBSD comme briques de cette infrastructure. J’ai choisi FreeBSD car les ports sont très proches des versions courantes des logiciels (et pour des application web c’est important) et surtout Jail est intégré au système de base (stabilité des mises à jour). Au niveau de l’existant, je disposais d’un serveur OpenLDAP (avec les comptes utilisateurs dedans). j’ai décidé de faire mon Jean-Pierre Troll et de n’utiliser aucun des systèmes “hype” de virtualisation (non pas que je les aimes pas, c’est juste que c’était un peu overkill par rapport à mes besoins). La manière de mutualiser le système a directement été dictée par la façon dont sont structurés les systèmes d’informations dans les universités. Petit rappel : chaque université dispose d’un CRI (Centre de Ressources Informatique) qui s’occupe des services mutualisés (mail, web, annuaire et dans notre cas subversion / trac). Ces services sont utilisés par différentes composantes. J’ai donc décidé de dédié un environnement confiné à chaque composante. Un environnement confiné est un Jail FreeBSD. C’est presque comme une machine virtuelle à part qu’on a une seule instance du noyau en exécution (raccourci très très grossier, que les gurus me pardonnent). Il en résulte un confinement un peu plus poreux qu’avec des systèmes comme XEN (para-virtualisation) ou VMWare (virtualisation complète). la mise en œuvre basique d’un Jail FreeBSD est détaillée ici. Je considère donc que vous avez un FreeBSD rutilant, un serveur OpenLDAP qui fonctionne et un Jail dans lequel déployer les instances de Subversion / Trac. Pour toutes les manipulation l’identifiant choisi est le mail et pas le login UNIX (le mail est bien pus générique). Let’s go !

Round 1 : Apache

Apache est LE composant principal de l’installation. C’est lui qui va servir de base pour l’authentification des utilisateurs sur Trac et Subversion. Apache va aussi réaliser l’affichage du site Trac via le mod_python. Nous allons utiliser le module LDAP fourni avec Apache pour l’authentification. un coup de portinstall :

portinstall www/apache22

Ne pas oublier d’activer LDAP dans apr* et l’authentification LDAP dans apache.

portinstall www/mod_python3
portinstall trac
portinstall mod_security

Le mod_security est facultatif. Nous avons vu qu’un Jail était dédié à une composante. Or une composante peut avoir plusieurs activités (recherche, enseignements, valorisation etc.). L’incidence au niveau informatique est que l’on peut avoir des URL différentes pour ces activités. Nous allons donc utiliser les virtualhost Apache. Considérons le virtualhost trac01.garnett.fr (ça change de je te foo sur le bar). Pour l’authentification LDAP, un précédent post donne la démarche. Une fois cette étape validée, on peut passer à la suite. J’exclu volontairement la partie SSL entre le virtualhost et le serveur LDAP pour plus de lisibilité.

Round 2 : Subversion

Toutes les interactions avec le serveur Subversion se feront sur HTTPS. L’accès en HTTPS à un serveur Apache est largement documenté sur Internet. Nous avons donc la configuration suivante :

<Virtualhost *:443> 
        <Location /svn> 
        DAV svn 
        SVNParentPath /usr/local/svn-trac/svn_of_trac01
        AuthzSVNAccessFile /usr/local/svn-trac/acls/acl-repo 
        AuthType Basic 
        AuthName "SVN"
        AuthBasicProvider "ldap" 
        AuthLDAPURL "ldap://mon_ldap/dc=example,dc=org?mail?sub?(objectClass=inetOrgPerson)" 
        authzldapauthoritative Off 
        require valid-user 
        </Location> 
</Virtualhost>

Cette section active DAV (DAV svn) pour la location /svn. Elle donne aussi le répertoire parent des dépôts subversions (SVNParentPath /usr/local/svn-trac/svn_of_trac01). Ce répertoire doit être readable par Apache. Les sous répertoires qui constituent donc les projets doivent donc être readable et writable par Apache. Il reste un détail : les ACLs sur les différents projets (AuthzSVNAccessFile /usr/local/svn-trac/acls/acl-repo). Ce fichier va contenir les différents droits sur les dêpots. Voyons un exemple :

[repo01:/] 
nico@bidule.fr = rw 
toto@bidule.fr = r
tutu@machin.fr = r

Nico à tous les droits tandis que toto et tutu ont juste la lecture sur la racine du projet repo01 situé dans /usr/local/svn-trac/svn_of_trac01. J’ai décidé de restreindre l’accès a ce fichier en chrootant un utilisateur dédié dans le répertoire /usr/local/svn-trac/acls. Très simple, il faut ajouter dans /etc/ssh/sshd_config :

[...]
AllowUsers  mon_user
[...] 
Subsystem	sftp	internal-sftp
[...]
Match User mon_user
	ForceCommand internal-sftp
	ChrootDirectory /usr/local/svn-trac/acls

Attention aux espaces dans le fichier de configuration, notamment sur le “ForceCommand internal-sftp”. Le moindre espace terminal fait merder le tout. Pour le chroot, tout les répertoires de niveau supérieurs doivent appartenir à root. Cette manipulation permet à un informaticien de composante de mettre à jour ses ACLs de manière autonome sans compromettre l’intégrité du serveur (Jail + chroot SFTP).

Pour tester le dêpot depuis une machine lambda :

# svn co https://trac01.garnett.fr/svn/repo01 --username nico@garnett.fr

Round 3 : Trac

La partie la plus simple. J’ai repris la documentation du site officiel sur l’installation avec le mod_python. La seule différence est que je force l’utilisateur à s’authentifier sur HTTPS et l’incite à rester sur un canal chiffré après authentification. Je donne ma configuration en commentant ce qui diffère par rapport à la documentation originale :

<VirtualHost *:80> 
        ServerName trac01.garnett.fr
        DocumentRoot /usr/local/www-trac/trac01 
        ErrorLog /var/log/httpd-error-www-trac01.log 
        CustomLog /var/log/httpd-access-www-trac01.log combined 
        Options none 
 
        RedirectMatch /([^/]+)/login https://trac01.garnett.fr/$1/login 
 
        <Location /> 
        SetHandler mod_python 
        SetEnv PYTHON_EGG_CACHE "/usr/local/www-cache/eggs" 
        PythonInterpreter main_interpreter 
        PythonHandler trac.web.modpython_frontend 
        PythonOption TracEnvParentDir /usr/local/www-trac/trac01 
        PythonOption TracUriRoot / 
        </Location> 
</VirtualHost> 
 
<Virtualhost *:443> 
        ServerName trac01.garnett.fr 
        DocumentRoot /usr/local/www-trac/trac01 
        ErrorLog /var/log/httpd-error-www-tractrac01-ssl.log 
        CustomLog /var/log/httpd-access-www-tractrac01-ssl.log combined 
        Options none 
 
        SSLEngine On 
 
        SSLCertificateFile /usr/local/etc/apache22/ssl/trac01/server.crt 
        SSLCertificateKeyFile /usr/local/etc/apache22/ssl/trac01/server.key 
 
        <Location /> 
        SetHandler mod_python 
        SetEnv PYTHON_EGG_CACHE "/usr/local/www-cache/eggs" 
        PythonInterpreter main_interpreter 
        PythonHandler trac.web.modpython_frontend 
        PythonOption TracEnvParentDir /usr/local/www-trac/trac01 
        PythonOption TracUriRoot / 
        </Location> 
        <LocationMatch "/[^/]+/login"> 
        SSLRequireSSL 
        SetHandler mod_python 
        SetEnv PYTHON_EGG_CACHE "/usr/local/www-cache/eggs" 
        PythonInterpreter main_interpreter 
        PythonOption TracEnvParentDir /usr/local/www-trac/trac01 
        AuthType Basic 
        AuthName "Trac" 
        AuthBasicProvider "ldap" 
        AuthLDAPURL "ldap://mon_ldap/dc=example,dc=org?mail?sub?(objectClass=inetOrgPerson)" 
        authzldapauthoritative Off 
        require valid-user 
        </LocationMatch> 
</VirtualHost>

La différence part rapport à la documentation originale est le passage sur HTTPS pendant et après l’authentification. La directive RedirectMatch permet ce genre de chose. La regexp “/([^/]+)/login https://trac01.garnett.fr/$1/login” redirige l’URL http://trac01.garnett.fr//login vers https://trac01.garnett.fr//login. Sauf si le client réecrit l’URL dans son navigateur, il est en HTTPS jusqu’à la fin de sa session. J’ai fait comme ça car un cookie transite de temps en temps entre le navigateur et le serveur une fois le client authentifié.

Conclusion

La solution ne serait pas complète sans un moyen simple d’ajouter des utilisateurs externes (qui n’ont pas de mail @garnett.fr). Cela peut être fait de manière super simple avec phpldapadmin et ce post qui proposait de merger une branche répliquée avec une branche writable pour enrichir un annuaire dédié avec des comptes locaux à l’application. Cette partie fera l’objet d’un autre post.

Digest de logs sous FreeBSD

J’aime bien avoir des remontées de logs par mail de mes machines. Ca fait très camp militaire le passage en revue des machines le matin. Les informations que je souhaite avoir sont les suivantes :

  • Mises à jour du système de base ?
  • Mises à jour des ports ?
  • Vulnérabilités connues sur mon système ?
  • Digest des logs (via logwatch)
  • Pour ce faire, il faut déjà installer plusieurs paquets :

    # cd /usr/ports/ports-mgmt/portupgrade
    # make clean install clean
    # portinstall portaudit
    # portinstall logwatch

    Commençons par mettre à jour le système de base. On va utiliser la commande freebsd-update vu que l’on est sur du i386. Pour télécharger les mises à jour :

    # freebsd-update fetch

    Pour lancer la mise à jour on utilisera la commande install à la place du fetch.

    Pour les mises à jour de ports, il nous faut déjà un arbre des ports à jour. Ajoutez la ligne suivante à la crontab :

    0       3       *       *       *       root    /usr/sbin/portsnap -I cron update

    Explications : cette commande portsnap va aller chercher une archive contenant la version à jour de l’arbre des ports (option “cron”). Ensuite juste le fichier /usr/ports/INDEX va être mis à jour (-I en combinaison avec update). Je ne souhaite pas mettre à jour violament l’arbre des ports au cas ou je sois en train de lancer une compilation dans celui ci alors qu’il est mis à jour de manière automatisée par le job de la crontab.

    Ensuite pour vérifier que les ports sont à jour :

    # portversion -l '<'

    Cette commande s’appuie sur le fichier INDEX pour savoir si un port installé est obsolète ou pas. Pour mettre le port à jour :

    # portupgrade <nom_du_port>

    Ou pour une mise à jour de tous les ports du système :

    # portupgrade -arR

    En parlant des ports, on peut aussi vérifier qu’aucun port installé n’est vulnérable à une attaque connue :

    # portaudit -Fad

    Cette commande télécharge la dernière version de la base de vulnérabilités et regarde si les ports installés sont exposés.

    Enfin, pour afficher un rapport de logs :

    # logwatch.pl --detail 10 --print

    Enfin on peut créer le script suivant :

    #!/usr/local/bin/bash
     
    umask 0077
    LOGFILE="/var/log/$HOSTNAME-daily-report.log"
     
    touch $LOGFILE
    RET=$?
     
    if [ $RET -ne 0 ]; then
            exit 100;
    fi
     
    echo "###################### Security Issues ###################" > $LOGFILE
    /usr/local/sbin/portaudit -Fad 2>>$LOGFILE 1>&2
    echo "" >> $LOGFILE
     
    echo "###################### Updating Status ###################" >> $LOGFILE
    echo "-- Base system --" >> $LOGFILE
    /usr/sbin/freebsd-update fetch 2>>$LOGFILE 1>&2
    echo "" >> $LOGFILE
    echo "-- Ports --" >> $LOGFILE
    /usr/local/sbin/portversion -l '<' 2>>$LOGFILE 1>&2
     
    /usr/local/sbin/logwatch.pl --detail 10 --print 2>>$LOGFILE 1>&2
     
    /usr/bin/mail -s "[STATCRON] $HOSTNAME reporting !" admin@admin.fr < $LOGFILE
     
    /bin/rm $LOGFILE
     
    exit 0

    Téléchargeable ici.

    Upgrade FreeBSD 6.3 vers 7.0 : Argh …

    Heureux les administrateurs qui ne mettent jamais à jour leur système. Sans sombrer dans le syndrome “cutting edge” à outrance j’essaie de maintenir les machines que j’administre ainsi que ma machine personnelle à jour niveau sécurité. Cependant il y a des fois où ce type de discipline est difficile à assumer. J’ai donc passé le présent serveur en FreeBSD 7.0 et j’ai pleuré. Revue de détail :

    Phase 1 : Mise à jour du système de base

    J’ai suivi la méthode d’un upgrade binaire décrite [ici]. Pour le système de base ça a très bien marché. En revanche ça a tout pété les ports.

    Phase 2 : Recompilation des ports

    A l’issu de l’upgrade du système de base j’obtiens :
    [garnett@silky ~]$ uname -a
    FreeBSD silky.garnett.fr 7.0-RELEASE-p2 FreeBSD 7.0-RELEASE-p2 #0: Wed Jun 18 07:33:20 UTC 2008 root@i386-builder.daemonology.net:/usr/obj/usr/src/sys/GENERIC i386

    Je me dis c’est OK, passons à la réinstallation des ports :

    [garnett@silky ~]$ sudo portupgrade -afP

    Et la c’est le drame : plus rien ne marche. J’ai des erreurs de librairies non trouvées par divers applications (Apache22, vim, php etc.). Gênant d’autant plus que je venais de réinstaller mes ports avec les nouvelles librairies du système de base … En lisant le fichier de sortie du portupgrade, je me rends compte qu’il a recompilé un bon paquet des ports (le -P veut dire que lorsqu’un package est disponible pour un port, on utilise l’utilise plutôt que de tout compiler).

    Bon, OK, ne faisons donc pas les choses à moitié et plutôt que d’avoir un truc un peu bâtard (ports et packages) recompilons tout :

    [garnett@silky ~]$ sudo portupgrade -af


    Ça mouline, ça mouline ;-)

    Confiant je tente un vim sur un fichier quelconque.
    Paf encore une librairie introuvable … Merde !

    Hop lancement de msn : chouette Arno est rentré de vacances. Après les politesses d’usage je lui demande si il a une idée et là il me dit qu’après chaque upgrade majeur de version il vaut mieux supprimer les ports et les réinstaller (méthode d’autant plus propre que certains logiciels disponibles sous forme de ports sont intégrés à cette occasion au système de base, par exemple ftp-proxy).

    Sans autre forme de procès :

    [garnett@silky ~]$ sudo pkg_delete -a
    [garnett@silky ~]$ sudo portinstall databases/mysql51-server
    [garnett@silky ~]$ sudo portinstall www/apache22

    Et la effectivement tout a fonctionné à merveille.
    Une fois de plus : merci Arno !!

    Moralité pour les upgardes mineurs ca passe en live. Par contre pour le prochain majeur je mettrais la machine offline et je stopperais les services pour réaliser ces manipulations.