Traditional NFS contains essentially no security features. NFS assumes that the physical network is secure, and all machines on it are uncompromised. If an attacker has root access to any machine on the network, he can read or write to any location on the NFS file system. To allow NFS to be used on insecure networks, version 4 of that protocol added optional security extensions using Kerberos. This document will describe how to configure FreeBSD to use secure NFS as either a client or a server. There are three steps: authentication, authorization, and NFS.

Authentication

With NFSv4, the problem of authenticating a user is solved by Kerberos. Kerberos is a trusted third party authentication service. An NFS server and an NFS user separately prove their identities to a KDC server, which issues them cryptographically signed tickets asserting their successful authentication. Then the server and user can trust each other. Any secure NFS network must contain a Kerberos KDC server. Configuring Kerberos on FreeBSD is described at https://www.freebsd.org/doc/handbook/kerberos5.html. From Kerberos's perspective, both NFS servers and NFS clients are Kerberos clients. After configuring your NFS machines as Kerberos clients, you must create a static NFS service ticket on any NFS servers. If your KDC server is Heimdal, start kadmin and use these commands:

kadmin> add --random-key --keytab=/tmp/my_nfs_server.keytab nfs/my_nfs_server.mydomain.com
kadmin> ext_keytab nfs/my_nfs_server.mydomain.com

then copy the keytab file to your my_nfs_server and either move it to /etc/krb5.keytab or merge it to an existing /etc/krb5.keytab with one of the following commands:

   1 # Move the temporary keytab file to /etc/krb5.keytab
   2 mv /tmp/my_nfs_server.keytab /etc/krb5.keytab
   3 chown root:wheel /etc/krb5.keytab
   4 chmod 600 /etc/krb5.keytb
   5 # OR, merge the temporary keytab file with an existing /etc/krb5.keytab
   6 ktutil copy /tmp/my_nfs_server.keytab /etc/krb5.keytab
   7 rm /tmp/my_nfs_server.keytab

Authorization

Authentication is the process of determining whether a user is whom says he says he is. Authorization, on the other hand, is the process of determining which operations are allowed for which users. Kerberos does not provide authorization, and NFSv4 does not specify how authorization is to be performed. On FreeBSD, it is performed by the kernel using the traditional UNIX file attributes, but there is a catch: unlike NFSv3, NFSv4 does not transmit UIDs across the wire. Instead, it transmits user identifiers as strings in the format "username@domain". FreeBSD must translate these strings into UIDs, and that is handled by PAM. There are many ways to configure PAM to manage users; here are the most common. As a rule of thumb, if you can do id <username> for any user, then you've successfully configured PAM and NFSv4 will work for that user.

Local users only

The simplest setup is to manage users separately on all machines, using the regular pw, adduser, etc utilities. This method requires no special configuration, but is tedious as changes must be synchronized on multiple machines. In particular, each account must have the same UID on all machines. This method is only practical for the smallest networks.

NIS

NIS is a mature directory service that is well integrated into FreeBSD. If you follow the directions at https://www.freebsd.org/doc/handbook/network-nis.html , then NFSv4 user mapping will work with no further modifications.

ActiveDirectory

ActiveDirectory is a proprietary product from Microsoft that combines Kerberos, LDAP, and other protocols into a single package. It can be used to manage users on networks with mixed Windows and Unix machines. From FreeBSD's perspective, ActiveDirectory is both the KDC and LDAP server. To use ActiveDirectory with Kerberos, add these lines to the [libdefaults] section of /etc/krb5.conf on every machine. Your Windows Domain is identical to your Kerberos Realm.

default_realm = <MY_WINDOWS_DOMAIN>
dns_lookup_realm = true
dns_lookup_kdc = true
forwardable = yes

As described above, you will need to generate a static NFS service ticket. This is significantly different than with Heimdal. Follow these instructions:

  1. Using ActiveDirectory's GUI, create a Computer account named nfs<SERVERNAME>. For example, if your NFS server is named frank.example.com, create a Computer account named nfsFrank.

  2. From the Windows CLI, run ktpass -princ nfs/<FQDN>@<REALM_DOMAIN> mapuser <REALM>\<ACCOUNT>$ +rndPass -out <ACCOUNT>.keytab. For example, if your NFS server is named frank.example.com and your Windows Domain is "EXAMPLE.COM", you would run ktpass -princ nfs/frank.example.com@EXAMPLE.COM mapuser EXAMPLE\nfsFrank$ +rndPass -out nfsFrank.keytab

  3. Transfer the temporary keytab file to the NFS server
  4. As described above, move or merge the temporary keytab file to /etc/krb5.keytab.

TODO: describe how to connect PAM to ActiveDirectory for user id mapping

NFS

Strictly speaking, we haven't been dealing with NFS at all up until this point. Once Kerberos and PAM are configured, NFS can be configured like normal according to nfsv4(4), exports(5), and mount_nfs(8). Unlike NFSv3, with Kerberized NFSv4 each user (not system) must have a Kerberos ticket in order to access the NFS file system. On a FreeBSD client, type "kinit" to check out a Kerberos ticket. The user who performs the mount must also have a Kerberos ticket. Optionally, you can use the static service ticket for mounting. This way, you can mount at boot time and the mount will stay available for as long as the static service ticket is valid (usually forever). To do this, use the gssname option in your client's /etc/fstab file.

Security Flavors

NFSv4 supports four flavors of security. Increasing levels provide more security but impose a performance penalty. You must choose the flavor appropriate for your installation. Security flavors are specified in /etc/exports on a per-export basis. That means they may vary per export, and also per client IP or network. The four flavors are:

sys

System-provided security. This is identical to NFSv3's security model. If you're reading this guide, then you probably don't want sec=sys.

krb5
Kerberos authentication. With this flavor, all RPC headers are cryptographically signed with the requestor's Kerberos ticket. This ensures that an unauthenticated attacker cannot access the NFS server. However, krb5 is vulnerable to man-in-the-middle attacks. krb5 is a good choice for networks that are secure and reliable, but with untrusted endpoints.
krb5i
Kerberos authentication and integrity. With this flavor, not only are RPC headers cryptographically signed, but the header also contains a secure hash of the contents of the RPC's payload. This ensures that corrupted or altered requests will not be accepted by the server, and corrupted and altered responses will not be accepted by the client. krb5i is robust against man-in-the-middle attacks, but provides no privacy from passive eavesdroppers; all RPC payloads are transmitted in the clear. krb5i is a good choice for networks that are secure but want robustness against accidental corruption. It can also be used by underpriveleged clients on insecure networks. For example, the NFS server may export sensitive files with krb5p, but use krb5i for insensitive files to improve performance.
krb5p
Kerberos authentication, integrity, and privacy. This is the most secure flavor of NFS. Not only does it provide authentication and integrity, but the entire RPC payload is encrypted. Thus a passive eavesdropper can see nothing but RPC headers. krb5p is a good choice for insecure networks, including wireless networks.

Tips

vfs.nfsd.issue_delegations=1

Troubleshooting

The client can mount a share, but ls shows it to be empty, and dmesg shows nfsv4 client/server protocol prob err=10020

The server has mounted or unmounted its exports after starting mountd. The solution is to restart mountd.

A linux client says Remote I/O error during mount, and a packet trace shows that the server returned NFS4ERR_SERVERFAULT

Some linux clients seem to request krb5i even if you try to use plain krb5. Try setting sec=krb5,krb5i in the server's exports file.

KerberizedNFS (last edited 2017-03-17 03:01:17 by AlanSomers)