NFS over TLS protects file traffic at the RPC transport layer while keeping normal NFS export and mount semantics. It is useful when an export still uses sec=sys for Unix user identity but the network path should not carry file data in clear text.
Linux implements this feature as RPC-with-TLS. The kernel asks tlshd to perform the TLS handshake, tlshd uses X.509 trust material, and the export's xprtsec= option decides whether clients may connect without TLS, with server-authenticated TLS, or with mutual TLS.
A production rollout should treat certificate names and trust stores as part of the mount contract. Clients must mount with a DNS name covered by the server certificate, and the export should deny non-TLS clients before the share is exposed beyond a trusted test host.
Related: How to configure an NFSv4-only server
Related: How to create an NFS export
Related: How to secure an NFS export with Kerberos
$ sudo dnf install --assumeyes nfs-utils ktls-utils Dependencies resolved. ##### snipped ##### Installed: ktls-utils-0.11-3.el9.aarch64 nfs-utils-2.5.4-43.el9.aarch64 Complete!
ktls-utils provides tlshd. Red Hat documents native NFS TLS support from RHEL 9.6; older kernels or NFS user-space packages may not support xprtsec=.
$ sudo openssl req -new -newkey rsa:4096 -noenc \ -keyout /etc/pki/tls/private/files.example.net.key \ -out /etc/pki/tls/private/files.example.net.csr \ -subj "/C=US/ST=State/L=City/O=Example Organization/CN=files.example.net" \ -addext "subjectAltName=DNS:files.example.net,IP:192.0.2.40"
The certificate's Subject Alternative Name must cover the hostname or IP address that clients use in the mount source. Keep the private key readable only by root.
The CA should return a server certificate such as files.example.net.crt and the CA certificate such as ca.crt. Use an internal CA, enterprise PKI, or another trusted issuer that matches the client trust policy.
$ sudo cp ca.crt /etc/pki/ca-trust/source/anchors/
$ sudo update-ca-trust
Leaving x509.truststore unset in /etc/tlshd.conf makes tlshd use the system trust store.
$ sudo mv files.example.net.crt /etc/pki/tls/certs/
$ sudo restorecon -Rv /etc/pki/tls/certs/ /etc/pki/tls/private/ Relabeled /etc/pki/tls/certs/files.example.net.crt Relabeled /etc/pki/tls/private/files.example.net.key
$ sudoedit /etc/tlshd.conf
[authenticate.server] x509.certificate= /etc/pki/tls/certs/files.example.net.crt x509.private_key= /etc/pki/tls/private/files.example.net.key
Edit the active tlshd configuration file installed by the local package. Red Hat-family packages use /etc/tlshd.conf.
$ sudo systemctl enable --now tlshd.service
tlshd reads its configuration when it starts. Restart tlshd.service after later certificate or /etc/tlshd.conf changes.
$ sudoedit /etc/exports.d/projects.exports
/srv/nfs/projects 192.0.2.0/24(rw,sync,no_subtree_check,root_squash,sec=sys,xprtsec=tls)
xprtsec=tls requires a TLS-protected transport without requiring a client certificate. Use xprtsec=mtls only after configuring client certificates under the tlshd client authentication section.
$ sudo exportfs -ra
No output usually means exportfs accepted the saved definitions. Fix any reported path, selector, or option error before testing from a client.
Related: How to reload NFS exports
$ sudo exportfs -v /srv/nfs/projects 192.0.2.0/24(sync,wdelay,hide,no_subtree_check,sec=sys,rw,root_squash,no_all_squash,xprtsec=tls)
Look for xprtsec=tls in the selector's option set. Defaults such as wdelay, hide, and no_all_squash can appear even when they were not written in the source file.
Related: How to list NFS exports on a server
$ sudo dnf install --assumeyes nfs-utils ktls-utils Dependencies resolved. ##### snipped ##### Complete!
$ sudo cp ca.crt /etc/pki/ca-trust/source/anchors/
$ sudo update-ca-trust
$ sudo systemctl enable --now tlshd.service
$ sudo mkdir --parents /mnt/projects
Files already inside /mnt/projects become hidden while the NFS filesystem is mounted there.
$ sudo mount -t nfs -o xprtsec=tls files.example.net:/srv/nfs/projects /mnt/projects
Use the server hostname covered by the certificate. A raw IP address fails hostname validation unless the certificate also includes that IP address as a subject alternative name.
Related: How to mount an NFS export on Linux
$ findmnt -o TARGET,SOURCE,FSTYPE,OPTIONS /mnt/projects TARGET SOURCE FSTYPE OPTIONS /mnt/projects files.example.net:/srv/nfs/projects nfs4 rw,relatime,vers=4.2,sec=sys,xprtsec=tls ##### snipped #####
Some clients show transport security in tlshd logs instead of every mount-option view. Treat the successful handshake log as the transport proof when the mount table omits xprtsec=tls.
$ sudo journalctl -u tlshd.service --since -5m --no-pager Jul 05 14:20:31 client.example.net tlshd[2184]: Handshake with files.example.net (192.0.2.40) was successful
$ sudo mkdir --parents /mnt/projects-no-tls-test
$ sudo mount -t nfs -o xprtsec=none files.example.net:/srv/nfs/projects /mnt/projects-no-tls-test mount.nfs: access denied by server while mounting files.example.net:/srv/nfs/projects
If this mount succeeds, the server export is not enforcing xprtsec=tls for the client selector that matched the request. Recheck /etc/exports.d/projects.exports and the active exportfs -v table before exposing the share.
$ sudo rmdir /mnt/projects-no-tls-test