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
Steps to require NFS over TLS for an export:
- Install the NFS and TLS handshake packages on the server.
$ 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=.
- Create a server private key and certificate signing request.
$ 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.
- Request a server certificate from the CA trusted by the clients.
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.
- Import the CA certificate into the server trust store.
$ sudo cp ca.crt /etc/pki/ca-trust/source/anchors/
- Rebuild the server trust store.
$ sudo update-ca-trust
Leaving x509.truststore unset in /etc/tlshd.conf makes tlshd use the system trust store.
- Install the signed server certificate.
$ sudo mv files.example.net.crt /etc/pki/tls/certs/
- Restore SELinux labels on the certificate and key paths.
$ 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
- Add the server certificate and private key to the tlshd server authentication section.
$ 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.
- Enable and start the tlshd service on the server.
$ sudo systemctl enable --now tlshd.service
tlshd reads its configuration when it starts. Restart tlshd.service after later certificate or /etc/tlshd.conf changes.
- Open the export definition file on the server.
$ sudoedit /etc/exports.d/projects.exports
- Require TLS transport security on the export.
/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.
- Reload the saved export definitions.
$ 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
- Verify that the active export requires TLS.
$ 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
- Install the NFS and TLS handshake packages on the client.
$ sudo dnf install --assumeyes nfs-utils ktls-utils Dependencies resolved. ##### snipped ##### Complete!
- Import the CA certificate into the client trust store.
$ sudo cp ca.crt /etc/pki/ca-trust/source/anchors/
- Rebuild the client trust store.
$ sudo update-ca-trust
- Enable and start the tlshd service on the client.
$ sudo systemctl enable --now tlshd.service
- Create the client mount point.
$ sudo mkdir --parents /mnt/projects
Files already inside /mnt/projects become hidden while the NFS filesystem is mounted there.
- Mount the export with TLS transport security.
$ 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
- Verify the mounted NFS source and options.
$ 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.
- Check the client tlshd log for the successful handshake.
$ 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
- Create a temporary mount point for the non-TLS denial test.
$ sudo mkdir --parents /mnt/projects-no-tls-test
- Verify that an unencrypted mount is denied.
$ 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.
- Remove the temporary denial-test mount point.
$ sudo rmdir /mnt/projects-no-tls-test
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.