In past tips we've looked at using Kerberos and how to authenticate various services with it, and recently looked at setting up an NFS server on Linux. This week we will be looking at tying the two together to get the better performance and security of NFSv4 in a kerberized environment. Hold on, there is a lot to do! And while it may look daunting, it shouldn't take very long to get everything set up and working properly.
This tip assumes you have a working Kerberos environment, a working NFS server, and a little bit of patience. It also assumes you are using a Red Hat Enterprise Linux or Fedora distribution; other Linux distros will have similar options although certain things like NFS or firewall settings will likely be done in different files.
To start with, we need to set up our top-level NFSv4 export directory. This is a "root" container, of sorts, where we can bind other mount points to it as subdirectories. In this example, we'll create /exports/ to be our top-level exported filesystem, and make the local /srv/ directory available through it:
# mkdir /exports
# chmod 1777 /exports
# mount --bind /srv /exports/srv
What this does is remounts /srv to /exports/srv. Effectively, this means that /srv can be accessed directly, or via /exports/srv and changes in one location reflect in the other.
To make this persistent, add the mount command above to /etc/rc.d/rc.local or some similar executed-at-boot script.
Next, edit /etc/sysconfig/nfs and enable the SECURE_NFS option:
Then edit /etc/exports and change old NFSv3-style exports to newer NFSv4-style exports. For example, an old /etc/exports might look like:
We want to change this to:
The first thing to note is that the "/exports" entry has the "fsid=0" option, which tells NFS that this is the "root" export, which we created earlier.
Subsequent directories (those disparate directories mounted beneath it, such as /srv, which we had re-mounted beneath /exports earlier), cannot have "fsid=0" in their options; instead we use "nohide" here, so that they do not need to be explicitly mounted, but become mounted as part of one mount call to the "root" export by the NFS clients.
You can also opt to use regular krb5, which is for authentication only, or krb5i (gss/krb5i) for integrity checking, or krb5p (gss/krb5p) for encryption. There is a performance penalty for krb5i and krb5p, but if you are on a semi-trusted or untrusted network, the integrity and full encryption options may be worth the performance cost.
Create the server principal for the NFS server and add it to the keytab file on the server using kadmin (usually /etc/krb5.keytab):
Authenticating as principal root/admin@DOMAIN.COM with password.
kadmin.local: addprinc -randkey nfs/nfsserver.domain.com
WARNING: no policy specified for nfs/nfsserver.domain.com@DOMAIN.COM; defaulting to no policy
Principal "nfs/nfsserver.domain.com@DOMAIN.COM" created.
kadmin.local: ktadd -e des-cbc-crc:normal -k /etc/krb5.keytab nfs/nfsserver.domain.com
Entry for principal nfs/nfsserver.domain.com with kvno 5, encryption type Triple DES cbc mode with HMAC/sha1 added to keytab WRFILE:/etc/krb5.keytab.
Entry for principal nfs/nfsserver.domain.com with kvno 5, encryption type ArcFour with HMAC/md5 added to keytab WRFILE:/etc/krb5.keytab.
Entry for principal nfs/nfsserver.domain.com with kvno 5, encryption type DES with HMAC/sha1 added to keytab WRFILE:/etc/krb5.keytab.
Entry for principal nfs/nfsserver.domain.com with kvno 5, encryption type DES cbc mode with RSA-MD5 added to keytab WRFILE:/etc/krb5.keytab.
Edit /etc/idmapd.conf and make sure the Nobody-User and Nobody-Group options are correct (i.e. on Red Hat Enterprise Linux and Fedora, use the "nfsnobody" user and group, other distributions may just use "nobody"). Also make sure that the Domain entry is properly set to your DNS domain name.
Next, restart the NFS services:
# service nfs restart
# service rpcidmapd restart
If you are using a firewall on the server, be sure to open TCP port 2049 for use with NFsv4.
Next, it is time to configure the clients. On the client system, edit /etc/sysconfig/nfs and enable SECURE_NFS as we did on the server. Next, you need to run kadmin which means you will need to authenticate to Kerberos. If the root user on the client does not have a Kerberos account, you will need to copy the existing /etc/krb5.keytab file to the user's directory that does have administrative privileges and manipulate the file as that user:
# cp /etc/krb5.keytab ~user/
# chmod 600 ~user/krb5.keytab
# chown user:user ~user/krb5.keytab
Couldn't open log file /var/log/kadmind.log: Permission denied
Authenticating as principal user/admin@DOMAIN.COM with password.
Password for user/admin@DOMAIN.COM:
kadmin: addprinc -randkey nfs/nfsclient.domain.com
WARNING: no policy specified for nfs/nfsclient.domain.com@DOMAIN.COM; defaulting to no policy
Principal "nfs/nfsclient.domain.com@DOMAIN.COM" created.
kadmin: ktadd -k /home/user/krb5.keytab nfs/nfsclient.domain.com
Entry for principal nfs/nfsclient.domain.com with kvno 4, encryption type Triple DES cbc mode with HMAC/sha1 added to keytab WRFILE:/home/user/krb5.keytab.
Entry for principal nfs/nfsclient.domain.com with kvno 4, encryption type ArcFour with HMAC/md5 added to keytab WRFILE:/home/user/krb5.keytab.
Entry for principal nfs/nfsclient.domain.com with kvno 4, encryption type DES with HMAC/sha1 added to keytab WRFILE:/home/user/krb5.keytab.
Entry for principal nfs/nfsclient.domain.com with kvno 4, encryption type DES cbc mode with RSA-MD5 added to keytab WRFILE:/home/user/krb5.keytab.
$ sudo su -
# cd ~user
# chown root:root krb5.keytab
# chmod 600 krb5.keytab
# mv krb5.keytab /etc/
And then restart (or start) the NFS client services, and make sure they will start at the next boot:
# service rpcidmapd restart
# service rpcgssd restart
# chkconfig rpcidmapd on
# chkconfig rpcgssd on
Then make the directory that the remote NFS export will be mounted to:
# mkdir /nfsserver
At this point, you can edit /etc/fstab. Because NFSv4 changes how things are called, you are requesting to mount the root ('/') of the server, as opposed to a specific path (i.e., /exports/srv/). This is why it is important to have one exported directory and bind any additional mounts under that tree. The /etc/fstab will contain something like this:
nfsserver.domain.com:/ /nfsserver nfs4 rw,hard,intr,sec=krb5 0 0
And try to mount it:
# mount -v /nfsserver
mount.nfs4: timeout set for Thu Oct 14 15:55:24 2010
mount.nfs4: trying text-based options 'hard,intr,sec=krb5,addr=192.168.1.14,clientaddr=192.168.1.52'
nfsserver.domain.com:/ on /nfsserver type nfs4 (rw,hard,intr,sec=krb5)
Now, as root, you will be able to see the contents of the mount point (/nfsserver), but as a regular user you will be unable to, until you kinit:
klist: No credentials cache found (ticket cache FILE:/tmp/krb5cc_501)
$ ls /nfsserver/
ls: cannot access /nfsserver/: Permission denied
Password for user@DOMAIN.COM:
$ ls /nfsserver/
Ticket cache: FILE:/tmp/krb5cc_501
Default principal: user@DOMAIN.COM
Valid starting Expires Service principal
10/14/10 15:54:53 10/15/10 15:54:53 krbtgt/DOMAIN.COM@DOMAIN.COM
renew until 10/21/10 15:54:53
10/14/10 15:54:57 10/15/10 15:54:53 nfs/nfsserver.domain.com@DOMAIN.COM
renew until 10/21/10 15:54:53
At this point, you will be able to access the remote NFSv4 server using Kerberos credentials. Before NFSv4, security on NFS was pretty much non-existant. You could prevent unauthorized machines from connecting to NFS exports, but had to rely on user ID mappings being the same between systems to use the server's permissions to adequately protect files. Using Kerberos in this manner makes NFS much more secure than it used to be.
Vincent Danen works on the Red Hat Security Response Team and lives in Canada. He has been writing about and developing on Linux for over 10 years and is a veteran Mac user.