Original in fr Frédéric Raynal
Frédéric Raynal prépare une thèse en informatique sur le tatouage d'images à l'INRIA. Il lit un très bon roman policier qui met en scène Th. Roosevelt au début du siècle alors qu'il était préfet de police. L'ambiance est très sombre. Il s'agit d'une enquête d'un groupe de personnes pour retrouver un tueur en série qui s'attaque à des enfants. Ce groupe s'appuie sur des techniques nouvelles (psychologies, empreintes digitales, etc...) pour parvenir à ces fins. Ce roman de de Caleb Carr, L'ange des ténèbres, dresse un portrait surprenant du début du siècle.
Le Network File System (NFS) permet de gérer des fichiers distribués sur plusieurs ordinateurs d'un réseau comme s'ils étaient sur un disque dur local. Ainsi, l'utilisateur n'a plus à se soucier de savoir où sont physiquement ses fichiers pour y accéder.
NFS permet très simplement de partager des données entre plusieurs machines. Par exemple, un utilisateur qui se connecte sur un réseau n'aura plus à se logger sur une machine précise : via NFS, son home directory lui sera livré (on dit en fait exporté) sur la machine où il se connecte.
NFS n'est toutefois pas un protocole très performant et n'est pas utilisable de manière confortable au travers une connexion par modem. En revanche, sur un réseau local, son utilisation offre une grande souplesse tant aux utilisateurs qu'aux administrateurs.
Il faut néanmoins prendre quelques précautions par rapport à ce service. En effet, permettre à n'importe qui d'écrire des données sur son réseau n'est pas franchement conseillé ;-) Certaines mesures indispensables limitent les risques.
Cet article commence donc par une très brève introduction
sur les systèmes de fichiers. Ensuite, nous verrons le fonctionnement
du protocole NFS. La partie suivante, moins théorique, détaillera
l'installation d'un serveur et d'un client NFS, ainsi que les précautions
minimum à prendre. Enfin, nous illustrerons dans un exemple, comment
combiner NFS, NIS et autofs.
Par exemple, on peut envisager tout support physique de données
(un disque dur par exemple) comme un suite de petites cases contenant des
informations : on parle de blocs (blocks en Anglais). Chaque
système de fichiers gère ces blocs différemment. Par
exemple, dans la figure 1 , on cherche à insérer
un fichier tenant sur 2 blocs. Dans l'illustration supérieure, le
fichier a été placé après le dernier bloc occupé,
laissant des espaces vides au début. A l'inverse, dans le schéma
inférieur, il a été placé au premier endroit
pouvant le contenir. Si le terme "fragmentation" vous évoque quelque
chose, vous savez maintenant ce qu'il représente ;-)
Le système de fichiers le plus commun sous Linux s'appelle ext2fs (extended 2 file system). Chaque fichier y est représenté par un inode1. Les répertoires contiennent des listes de fichiers, l'accès aux devices se fait par l'intermédiaire d'opérations de lecture/écriture sur des fichiers particuliers.
Le rôle d'un serveur NFS est donc de distribuer à ses clients
les inodes des fichiers auxquels ils veulent accéder. Toutefois,
le client ne pourrait fonctionner correctement s'il ne recevait que l'inode
de ces fichiers! Un serveur NFS offre donc une couche réseau supplémentaire
pour permettre à des machines distantes de manipuler ses inodes.
Les 4 services permettant à NFS de fonctionner sont :
Protocole |
|
|
nfs | Ce protocole est la base qui permet la création de fichier, leur recherche, leur lecture ou leur écriture. Ce protocole gère donc également l'authentification et les statistiques sur les fichiers. |
|
mountd | Celui-ci s'occupe du montage des systèmes exportés auxquels on accédera par nfs. Il envoie donc des requêtes de type mount et umount au serveur, qui doit donc conserver des informations sur les systèmes de fichiers exportés (voir section sur XXX). |
|
nsm
(Network Status Monitor) |
Il sert à monitorer les noeuds du réseau pour connaître l'état d'une machine (cliente ou serveur) pour signaler, par exemple, qu'elle redémarre. |
|
nlm
(Network Lock Manager) |
Pour éviter que des données soient altérées par plusieurs clients en même temps, ce protocole gère un système de locks (serrure ou fermeture en Anglais) qui permettent de signaler les systèmes de fichiers utilisés. Ainsi, à l'aide du protocole nsm qui sait quand un client redémarre, il libère tous les locks du client avant de les lui restituer si une nouvelle requête est émise. |
|
Le démon knfsd, disponible
avec les dernières versions du noyau, supporte directement les protocoles
nfs
et nlm. En revanche, mountd et nsm ne le sont pas
encore. Une fois le serveur NFS installé et démarré,
on peut vérifier que tout fonctionne ainsi :
>> ps auxwww | egrep "nfs|mount|lock|stat"Il existe actuellement 2 versions de NFS (versions 2 et 3 - que nous noterons respectivement NFSv2 et NFSv3 quand nous voudrons les différencier). Le serveur NFS de Linux ne supporte pour l'instant que la version 2 (d'où l'option sur la ligne du mountd de l'exemple précédent).
root 1370 0.0 0.2 1176 580 ? S 22:28 0:00 rpc.mountd --no-nfs-version 3
root 1379 0.0 0.0 0 0 pts/0 SW 22:28 0:00 [nfsd]
root 1380 0.0 0.0 0 0 pts/0 SW 22:28 0:00 [nfsd]
root 1381 0.0 0.0 0 0 pts/0 SW 22:28 0:00 [nfsd]
root 1382 0.0 0.0 0 0 pts/0 SW 22:28 0:00 [nfsd]
root 1383 0.0 0.0 0 0 pts/0 SW 22:28 0:00 [nfsd]
root 1384 0.0 0.0 0 0 pts/0 SW 22:28 0:00 [nfsd]
root 1385 0.0 0.0 0 0 pts/0 SW 22:28 0:00 [nfsd]
root 1386 0.0 0.0 0 0 pts/0 SW 22:28 0:00 [nfsd]
root 1399 0.0 0.0 0 0 pts/0 SW 22:28 0:00 [lockd]
root 1409 0.0 0.2 1156 560 ? S 22:28 0:00 rpc.statd
root 1652 0.0 0.1 1228 484 pts/3 S 22:49 0:00 egrep nfs|mount|lock|stat
L'objet au centre de toutes les préoccupations de NFS s'appelle un file handle. Il s'agit d'une suite de bits relativement ésotérique permettant de désigner de manière unique chacun des objets du systèmes de fichiers (donc un fichier entre autre, mais pas uniquement). Il contient par exemple, l'inode du fichier, mais également un fichier représentant le device où se trouve ce fichier. On peut donc voir NFS comme un système de fichiers qui en encapsule un autre.
root >>/usr/sbin/rpcinfo -pLa commande rpcinfo permet de connaître les services RPC qui fonctionnent sur la machine spécifiée en argument (l'option -p). On constate donc que portmap ne tourne pas encore : on le démarre (la plupart des distributions de Linux mettent en place des scripts qui permettent de faire ceci de manière automatique au démarrage de la machine) et on vérifie qu'il fonctionne correctement. Une autre possibilité expliquant la réponse négative reçue suite à l'appel de rpcinfo est tout simplement l'interdiction faite au portmapper de répondre, par l'entremise des fichiers /etc/hosts.{allow, deny}.
rpcinfo: can't contact portmapper: RPC: Remote system error - Connection refused
root >>/sbin/portmap
root >>/usr/sbin/rpcinfo -p
program vers proto port
100000 2 tcp 111 portmapper
100000 2 udp 111 portmapper
Avant de démarrer NFS proprement dit, il faut le configurer. Le seul fichier de configuration s'appelle /etc/exports. Chaque ligne contient l'emplacement à exporter suivi d'une liste de clients autorisés à y accéder . Il est possible, voire indispensable, de rajouter des options à la suite de chaque nom de client. La page man exports décrit clairement les syntaxes valides pour les noms de clients et les options.
Les formulations acceptées pour les noms des clients sont :
Lorsqu'on modifie le fichier de configuration /etc/exports, il faut signaler aux démons concernés que des changements se sont produits. La commande exportfs transmet ces informations aux serveurs. L'option -r synchronise le fichier /etc/mtab2 avec le fichier /etc/exports. L'option -v permet de connaître les systèmes de fichiers exportés avec leurs options.
Une fois que tout est en place, certains fichiers contiennent des informations importantes :
La commande mount permet d'accéder à différents systèmes de fichiers. Elle signale au noyau qu'un nouveau système de fichier est utilisable en indiquant son type, son device et un point de montage. L'option -t permet de préciser le système auquel un client veut accéder. Seuls les modules évoqués ci-dessus sont reconnus par le noyau. Pour un système NFS, l'argument s'écrit donc : -t nfs.
mount dispose d'options propres à NFS. Par exemple, les options rsize et wsize permettent de modifier les tailles des blocs en lecture et en écriture. On peut combiner les options spécifiques à NFS avec des options plus générales, comme intr, noexec ou nosuid. La page man de mount contient toutes ces options.
Supposons que la machine charly dispose d'un serveur NFS et exporte son répertoire /usr/local. Nous souhaitons y accéder de la machine jill, il suffit alors de monter le répertoire exporté de charly sur jill :
root@jill >> mount -t nfs -o nosuid,hard,intr charly:/usr/local /usr/localLa commande indique donc que nous allons monter un système de fichiers de type NFS (-t nfs), avec les options nosuid, hard et intr. Les 2 derniers arguments sont les plus intéressants. Le premier spécifie le device qui doit être monté. Dans le cas de NFS, la syntaxe diffère de l'usage habituel de mount. En effet, on commence par stipuler un serveur, puis un répertoire de ce serveur (Attention : un répertoire n'est normalement pas un device). Le dernier argument indique l'endroit auquel correspond ce système de fichiers sur le client. On vient donc de partager le /usr/local de charly avec jill, ce qui évite d'avoir à installer plusieurs fois certains programmes. Pour que ceci soit établi de manière permanente, on peut également le spécifier dans le fichier /etc/fstab de jill qui contient tous les devices à installer au démarrage. Ainsi, de manière équivalente, le fichier /etc/fstab contiendrait la ligne :
# device point de système de options dump fsckorder
# montage fichiers
charly:/usr/local /usr/local nfs nosuid,hard,intr 0 0
Un client ne peut croire aveuglément un serveur, il faut donc préciser des options contraignantes lors de l'utilisation de la commande mount. Nous avons déjà vu la première : nosuid. Elle annule l'effet des bits SUID et SGID. Ainsi, une personne root sur le serveur doit se connecter d'abord en tant qu'utilisateur quelconque sur le client pour ensuite seulement redevenir root. Une autre option, plus contraignante, est noexec. Elle interdit l'exécution des programmes contenus sur le système exporté. Cette option n'est utilisable que pour les systèmes contenant uniquement des données.
Du côté du serveur NFS, on peut également spécifier qu'on ne fait pas confiance au compte root des clients. On doit alors préciser dans le /etc/exports l'option root_squash. Ainsi, si un utilisateur avec l'UID 0 (celui de root) sur le client accède au système exporté par le serveur, il se voit attribuer l'UID de nobody pour effectuer les requêtes sur les fichiers. Cette option est active par défaut sous Linux mais s'annule par l'option no_root_squash. Notons qu'on peut préciser une plage d'UID pour lesquels l'option s'applique. Rappelons également que les options anonuid et anongid permettent de changer l'UID/GID de l'utilisateur nobody en celui souhaité.
Certaines mesures sont d'un ordre plus général et concernent
plutôt le portmapper. Par
exemple, on interdit l'accès à ce service à toutes
les machines par la ligne suivante dans le fichier
/etc/hosts.deny
:
# hosts.deny : interdiction absolue pour tout le monde de
# se servir du portmap
portmap: ALL
Ensuite, dans le /etc/hosts.allow,
on contrebalance cette interdiction drastique en autorisant l'accès
à toutes les machines souhaitées.
Des règles de firewalling adéquates contribuent également
à une meilleure protection. Il faut prendre garde aux ports employés
par les divers services ainsi qu'aux protocoles utilisés :
Service RPC | Port | Protocoles |
portmap | 111 | upd / tcp |
nfsd | 2049 | udp |
mountd | variable | udp / tcp |
Voyons d'abord la configuration sur notre serveur charly. Nous commençons par définir quelques maps NIS qui contiendront toutes les informations dont nous avons besoin.
Le fichier /etc/netgroup contient des groupes de machines ayant des caractéristiques communes (une même architecture par exemple). Il s'agit d'une map de NIS très pratique à utiliser pour NFS. Il suffit juste de rassembler dans un groupe toutes les machines pouvant accéder à un même système de fichiers exporté. Ce groupe sert ensuite dans le /etc/exports plutôt que de préciser tous les client un à un :
# /etc/netgroupConcernant NFS, nous savons que la configuration est assez restreinte. Le fichier /etc/exports de charly contient :
charlysangels (sabrina,,) (jill,,) (kelly)
# /etc/exportsPar ailleurs, nous décidons d'utiliser l'automount pour accéder au répertoire /usr/local ainsi exporté. En effet, plutôt que de monter directement ce système au boot, ce sera fait automatiquement si un utilisateur accède à un fichier de ce répertoire. Nous créons le fichier /etc/auto.map pour définir ce qui sera accessible à la fois par automount et par NIS :
/usr/local @charlysangels(ro)
# /etc/auto.mapComme nous voulons que ces informations (les nouveaux auto.map et netgroup) soient intégrées dans la base de données de NIS, nous devons modifier le Makefile avant de la reconstruire. En effet, il faut s'assurer que netgroup sera bien ajouté à la base. Concernant auto.map, ce fichier n'est pas défini par défaut, il faut signaler son existence. Il suffit pour cela d'ajouter une nouvelle entrée dans le Makefile, ainsi que la règle associée (en prenant modèle sur ce qui existe déjà) :
charly charly:/usr/local
#A ajouter dans le Makefile des Yellow Pages
AUTO_MAP = $(YPSRCDIR)/auto.map
# ...
#...
auto.map: $(AUTO_MAP) $(YPDIR)/Makefile
@echo "Updating $@..."Cette règle de production se contente d'enlever les commentaires, d'ajouter une nouvelle entrée à la base de données puis de transmettre l'information à tous les serveurs.
-@sed -e "/^#/d" -e s/#.*$$// $(AUTO_MAP) | $(DBLOAD) \
-i $(AUTO_MAP) -o $(YPMAPDIR)/$@ - $@
-@$(NOPUSH) || $(YPPUSH) -d $(DOMAIN) $@
Il ne reste plus qu'à exécuter un make dans le répertoire /var/yp.
Au tour de nos trois clients sabrina, jill et kelly. Là, il n'y a presque rien à faire :) Nous devons préciser à autofs qu'il doit gérer une nouvelle map qui lui sera fournie via les YPs. Dans chacun des /etc/auto.master des clients, la ligne suivante permet de signaler la présence d'une map auto.map qui sera obtenue via les services des YPs.
#/etc/auto.masterpuis il faut redémarrer autofs pour que cette nouvelle map soit prise en compte.
/usr/local yp auto.map --intr,nosuid,nodev
Ainsi, il existe un unique répertoire /usr/local physiquement sur charly. Du coup, pour installer des programmes très spécifiques, en les disposant sur charly, toutes nos machines pourront également en profiter.
Cet exemple peut aller beaucoup plus loin en n'installant qu'un seul
système /usr, /usr/doc
ou d'autres, mais la pratique montre que ce n'est pas très raisonnable.
Les installations nécessitent souvent de modifier des fichiers dans
le répertoire /etc ou autres.
Il faudrait donc aller faire des retouches sur toutes les machines pour
mettre à jour les fichiers non-exportés, ce qui devient vite
très fastidueux.
NFS