Right, let’s talk about securing NFS. The default setup, which relies on hostnames and UID matching, is what I like to call “optimistically insecure.” It trusts the client to tell it who a user is. This is like a nightclub where the bouncer just asks, “You’re on the list, right?” and takes your word for it. It’s fine for a homogenous, trusted network (like a 1995 lab), but in the modern world, it’s a gaping hole. We’re going to fix that by moving from this “host-based” trust to actual user authentication with Kerberos.

The Flaw in the Original Plan: rpcsec_gss and Why UIDs Lie

The classic NFSv3 security model is sys, which uses the client’s report of its user’s UID and GID. The server then blindly trusts these identifiers. The problem is trivial to exploit: root on any client can use sudo -u #1000 to become whoever they want. The server has no way of knowing if the UID 1000 on the client is actually the same human as UID 1000 on the server. This is the core weakness.

The solution is the rpcsec_gss security flavor introduced with NFSv4. Instead of trusting a number from the client, it uses the Kerberos protocol to have the user (or service) cryptographically prove their identity to the server. The server says, “Okay, prove you are joe@EXAMPLE.COM,” and the client provides a Kerberos ticket that only the real Joe could have obtained. Now we’re authenticating the principal, not just a number.

Setting Up the Krb5 Dance Floor (The Prerequisites)

Before a single NFS mount is made, you need a functioning Kerberos realm. I’m assuming you have a KDC (Key Distribution Center) running—something like FreeIPA or a vanilla MIT Kerberos setup. Both your NFS server and all clients must be joined to this realm and have valid keytab files.

First, ensure your krb5.conf is consistent and correct across all machines. An inconsistency here will cause baffling failures that make you question your life choices.

# /etc/krb5.conf on both server and client
[libdefaults]
    default_realm = EXAMPLE.COM
    dns_lookup_realm = false
    dns_lookup_kdc = true
    # Using modern encryption is a very good idea
    permitted_enctypes = aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96

[realms]
    EXAMPLE.COM = {
        kdc = kdc.example.com
        admin_server = kdc.example.com
    }

[domain_realm]
    .example.com = EXAMPLE.COM
    example.com = EXAMPLE.COM

Next, you need principals for your machines and your NFS service. The service principal is crucial and must follow the format nfs/hostname.example.com@REALM. The hostname must be the FQDN that the client uses to connect to the server.

# On the KDC, create the server principal
kadmin: addprinc -randkey nfs/fileserver.example.com

# On the NFS server itself, extract the key to a keytab
root@fileserver:~# apt-get install krb5-user # or your distro's equivalent
root@fileserver:~# kadmin -p admin/admin -q "ktadd nfs/fileserver.example.com"

This creates /etc/krb5.keytab on the server with the key for its NFS service. Do the same for the client’s host principal (host/client.example.com), which is used for the RPCSEC_GSS context establishment.

Server-Side Configuration: /etc/exports with sec=krb5

Now for the magic. In your /etc/exports file, you replace the sec=sys option with a Kerberos security flavor. The main ones are:

  • sec=krb5: Authenticates the client user’s identity (this is the baseline).
  • sec=krb5i: Adds integrity protection via cryptographic checksums, preventing data tampering in transit.
  • sec=krb5p: Adds privacy protection via encryption. This is the whole enchilada.

You should almost always use at least krb5i. The performance hit for integrity is negligible for most uses, and the security benefit is massive. Use krb5p if you’re mounting over an untrusted network.

# /etc/exports on the server
/export/shared  *.example.com(sec=krb5i,rw,sync,no_subtree_check)

After editing /etc/exports, export the shares:

root@fileserver:~# exportfs -rva

Client-Side Mounting: Actually Using the Security

The client must have a valid Kerberos ticket for the user doing the mounting. The mount command is the same, but the options specify the security flavor.

# First, get a ticket for the user
you@client:~$ kinit joe
Password for joe@EXAMPLE.COM:

# Now mount with sec=krb5i
you@client:~$ sudo mount -t nfs4 -o sec=krb5i fileserver.example.com:/export/shared /mnt/nfs

# Verify the mount used the correct security flavor
you@client:~$ mount | grep nfs
fileserver.example.com:/export/shared on /mnt/nfs type nfs4 (rw,relatime,vers=4.2,sec=krb5i,...)

If you get an “Access denied” error, the first place to look is the server’s kernel log (dmesg or /var/log/kern.log). It’s usually brutally honest about what went wrong—often a missing keytab, a mismatched service principal name, or a clock skew greater than 5 minutes (another classic Kerberos pitfall).

The Gotchas: Because Nothing is Ever Simple

  1. Name Mapping: Even with Kerberos, the server still needs to map the principal joe@EXAMPLE.COM to a local UID. This is where idmapd comes in. Ensure /etc/idmapd.conf is configured with your domain (Domain = example.com) on both server and client. If the mapping fails, you’ll end up with “nobody” as the owner.
  2. Firewalls: rpcsec_gss uses a dynamic port. You must open the sunrpc port (111) for rpcbind and the nfs port (2049). Locking it down further requires pinning rpc.gssd to a specific port, which is a pain.
  3. The root Squabble: By default, Kerberized NFS treats the root user as nobody special, which is a security feature. If you absolutely need root access, you must export the share with the no_root_squash option and the client’s root user must have a valid Kerberos ticket for the server’s root principal. This is generally a terrible idea.
  4. Debugging: When it breaks, run rpcdebug -m nfs -s all on both ends to turn on verbose logging. Also, run exportfs -v to see what the server thinks it’s exporting.

The shift to Kerberos is a bit of a headache to set up, I won’t lie. But once it’s running, you have a file-sharing system that doesn’t just trust the network—it verifies every user and can protect every byte of data. It’s what moves NFS from a lab curiosity to a enterprise-ready filesystem.