If you are running a FreeBSD13.2 or newer system, TLS 1.3 is supported and this conforms to the RFC and the Linux client requirements. (The Linux client patches may not have made it into a production Linux kernel yet.) For those familiar with FreeBSD, the steps are: - Install a recent FreeBSD13 (13.2 or newer or main/current FreeBSD14) system on amd64 (or aarch64/arm64). - If you run a custom kernel configuration, "options KERN_TLS" needs to be in that kernel configuration. - Set ktls sysctl(s) and load modules, as required (See "man ktls" for more). (A) Install the software (here is how I'd do it): - Install a recent FreeBSD13 (or main/current FreeBSD14) system on amd64, including sources and ports. There are many ways to do this, but downloading and installing a FreeBSD13 release or FreeBSD14 snapshot is probably the easiest. Go anonymous ftp onto ftp.freebsd.org cd pub/FreeBSD/releases/ISO-IMAGES/13.2 or cd pub/FreeBSD/snapshots/ISO-IMAGES/14.0 - You want to get an install image with "amd64" in it (thats 64bit x86). (aarch64/arm64 should work, as well) The more recent date is a newer snapshot. You might as well try the most recent one. An iso with "disc1" in the name is a full install image that can be burned onto a DVD. (I haven't done other types of installs, but there are several others.) - Burn the iso onto a DVD (or whatever). - Install it on a 64bit x86 system. Click on "source" and "ports" selections to add them to what will be installed. - You should now be able to boot FreeBSD on the system. (For here on, you might as well login as root.) Look at /usr/src/sys/amd64/conf/GENERIC and see if "options KERN_TLS" is in the file. If not, then: - Build/install a custom kernel with "options KERN_TLS" in the kernel config. # cd /usr/src/sys/amd64/conf - edit GENERIC and add the line options KERN_TLS # cd /usr/src # make buildkernel # make installkernel # reboot (B) - Set ktls sysctl(s) and load modules, as required. (See "man ktls" for more info.) - For a FreeBSD13 system, ktls_ocf.ko must be loaded. The simplest way to do that is to put/add "ktls_ocf" to a kld_list line in the system's /etc/rc.conf. (This is not needed for a FreeBSD14/main system.) - edit /etc/sysctl.conf and add this line kern.ipc.tls.enable=1 # reboot You should now be finally ready to configure and run a TLS mount. (If you have problems or I forgot any steps, feel free to email me at rmacklem@freebsd.org.) First, a bit of background. NFS-over-TLS uses the KERNEL_TLS and will only work on architectures that support a direct map, such as amd64 and aarch64/arm64 (not i386). Then daemons must be running on the NFS server(s) and NFS client(s) for NFS-over-TLS to work, rpc.tlsservd(8) for the server(s) and rpc.tlsclntd(8) for the client(s). You will have to create a X.509v3 certificate for at least the NFS server(s) and, optionally, some or all of the NFS clients. These certificates must each be a pair of files called "cert.pem" and "certkey.pem" for the server and for the first/default one for the client(s). Once created, they need to be copied into a directory called "/etc/rpc.tlsclntd" on the client(s) and "/etc/rpc.tlsservd" on the server(s). (It is possible to have alternate certificates in a client, with file names of .pem and key.pem. For example, if the name that is given by the "tlscertname" NFS mount option is "other", then the files need to be named "other.pem" and "otherkey.pem". For more info on this, see "man mount_nfs" and "man rpc.tlsclntd".) For testing, I would suggest starting with just a default certificate for the client(s) with files named "cert.pem" and "certkey.pem". You can also do some testing with no certificates on the client(s). These files should be owned by "root", with no group/world permissions. In particular, the key files need to be secured to root only access. Although normally the server and client(s) would be different systems, you can use one system for both server and client for testing. This system needs to be configured for both server and client, with both daemons running. There are many ways to create signed certificates for TLS, but here is the simple method I've used for a site local CA, using only the openssl command that is in FreeBSD. I am far from an expert in this area, so there are almost certainly better ways to do this. (Some have mentioned easyrsa in the openVPN software package, but I haven't tried it.) I've been using the openssl1.1.1 shipped with FreeBSD and not the openssl3 installed under /usr/local by /usr/ports/security/openssl-devel. I have only applied this one simple patch to /etc/ssl/openssl.cnf: --- openssl.cnf.sav 2020-03-31 07:41:12.545812000 -0700 +++ openssl.cnf 2020-04-01 10:55:31.682616000 -0700 @@ -66,7 +66,7 @@ name_opt = ca_default # Subject Name options cert_opt = ca_default # Certificate field options # Extension copying option: use with caution. -# copy_extensions = copy +copy_extensions = copy # Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs # so this is commented out by default to leave a V1 CRL. You will probably want to make additional changes to /etc/ssl/openssl.cnf. First, I create a simple subtree of files under a top level directory (I use /root) with the following commands: # mkdir demoCA # cd demoCA # cat /dev/null > index.txt # echo 01 > serial # echo 01 > crlnumber # mkdir private # chmod 700 private # mkdir newcerts Now, I use the following commands to create certifcates and a Certificate Revocation List (CRL). (In the directory above "demoCA".) 1 - Create the Certificate Authority (CA) root key. # openssl genrsa -out demoCA/private/cakey.pem 2 - Create a CA root certificate. # openssl req -new -x509 -key demoCA/private/cakey.pem -out demoCA/cacert.pem --> There will be several questions to answer. As far as I know, you can put just about anything in these fields. Now, you should be ready to create/sign certificates for the NFS server/client(s). 3 - Create a key for the certificate. # openssl genrsa -out certkey.pem (If your openssl-devel is alpha9 or later, you can optionally use the "-aes256" option on the above command for the default client certificates to add a passphrase to the key as protection against the certificate/key being used by an attacker. For alpha8 or earlier, rpc.tlsclntd will crash in the openssl library if you do this.) 4 - Create a Certificate Signing Request (CSR). # openssl req -new -key certkey.pem -addext "subjectAltName=" -out req.pem --> Similar to #2, you will need to answer the questions. The CN must be something different than used for #2. Typically it would be the FQDN of the machine, if it has one. The other fields can be the same as #2 and some (maybe all?) must be the same. is the messy part. The subjectAltName should have all the FQDN name(s) for the machine, if it has any. These are specified via DNS: and are separated by ','s if there are multiple entries. If you are using the "-u" option on the NFS server's rpc.tlsservd and this certificate is for a client where you wish all RPCs to be done as a specific "user" on the NFS server, you also need to put an entry in subjectAltName of the form otherName:1.3.6.1.4.1.2238.1.1.1;UTF8:user@domain. "domain" must match what the NFS server is using for its user name domain. This is usually the FQDN for the server, but without the hostname component. For example, if the NFS server's FQDN is nfsv4-server.uoguelph.ca, the default user name domain is uoguelph.ca. This default can be overridden via the "-n" command line option for rpc.tlsservd. If this client will be mounting multiple NFS servers in different user name domains, there can be multiple otherName entries, one for each of the user name domains. Here are a few examples: For a server with a FQDN of nfsv4-server.uoguelph.ca: # openssl req -new -key certkey.pem -addext "subjectAltName=DNS:nfsv4-server.uoguelph.ca" -out req.pem For a server with two network interfaces, where one reverse DNS resolves to nfsv4-server.uoguelph.ca and the other to nfsv4-server2.uoguelph.ca # openssl req -new -key certkey.pem -addext "subjectAltName=DNS:nfsv4-server.uoguelph.ca,DNS:nfsv4-server2.uoguelph.ca" -out req.pem For a client where you wish all RPCs to be done as the user rmacklem on the above server: # openssl req -new -key certkey.pem -addext "subjectAltName=otherName:1.3.6.1.4.1.2238.1.1.1;UTF8:rmacklem@uoguelph.ca" -out req.pem For a client where you wish all RPCs to be done as the user rmacklem on one NFS server using the name domain of "uoguelph.ca" and all RPCs done as user ricktst on another NFS server using the name domain "rick.home": # openssl req -new -key certkey.pem -addext "subjectAltName=otherName:1.3.6.1.4.1.2238.1.1.1;UTF8:rmacklem@uoguelph.ca,otherName:1.3.6.1.4.1.2238.1.1.1;UTF8:ricktst@rick.home" -out req.pem For a client similar to the above, but has a FQDN of nfsv4-client.uoguelph.ca: # openssl req -new -key certkey.pem -addext "subjectAltName=DNS:nfsv4-client.uoguelph.ca,othername:1.3.6.1.4.1.2238.1.1.1;UTF8:rmacklem@uoguelph.ca" -out req.pem If you want to look at the CSR: # openssl req -in req.pem -noout -text 5 - Sign the CSR with the CA. # openssl ca -in req.pem -out cert.pem (A copy of cert.pem will be kept in demoCA/newcerts with the name .pem.) You can now copy certkey.pem and cert.pem to the directory /etc/rpc.tlsservd on the server(s) or /etc/rpc.tlsclntd on the client(s). If you want to look at any certificate, you can use the command... # openssl x509 -in cert.pem -noout -text For a minimal setup where you do not want certificates in the client(s), all you need to do is #3-5 for each of the NFS servers. If you want certificates for clients, just repeat #3-5 for each of them. If you have created certificates for any of your NFS client(s), you probably want to create a Certificate Revocation List (CRL) as well. The initial file will not have any revocations in it, but can be provided to either/both of the rpc.tlsservd(8) and rpc.tlsclntd(8) daemons, then it can be reloaded by posting a SIGHUP to the daemon(s) when updated. This avoids restarting the daemon(s), which is not a good thing to do while there are NFS-over-TLS mount(s) to the NFS server. 6 - Create a new/empty CRL. # openssl ca -gencrl -out demoCA/crl.pem You can look at this CRL with the command... # openssl crl -in crl.pem -noout -text If you need to revoke a certifcate at some time. # openssl ca -revoke where is the certificate being revoked Then do #6 again and copy it to the NFS server(s) and NFS client(s) that are using it. (More on where it is used further down it this doc.) Now, when will you want certificates for some/all of the client(s)? One case might be laptops. They do not have fixed IP addresses/DNS names, so exports(5) cannot be applied to them easily. You might find that the client having a certificate signed by your CA is sufficient assurance of its identity to allow it to do an NFS mount from any IP address. For this case, you can also set the otherName field of the subjectAltName to "user@domain" so that all RPCs will be performed on the server as "user", if you specify the "-u" command line option for the rpc.tlsservd(8) daemon on the NFS server. (See the above example for "rmacklem@uoguelph.ca" for the exact syntax.) (If you do not want this feature simply do not set the otherName field of subjectAltName or do not set "-u" on the rpc.tlsservd(8) daemon.) Another case might be where you do not trust the client to use the correct IP address when mounting the NFS server, although the client has a well known fixed IP address/DNS name. For this case, you can also set the DNS field of subjectAltName to the FQDN of the client and enable the server to check this via the "-h" option. The FQDN in the client's certificate may have a wildcard "*" in it, depending on what command line options are specified for the server's rpc.tlsservd. For client(s) where you find controlling mount access via the client's IP address using the exports(5) file is sufficient and you are not using the "-u" command line option on the server's rpc.tlsservd, the client does not need to have a certificate. You can still allow/require the client to use TLS so that the RPC traffic is encrypted on the wire. Once you have key(s) and certificate(s) in the /etc/rpc.tlsservd directory on the NFS server(s) and in the /etc/rpc.tlsclntd directory on the NFS client(s), you need to set the appropriate command line option(s) for the daemons. The man pages for rpc.tlsclntd(8) and rpc.tlsservd(8) cover the command line options, but here are a few examples. For an NFS server: (Although these examples show the daemons started via a command line, the options should normally be specified via the tlsclntd_flags/tlsservd_flags line(s) in /etc/rc.conf and then they are started upon boot.) - An NFS server where no clients have certificates. # rpc.tlsservd -v - An NFS server where some/all clients have certificates and you wish to verify them against your site local CA created above. # rpc.tlsservd -v -m -l /root/demoCA/cacert.pem -r /root/demoCA/crl.pem - An NFS server where all clients have certificates and FQDN names that are in the certificates (in either the subjectAltName DNS field or subjectName CN field) and you want to check the client's IP address reverse DNS maps to the FQDN. The FQDN in the client's certificate cannot have a wildcard "*" in it. # rpc.tlsservd -v -m -h -l /root/demoCA/cacert.pem -r /root/demoCA/crl.pem - Similar to the above, but the FQDN in the client's certificate may have a wildcard "*" in it, which will only match a single component of the client's reverse DNS name. For example, an FQDN set to "*.uoguelph.ca" will match "laptop21.uoguelph.ca", but not "laptop3.cis.uoguelph.ca". # rpc.tlsservd -v -m -h -w -l /root/demoCA/cacert.pem -r /root/demoCA/crl.pem - Similar to the above, except that a wildcard "*" in the FQDN can match multiple fields. For example, if the FQDN is set to "*.uoguelph.ca", it would match "laptop3.cis.uoguelph.ca" as well as "laptop21.uoguelph.ca". # rpc.tlsservd -v -m -h -W -l /root/demoCA/cacert.pem -r /root/demoCA/crl.pem - An NFS server where some client(s) have certificates with the otherName field of the subjectAltName set to "user@domain" and you want those clients to use the for "user" in the password database for all RPCs on the connection, ignoring the credentials in the RPC header. # rpc.tlsservd -v -m -u -l /root/demoCA/cacert.pem -r /root/demoCA/crl.pem For an NFS client: - An NFS client without a certificate. # rpc.tlsclntd -v - An NFS client with a certificate and key in /etc/rpc.tlsclntd on the client created by the site local CA above that the server can use for verification. # rpc.tlsclntd -v -m - An NFS client which wants to verify the NFS server's certificate. (This requires that the cacert.pem and crl.pem be copied onto the client from the CA site.) The FQDN in the server's certificate must match the reverse DNS name for the server's IP address and there cannot be a wildcard in the FQDN. # rpc.tlsclntd -v -l -r - An NFS client that has a certificate and key in /etc/rpc.tlsclntd and also wishes to verify the NFS server's certificate as above. # rpc.tlsclntd -v -m -l -r For "-m" it will log failed certificate verifications and for "-v" it will log a lot of other stuff, as well. It will go wherever /etc/syslog.conf directs LOG_DAEMON | LOG_INFO, which is /var/log/daemon.log by default. Once you have set things up, you can add line(s) to your /etc/rc.conf for the daemon(s): For the client: tlsclntd_enable="YES" For the server: tlsservd_enable="YES" - plus tlsclntd_flags and/or tlsservd_flags if you are using command line options for these. For example: tlsclntd_flags="-v -m" Although setting up NFS on FreeBSD is a separate topic, here's a simple example for those not familiar with this. - For NFSv4, choose to either put uids/gids in strings (the Linux default) by adding these two lines to /etc/sysctl.conf: vfs.nfs.enable_uidtostring=1 vfs.nfsd.enable_stringtouid=1 OR - generate "user@domain" strings by adding this line to your /etc/rc.conf: nfsuserd_enable="YES" For a server where you have one file system mounted at /data on the server to mount on the client(s), create a /etc/exports file with the following two lines in it: /data -tls -maproot=root -network 192.168.1.0 -mask 255.255.255.0 V4: /data -tls --> If you want to allow non-TLS mounts as well as TLS mounts, don't use the "-tls" export option. There are also the -tlscert and -tlscertuser export options. Here is the section of "man exports" that describes these. -tls requires that the client use TLS. -tlscert requires that the client use TLS and provide a verifiable X.509 certificate during TLS handshake. -tlscertuser requires that the client use TLS and provide a verifiable X.509 certificate. The otherName component of the certificate's subjAltName must have a an OID of 1.3.6.1.4.1.2238.1.1.1 and a UTF8 string of the form "user@domain". "user@domain" will be translated to the credentials of the specified user in the same manner as nfsuserd(8), where "user" is normally a username is the server's password database and "domain" is the DNS domain name for the server. All RPCs will be performed using these credentials instead of the ones in the RPC header in a manner similar to -mapall=user. - Add these lines to your /etc/rc.conf file: mountd_enable="YES" nfs_server_enable="YES" nfs_server_flags="-t -n 32" nfsv4_server_only="YES" --> If you want to support NFSv3 mounts as well as NFSv4, replace nfsv4_server_only="YES" with nfsv4_server_enable="YES" after rebooting, the NFS server should be running. For NFSv4 client mounts, a command like: # mount -t nfs -o nfsv4,minorversion=1,tls nfsv4-server:/ /mnt should work (nfsv4-server is the DNS name for the server). For an NFSv3 mount, you should to add the following line to your /etc/rc.conf file, although it is not critical: nfs_client_enable="YES" The NFSv3 mount command would look like: # mount -t nfs -o tls nfsv4-server:/data /mnt --> Note that the "/data" path is needed for the NFSv3 mount. Although the kernel NFSv3 client will use TLS, the userland sideband protocols Mount, NSM (rpc.statd) and NLM (rpc.lockd) will not. This may result in interoperability issues someday, if non-FreeBSD servers require that the NFSv3 related protocols use TLS. (To do this, TLS support would need to be added to the Sun RPC functions in libc. I have no intention of doing that at this time.)