NFS avec Kerberos
=================

Date: 2016-07-23 18:21
Author: jdn06
Category: Logiciels libres
Tags: NFS, Kerberos, Archlinux, FreeBSD

Après plusieurs années  passées à regretter le manque  de sécurité de
mon partage NFS domestique, reposant sur les seules adresses IP, sans
authentification  par  défaut, et  à  lancer  périodiquement un  bref
regard  sur  Kerberos, avant  d’en  conclure  rapidement que  c’était
décidément trop compliqué, j’ai profité des vacances pour regarder de
plus près ce protocole intimidant – et pas seulement de nom…

Bon, je ne vais pas non plus mentir : je me suis cassé les dents deux
bonnes  journées  avant  de  parvenir  à le  faire  marcher,  mais  a
posteriori, je dois dire que  ce n’est finalement pas aussi difficile
qu’on  pourrait le  croire. Non  que  deux journées  soient un  temps
négligeable, mais simplement  parce que j’ai beaucoup  perdu de temps
sur des  choses stupides,  faute de  chercher immédiatement  les bons
outils de débogeage.

Je veux  donc dire qu’en respectant  quelques règles de bon  sens, on
doit  pouvoir  faire  beaucoup  mieux. Je  renvoie  tout  d’abord  au
meilleur tutoriel en ligne que j’ai trouvé[1].

Quand  on débute  dans ce  genre d’entreprise,  il est  inévitable de
tâtonner un peu  et de commettre des erreurs. Le  problème est de les
trouver sans tourner en rond pendant des heures. Or, la mise en place
d’un tel système requiert tout un ensemble de démons et de protocoles
qui coopèrent,  en ne produisant  par défaut  que bien peu  de traces
dans les logs.

Essayons de  tracer brièvement les  étapes de  la mise en  place d’un
serveur NFS Kerberisé  sans FQDN, seulement avec des  noms de machine
sur un réseau  local. J’utilise par défaut Kerberos  MIT (la présence
du  concurrent  Heimdal  sur  FreeBSD m’a  posé  d’ailleurs  quelques
problèmes pour les clients sur FreeBSD…)

Une fois krb5 installé, il  faut commencer par éditer /etc/krb5.conf.
Le  realm qu’il  faut créer  sera en  quelque sorte  la marque  de ce
serveur Kerberos, qui le distingue  des autres serveurs Kerberos avec
lesquels les clients  pourraient être en contact. De  plus le fichier
doit contenir  quelques éléments  minimaux. La documentation  (et les
conseils de débogeage) insistent beaucoup sur la nécessité d’utiliser
exclusivement des FQDN. En fait,  il est possible d’utiliser des noms
de machines  locales, à condition  qu’elles figurent toutes  dans les
/etc/hosts du serveur et des clients.

Cela donne donc en gros :

   [realms]
       MONREALM = {
           kdc = mon_serveur_kerberos
           admin_server = mon_serveur_kerberos
           nfs-server = mon_serveur_kerberos
           }

   [domain_realm]
       mon_serveur_kerberos = MONREALM

   [logging]
       default = /var/log/kerberos.log
       kdc = /var/log/kerberos.log
       admin_server = /var/log/kerberos.log

Il faut ensuite créer un fichier /var/lib/krb5kdc/kadm5.acl et placer
dedans : */admin@MONREALM *

Il faut  aussi ouvrir les  ports suivants  sur le serveur  Kerberos à
tous les clients potentiels  et au serveur nfs : 88 et  749 en tcp et
en udp.

Puis on intialise la base de données avec un

   sudo kdb5_util create -r MONREALM -s

et on peut alors se connecter en admin localement avec un simple

   sudo kadmin.local

ce qui  va nous permettre  de lancer des  commandes dans le  shell de
Kerberos :

- listprincs  permet de  voir  tous  les  principaux  existants ;  un
principal  est  en  quelque  sorte un  utilisateur  et  un  contexte.

- add_principal -randkey nfs/mon_serveur_nfs@MONREALM   va  permettre
d’ajouter  un principal  pour  le serveur  nfs.  On utilise  l’option
randkey  car  on  ne  veut  pas  créer un  mot  de  passe,  mais  une
clé  qui permettra  au serveur  nfs  de s’authentifier  tout seul.

- ktadd nfs/mon_serveur_nfs@MONREALM  pour ajouter la  clé au fichier
/etc/krb5.keymap

Il   faudra   ajouter   comme  principaux   nfs/client1@MONREALM   et
nfs/client2@MONREALM,  à  nouveau  avec   des  clés  exportées,  puis
root/admin@MONREALM avec mot de  passe (donc sans l’option -randkey),
afin de pouvoir se connecter depuis les autres machines.

Il  faut  ensuite configurer  les  autres  machines (serveur  nfs  et
clients) pour pouvoir  utiliser le serveur Kerberos.  L’étape pour le
serveur  nfs  est  inutile  s’il  est sur  la  même  machine  que  le
serveur  Kerberos. A  chaque fois,  il  suffit de  copier le  fichier
/etc/krb5.conf  du  serveur  sur  ces  différentes  machines  (et  de
vérifier que leur fichier  /etc/hosts est correctement complété) puis
de lancer sudo kadmin, d’indiquer le mot de passe de sudo, puis celui
que Kerberos  demande. On importe  ensuite la clé qui  concerne cette
machine, avec par exemple la commande

   ktadd nfs/client1@MONREALM

afin que Kerberos transfère la clé  depuis le serveur vers le fichier
/etc/krb5.keymap du client1. Pour vérifier que cela a marché, on sort
de kadmin et  on essaie, toujours depuis le client,  un

   sudo kinit -k nfs/client1@MONREALM

La commande  ne doit  pas produire d’erreur.  On vérifie  le résultat
avec sudo klist.

Une fois  tout cela  ajouté, et les  vérifications faites,  la partie
Kerberos proprement dite est terminée. Reste à faire marcher NFS avec
Kerberos. Théoriquement, c’est le plus  facile. En pratique, c’est là
que j’ai beaucoup perdu de temps. Et comme je n’étais pas très l’aise
avec Kerberos,  j’étais persuadé qu’il s’agissait  d’un problème avec
la configuration de ce dernier, alors  que ce n’était pas vraiment le
cas.

Tout  d’abord,  il   faut  utiliser  la  norme   récente  du  fichier
/etc/exports, à savoir :

   /srv/nfs4 192.168.1.0/24(ro,fsid=0,no_subtree_check,async,\
   all_squash,sec=krb5)
       et non :
   /srv/nfs4 gss/krb5(ro,fsid=0,no_subtree_check,async,all_squash)

Ensuite, tout devrait fonctionner avec un simple

   sudo mount -v -o ro -t nfs4 mon_serveur_nfs:/ \
   /point_de_montage_nfs

depuis le  client. Si le  shell rend  la main sans  message d’erreur,
vous avez  gagné. Il reste  cependant à  obtenir des droits  pour les
autres utilisateurs  que root  sur la machine  client. Pour  cela, le
plus simple est de faire créer un principal utilisateur@MONREALM avec
mot de passe, dans le serveur Kerberos. Lorsque l’utilisateur veut se
connecter au partage  NFS monté par root, il suffit  qu’il tape kinit
dans une console  et renseigne le mot de passe  indiqué à la création
du principal en  question. Le ticket ainsi créé lui  donne ensuite un
accès de 24 heures.

Si vous avez moins de chance, il faut alors déboguer, et ça peut être
long et fastidieux. Mon premier réflexe, puisque c’est le serveur nfs
qui refuse le montage, a été  de regarder, en m’inspirant du très bon
article  du wiki  d’archlinux.org[2],  les logs  du  côté serveur  et
client en activant :

- pour le serveur

   sudo rpcdebug -m rpc -s all
   sudo rpcdebug -m nfsd -s all

- et pour le client

   sudo rpcdebug -m nfs -s all

Vu la verbosité du résultat, j’ai  mis beaucoup de temps à comprendre
que l’erreur ne figurait pas dans  ces logs et qu’il fallait chercher
ailleurs.  Mais où ?  Il faut  regarder  du côté  des mécanismes  qui
assurent  la  transisition  entre  Kerberos et  NFS,  à  savoir  sous
Archlinux les  démons rpc-gssd  (sur le client)  et gssproxy  (sur le
serveur). J’ai ajouté un fichier  de configuration pour gssproxy avec
un mode debug, /etc/gssproxy/gssproxy.conf :

   [gssproxy]
     debug = true

   [service/nfs-server]
     mechs = krb5
     socket = /run/gssproxy.sock
     cred_store = keytab:/etc/krb5.keytab
     trusted = yes
     kernel_nfsd = yes
     euid = 0

J’ai  ensuite  placé   une  option  de  debug  dans   le  lanceur  du
démon  rpc-gssd   (en  faisant  ça   assez  salement  par   un  ajout
d’option  dans  le  fichier  /usr/lib/systemd/system/rpc-gssd.service
ExecStart=/usr/sbin/rpc.gssd $GSSDARGS -vvv)  Avoir  cette  idée plus
vite m’aurait fait  gagner beaucoup de temps, plutôt  que de tâtonner
pendant des heures  du côté de Kerberos,  de RPC, de NFS  et de leurs
logs. J’ai fini par trouver un problème rapporté depuis un bon moment
concernant la version  0.5.1 de gssproxy. En revenant  à une ancienne
version, 0.4.1, le problème a disparu et tout s’est mis à fonctionner
selon mes attentes.

Happy end ? Par encore tout à fait, mais ça vient…

Il me restait  encore à configurer mon client sous  FreeBSD 10.3 ; or
ce dernier  utilise par défaut la  version Heimdal et non  la version
MIT du  protocole Kerberos.  Tant que c’est  le même  protocole, tout
doit être  compatible, me  disais-je, avant de  déchanter un  peu. En
effet, toute utilisation de  kadmin figeait le processus indéfiniment
sans aboutir. En réalité, kadmin  n’est pas compatible entre ces deux
versions. Or, pour transférer la clé,  il faut d’une manière ou d’une
autre l’utiliser. J’ai donc installé  la version MIT depuis les ports
pour transférer  la clé,  puis l’ai  désinstallée. Pour  permettre le
montage NFS via Kerberos, il faut lancer trois démons :

- nfsclient
- nfsuderd
- gssd

Restait aussi un autre problème que j’ai contourné sans en comprendre
l’origine,  à  savoir  le  fait   que  le  ticket  n’était  pas  créé
automatiquement au montage NFS,  provoquant l’échec de celui-ci. J’ai
donc créé le script suivant pour lancer le client NFS sous FreeBSD :

   #!/bin/sh
   sudo service nfsclient onestart
   sudo service nfsuserd onestart
   sudo service gssd onestart

   sudo kinit -k nfs/client2@MONREALM
   sudo mount_nfs -v -o nfsv4 mon_serveur_nfs:/ /point_de_montage_nfs

   kinit

Et tout fonctionnait… enfin !

[1] http://nfsv4.bullopensource.org/doc/kerberosnfs/krbnfs_howto_v3.pdf
[2] https://wiki.archlinux.org/index.php/NFS/Troubleshooting