NFSv4

Published: 11-07-2015

Updated: 25-01-2017

By: Maxime de Roucy

tags: nfs

Ici je détaille la création d’un partage avec authentification via Kerberos.

Les démon nécessaire pour NFSv4 sont :

Sources :

Configuration

Kerberos

Voir la page dédiée.

Il faut que chaque machine ai un fqdn et puisse résoudre ceux des autres (et faire des requête inverse).

BIND

TODO a écrire

bind doit être installé

hosts

Si vous n’avez pas de serveur DNS administrable sur votre réseau et que votre architecture est simple, vous pouvez utiliser les fichiers /etc/hosts.

127.0.0.1   localhost
::1     localhost
192.168.1.102   server.lan server
192.168.1.100   laptop.lan laptop

Définissez les entrés correspondant au client dans le /etc/hosts du server et vice-versa.

Principals

Création des « principals », ces opérations peuvent être faite sur le client ou le serveur, du moment qu’on est dans un kadmin c’est pareille.

root@server # kadmin

Authenticating as principal root/admin@LAN with password.
Password for root/admin@LAN:

kadmin:  addprinc -randkey nfs/server.lan

WARNING: no policy specified for nfs/server.lan@LAN; defaulting to no policy
Principal "nfs/server.lan@LAN" created.

kadmin:  addprinc -randkey nfs/laptop.lan

WARNING: no policy specified for nfs/laptop.lan@LAN; defaulting to no policy
Principal "nfs/laptop.lan@LAN" created.

kadmin:  addprinc max

WARNING: no policy specified for max@LAN; defaulting to no policy
Enter password for principal "max@LAN":
Re-enter password for principal "max@LAN":
Principal "max@LAN" created.

kadmin:  quit

Dans l’ordre :

Sur le serveur, enregistrement de la clé du principal nfs/server.lan@LAN dans le « keytab »

root@server # kadmin

Authenticating as principal root/admin@LAN with password.
Password for root/admin@LAN:

kadmin:  ktadd nfs/server.lan

Entry for principal nfs/server.lan with kvno 2, encryption type aes256-cts-hmac-sha1-96 added to keytab FILE:/etc/krb5.keytab.
Entry for principal nfs/server.lan with kvno 2, encryption type aes128-cts-hmac-sha1-96 added to keytab FILE:/etc/krb5.keytab.
Entry for principal nfs/server.lan with kvno 2, encryption type des3-cbc-sha1 added to keytab FILE:/etc/krb5.keytab.
Entry for principal nfs/server.lan with kvno 2, encryption type arcfour-hmac added to keytab FILE:/etc/krb5.keytab.

kadmin:  quit

Sur le client, enregistrement de la clé du principal nfs/laptop.lan@LAN dans le « keytab »

root@laptop # kadmin

Authenticating as principal root/admin@LAN with password.
Password for root/admin@LAN:

kadmin:  ktadd nfs/laptop.lan

Entry for principal nfs/laptop.lan with kvno 3, encryption type aes256-cts-hmac-sha1-96 added to keytab FILE:/etc/krb5.keytab.
Entry for principal nfs/laptop.lan with kvno 3, encryption type aes128-cts-hmac-sha1-96 added to keytab FILE:/etc/krb5.keytab.
Entry for principal nfs/laptop.lan with kvno 3, encryption type des3-cbc-sha1 added to keytab FILE:/etc/krb5.keytab.
Entry for principal nfs/laptop.lan with kvno 3, encryption type arcfour-hmac added to keytab FILE:/etc/krb5.keytab.

kadmin:  quit

Serveur

Noyau

Vérifier les options de compilation du noyau. Au minimum :

.config - Linux/x86 4.2.5-gentoo Kernel Configuration
> File systems > Network File Systems qqqqqqqqqqqqqqqqqqqqqqqqqqqq
lqqqqqqqqqqqqqqqqqqqqqq Network File Systems qqqqqqqqqqqqqqqqqqqqk
x  …                                                             x
x lqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqk x
x x            --- Network File Systems                        x x
x x             …                                              x x
x x            [*]   NFS server support                        x x
x x             …                                              x x
x x            [*]     NFS server support for NFS version 4    x x
x x             …                                              x x
x x            [*]   Secure RPC: Kerberos V mechanism          x x
x x                                                            x x
x mqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqj x
tqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqu
x    <Select>    < Exit >    < Help >    < Save >    < Load >    x
mqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqj

Sur certain tuto il est indiqué que « Secure RPC: Kerberos V mechanism » doit être compilé comme module noyau sinon le couplage NFS↔Kerberos ne fonctionne pas. Ce n’est pas le cas sur mon installation. L’élément est compilé en dure et tous fonctionne parfaitement.

Source : wiki Gentoo

idmapd

Les paramètre important du fichier /etc/idmapd.conf sont Domain et Local-Realms.

[General]
Domain = lan
Local-Realms = LAN
[Mapping]
Nobody-User = nobody
Nobody-Group = nobody
[Translation]
Method = nsswitch
[Static]
[UMICH_SCHEMA]
LDAP_server = ldap-server.local.domain.edu
LDAP_base = dc=local,dc=domain,dc=edu

La présence de idmapd ne signifie pas que les noms, uid et gid peuvent être différent entre le serveur et le client. Avec Kerberos on ne se base que sur les noms des utilisateurs, il faut donc que les noms soit identique sur le client et le serveur. Sans Kerberos on se base en plus sur les uid et gid, il faut donc que les noms soit identique mais aussi les uid/gid.

L’utilisation de montage NFS implique l’utilisation de deux niveau/type d’opérations. Il y a les opérations RPC et les opérations NFS. Au niveau NFS (haut niveau), les opérations qui ont besoin d’identifier un utilisateur utilise sont nom, il n’y a pas de notion de uid ou gid. Au niveau RPC (bas niveau) ça dépend. Si on se sert de Kerberos c’est le nom de l’utilisateur qui est utilisé (en fait c’est le *principal*… mais celui-ci dépend du nom), c’est pourquoi l’utilisateur à besoin d’un ticket pour naviguer dans les répertoires monté en NFS. Si on ne s’en sert pas (on se sert alors donc de auth_unix) ce sont l’uid et les gid qui sont utilisé.

Les accès (lecture, écriture, exécution) au fichier et dossier sont assuré au niveau RPC. En revanche, la gestion/affichage des ACL, des owner/group des fichier/dossier est fait au niveau NFS.

Exemple d’Alessio Gaeta, sans Kerberos. Pour faire simple, l’affichage est géré au niveau NFS, on à donc une correspondance au niveau des nom. Mais au niveau de l’éxécution des opération, les manipulation de fichier, les uid sont utilisé. « valentina client » devient donc l’équivalent de « alberto server » même si ça ne correspond pas à ce qui est afficher dans point de montage du client.

root@server # id alberto
uid=1002(alberto) …
root@server # id valentina
uid=1005(valentina) …
root@server # ls -l
… alberto   … alberto-dir
… valentina … valentina-dir
root@server # ls -n
… 1002      … alberto-dir
… 1005      … valentina-dir

root@client # id alberto
id: alberto: no such user
root@client # id valentina
uid=1002(valentina) …

valentina@client % ls -l
… nobody    … alberto-dir
… valentina … valentina-dir
valentina@client % ls -n
… 65534     … alberto-dir
… 1002      … valentina-dir
valentina@client % ls valentina-dir
ls: cannot open directory valentina-dir: Permission denied
valentina@client % ls -l alberto-dir
… nobody    … file1
… nobody    … file2
valentina@client % ls -n alberto-dir
… 65534     … file1
… 65534     … file2
valentina@client % touch valentina-dir/newfile
touch: cannot touch 'valentina-dir/newfile': Permission denied
valentina@client % touch alberto-dir/newfile

root@server # ls -l alberto-dir
… alberto   … file1
… alberto   … file2
… alberto   … newfile
root@server # ls -n alberto-dir
… 1002     … file1
… 1002     … file2
… 1002     … newfile

TODO : faire la même chose avec kerberos (pour l’instant mes utilisateurs on les même uid/gid)

Démons

Avant de démarrer les démon vérifié que le répertoire dont le nom est contenu dans le fichier /proc/fs/nfsd/nfsv4recoverydir est bien présent :

root@server # cat /proc/fs/nfsd/nfsv4recoverydir
/var/lib/nfs/v4recovery
root@server # mkdir -p /var/lib/nfs/v4recovery

Sans cela vous risquez d’obtenir une erreur :

NFSD: Unable to create client record on stable storage: -110

systemd

Pour ceux qui ont fait le choix d’utiliser systemd.

Il faut modifier le fichier de configuration /etc/conf.d/nfs. Noté que j’ai du changer les noms des variables par rapport à la version OpenRC.

root@server # grep -v -e '^#' -e '^$' /etc/conf.d/nfs
RPCNFSDARGS="--no-udp -N 2 -N 3 3"
RPCMOUNTDARGS="-N 2 -N 3"
RPCIDMAPDARGS=""
SVCGSSDARGS=""

J’ai aussi dû éditer le unit-file de nfs-serveur pour faire en sorte qu’il ne démarre que les démons voulue.

root@server # systemctl edit --full nfs-server.service
root@server # systemd-delta
…
[OVERRIDDEN] /etc/systemd/system/nfs-server.service → /usr/lib/systemd/system/nfs-server.service

--- /usr/lib/systemd/system/nfs-server.service  2015-12-01 05:55:13.640200202 +0100
+++ /etc/systemd/system/nfs-server.service      2016-01-31 18:15:07.326798346 +0100
@@ -1,10 +1,7 @@
 [Unit]
 Description=NFS server and services
-Requires= network.target proc-fs-nfsd.mount rpcbind.target
-Requires= nfs-mountd.service
-Wants=rpc-statd.service nfs-idmapd.service auth-rpcgss-module.service
-Wants=rpc-gssd.service gssproxy.service rpc-svcgssd.service
-Wants=rpc-statd-notify.service
+Requires= network.target proc-fs-nfsd.mount nfs-mountd.service
+Wants= nfs-idmapd.service rpc-svcgssd.service

 After= network.target proc-fs-nfsd.mount rpcbind.target nfs-mountd.service
 After= nfs-idmapd.service rpc-statd.service

…

Note : ici je suis obligé d’utiliser systemctl edit --full car, comme indiqué dans le man systemd.unit :

Note that dependencies (After=, etc.) cannot be reset to an empty list, so dependencies can only be added in drop-ins. If you want to remove dependencies, you have to override the entire unit.

Lancement et ajout du processus au démarrage.

root@server # systemctl start nfs-server.service
root@server # systemctl enable nfs-server.service

OpenRC

Si vous utilisez OpenRC et non systemd.

Le fichier /etc/conf.d/nfs permet de configurer les démons à démarrer et leurs options.

NFS_NEEDED_SERVICES="rpc.idmapd rpc.svcgssd"
OPTS_RPC_NFSD="--no-udp -N 2 -N 3 4"
OPTS_RPC_MOUNTD="-N 2 -N 3"
OPTS_RPC_IDMAPD="-S"
OPTS_RPC_SVCGSSD=""
EXPORTFS_TIMEOUT=30

Démarrage des démons et activation au boot :

root@server # /etc/init.d/nfs start
 * Starting rpcbind ...          [ ok ]
 * Starting svcgssd ...          [ ok ]
 * Starting idmapd ...           [ ok ]
 * Exporting NFS directories ... [ ok ]
 * Starting NFS mountd ...       [ ok ]
 * Starting NFS daemon ...       [ ok ]
 * Starting NFS smnotify ...     [ ok ]
root@server # rc-update add nfs default

Exports

/etc/exports

/export        -fsid=0,ro,async,all_squash,no_subtree_check,sec=krb5 192.168.1.0/24 2001:470:1f13:1e5::/64
/export/max    -rw,async,no_subtree_check,sec=krb5 192.168.1.0/24 2001:470:1f13:1e5::/64
/export/ddext  -rw,async,no_subtree_check,sec=krb5 192.168.1.0/24 2001:470:1f13:1e5::/64

Firewall

Le client n’est pas protégé par un firewall. Sur le serveur j’accepte les connexions sur le démon nfsd (2049).

-A INPUT -s 192.168.1.0/24 -p tcp --dport nfs -j ACCEPT

Pour kerberos, allez voir la page dédiée.

Client

/etc/conf.d/nfs-common.conf

root@laptop # cat /etc/conf.d/nfs-common.conf
…
GSSD_OPTS=""
…
root@laptop # systemctl enable --now rpc-gssd.service

/etc/fstab

server.lan:/max     /mnt/server   nfs  defaults,_netdev,nfsvers=4,nolock,users,noauto,lazytime,sec=krb5  0  0
server.lan:/ddext   /mnt/ddext    nfs  defaults,_netdev,nfsvers=4,nolock,users,noauto,lazytime,sec=krb5  0  0

Montage du partage

max@laptop % mount /mnt/ddext
max@laptop % ls /mnt/ddext
ls: cannot open directory /mnt/ddext: Permission denied

Authentification de l’utilisateur dans Kerberos. Pour pouvoir parcourir le montage.

max@laptop % kinit
Password for max@LAN:
max@laptop % ls /mnt/ddext
test1 test2 …

Sources : * help ubuntu * poste de blog sur NFS & MIT Kerberos * kinit

nolock

Vous aurez peut-être remarqué l’option nolock dans le fstab du client. Sans cette option, je me retrouve avec :

max@laptop % mount /mnt/server
Job for rpc-statd.service failed. See "systemctl status rpc-statd.service" and "journalctl -xe" for details.
mount.nfs: rpc.statd is not running but is required for remote locking.
mount.nfs: Either use '-o nolock' to keep locks local, or start statd.
mount.nfs: an incorrect mount option was specified

NFSv2 et NFSv3 utilise le « NLM sideband protocol » pour géré le système de lock de fichier. Dans NFSv4, le locking est intégré au protocol, il n’y a plus besoin de NLM.

In NFS version 4, file locking is supported directly in the main NFS protocol, and the NLM and NSM sideband protocols are not used.

Si, l’option nolock n’est pas présente, mount utilise NLM. rpc.statd est le service responsable de ce protocole, systemd essaie donc de le démarrer mais échoue car rpcbind n’est pas pas démarré (ainsi que toutes les dépendances habituel necessaire à un client NFSv2 ou NFSv3).

If neither option is specified (or if lock is specified), NLM locking is used for this mount point.

pam_krb5

Il est possible de faire en sorte de récupérer automatiquement le ticket de l’utilisateur au login de celui-ci.

Installer le paquet pam-krb5.

TODO a écrire (dans la page Kerberos… pas celle de NFS)

Invalid argument

Si la commande mount retourne Invalid argument alors que tous les argument semble bon. Vérifier que rpc.gssd est démarré.

max@laptop % mount -v /mnt/server
mount.nfs: timeout set for Sat Sep 10 18:45:28 2016
mount.nfs: trying text-based options 'nolock,sec=krb5,vers=4,addr=2001:…,clientaddr=2001:…'
mount.nfs: mount(2): Invalid argument
mount.nfs: an incorrect mount option was specified

J’ai eu un problème avec rpc-gssd.service qui ne se lancé pas. J’ai indiqué la solution dans le bug tracker Archlinux.

Résumé

Ajout d’un nouveau client

Sur le serveur :

root@server # systemctl start krb5-kadmind.service
root@server # kadmin
Authenticating as principal root/admin@LAN with password.
Password for root/admin@LAN:
kadmin:  addprinc -randkey nfs/max-test.lan
WARNING: no policy specified for nfs/max-test.lan@LAN; defaulting to no policy
Principal "nfs/max-test.lan@LAN" created.
kadmin:  quit

Sur le client :

max@max-test % cat /etc/krb5.conf
[libdefaults]
    default_realm = LAN
[realms]
    LAN = {
        admin_server = server.lan
        default_domain = lan
        kdc = server.lan
    }
[domain_realm]
    .lan = LAN
    lan  = LAN
max@max-test % grep server.lan /etc/hosts
2001:… server.lan
root@max-test # kadmin
Authenticating as principal root/admin@LAN with password.
Password for root/admin@LAN:
kadmin:  ktadd nfs/max-test.lan
Entry for principal nfs/max-test.lan with kvno 2, encryption type aes256-cts-hmac-sha1-96 added to keytab FILE:/etc/krb5.keytab.
Entry for principal nfs/max-test.lan with kvno 2, encryption type aes128-cts-hmac-sha1-96 added to keytab FILE:/etc/krb5.keytab.
kadmin:  quit
max@max-test % yaourt -S nfs-utils
max@max-test % grep server /etc/fstab
server.lan:/max /mnt/server nfs defaults,nfsvers=4,nolock,_netdev,users,noauto,lazytime,sec=krb5 0 0
max@max-test % sudo systemctl start rpc-gssd.service
max@max-test % sudo mkdir /mnt/server
max@max-test % kinit
Password for max@LAN:
max@max-test % mount /mnt/server

Débug

En générale avec NFS, si vous pensez avoir une bonne conf mais que ça ne fonctionne pas… reboot. Ça m’est arrivé plusieurs fois de rebooter pour que d’un coup tout fonctionne. Il y a certainement des caches et des buffers qu’il faudrait vider pour éviter le redémarrage mais je ne sais pas comment faire.

Serveur

Activation des options de debug

/etc/conf.d/nfs

NFS_NEEDED_SERVICES="rpc.idmapd rpc.svcgssd"
OPTS_RPC_NFSD="--no-udp -N 2 -N 3 8 -d"
OPTS_RPC_MOUNTD="--no-udp -N 2 -N 3 -d all"
OPTS_RPC_STATD=""
OPTS_RPC_IDMAPD="-vvvv"
OPTS_RPC_GSSD=""
OPTS_RPC_SVCGSSD="-vvvv"
OPTS_RPC_RQUOTAD=""
EXPORTFS_TIMEOUT=30

/etc/conf.d/rpcbind

RPCBIND_OPTS="-vvvv"

Arrêt des démons

root@server # /etc/init.d/rpcbind stop
 * Stopping NFS mountd ...         [ ok ]
 * Stopping NFS daemon ...         [ ok ]
 * Unexporting NFS directories ... [ ok ]
 * Stopping svcgssd ...            [ ok ]
 * Stopping idmapd ...             [ ok ]
 * Stopping rpcbind ...            [ ok ]
root@server # pgrep -f -a 'nfs'
root@server # pgrep -f -a '\/rpc'

Redémarrage des démons

root@server # /etc/init.d/nfs start
 * Starting rpcbind ...          [ ok ]
 * Starting svcgssd ...          [ ok ]
 * Starting idmapd ...           [ ok ]
 * Exporting NFS directories ... [ ok ]
 * Starting NFS mountd ...       [ ok ]
 * Starting NFS daemon ...       [ ok ]
 * Starting NFS smnotify ...     [ ok ]

Vérification des démons qui sont lancés et leurs options

root@server # pgrep -f -a '\/rpc'
1467 /sbin/rpcbind -vvvv
1550 /usr/sbin/rpc.svcgssd -vvvv
4571 /usr/sbin/rpc.idmapd -vvvv
15095 /usr/sbin/rpc.mountd --no-udp -N 2 -N 3 -d

N’exporter qu’un seul répertoire de façon très simple

/etc/exports

/export/max   gss/krb5(fsid=0,rw,insecure,no_subtree_check)

Ré-exports

root@server # exportfs -ra

Désactivation du firewall et vérification

root@server # /etc/init.d/iptables stop
…
root@server # iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Client

Activation des options de debug

/etc/conf.d/nfs-common.conf

STATD_OPTS=""
SMNOTIFY_OPTS=""
IDMAPD_OPTS=""
GSSD_OPTS="-vvvv"

/etc/conf.d/rpcbind

RPCBIND_ARGS="-vvvv"

Arrêt des démons

max@laptop % sudo systemctl stop rpcbind
Warning: Stopping rpcbind.service, but it can still be activated by:
  rpcbind.socket
max@laptop % sudo systemctl stop nfs-client.target
max@laptop % pgrep -f -a rpc
153 rpciod
15461 /usr/sbin/rpc.gssd
15462 /usr/sbin/rpc.svcgssd
max@laptop % sudo kill 15461 15462

Redémarrage des démons

root@laptop # systemctl start rpcbind.service
root@laptop # systemctl start nfs-clients.target

Vérification des démons qui sont lancés et leurs options

max@laptop % pgrep -f -a rpc
153 rpciod
15461 /usr/sbin/rpc.gssd -vvvv
15508 /usr/bin/rpcbind -w -vvvv

Monter un répertoire de façon très simple

max@laptop % mkdir /tmp/test
max@laptop % sudo mount -vvv -t nfs4 -o sec=krb5 server.lan:/ /tmp/test

Notes

À chaque échec redémarré les démon du client (et potentiellement du serveur). Ils possèdent un cache que peu foutre la merde (notamment pour les résolution DNS).

Commandes

showmount ne peut plus être utilisé sur un serveur full NFSv4.