Secure NFS
My usual answer to the question, "How do I secure an NFS server?" is to not run NFS. Really. NFS stands for No Fucking Security. Which is why I'll only ever install NFS servers on totally closed private networks. But recently I had no choice - I had to run NFS and the box had to have a public IP.
I installed 5.3-RELEASE the same way as I usually do, with the exception that I allowed sysinstall to enable the NFS Server. This added the following to /etc/rc.conf:
nfs_server_enable="YES" rpcbind_enable="YES"
A look at sockstat showed the following NFS related listening going on:
root nfsd 377 3 tcp4 *:2049 *:* root nfsd 377 4 tcp6 *:2049 *:* root mountd 375 4 udp4 *:1006 *:* root mountd 375 5 tcp4 *:888 *:* root mountd 375 6 udp6 *:1005 *:* root mountd 375 7 tcp6 *:887 *:* root rpcbind 308 4 udp6 *:* *:* root rpcbind 308 5 stream /var/run/rpcbind.sock root rpcbind 308 6 udp6 *:111 *:* root rpcbind 308 7 udp6 *:1023 *:* root rpcbind 308 8 tcp6 *:111 *:* root rpcbind 308 9 udp4 *:111 *:* root rpcbind 308 10 udp4 *:862 *:* root rpcbind 308 11 tcp4 *:111 *:*
Rather horrific really. But it's not all bad. A quick look in /etc/defaults/rc.conf and a read of the corresponding man pages and I discover that I can bind nfsd and rpcbind to a single IP, and mountd can be told to bind to a specific port and to use libwrap. So now the /etc/rc.conf entries look like this:
nfs_server_enable="YES" nfs_server_flags="-u -t -n 4 -h 172.16.0.1" rpcbind_enable="YES" rpcbind_flags="-h 172.16.0.1 -l" mountd_enable="YES" mountd_flags="-r -p 888"
Thankfully all the hosts that will be accessing this box are on the same subnet - hence the private IP alias. A sockstat now (after a reboot) tells me:
root nfsd 368 3 tcp4 172.16.0.1:2049 *:* root mountd 360 4 udp4 *:888 *:* root mountd 360 5 tcp4 *:888 *:* root mountd 360 6 udp6 *:888 *:* root mountd 360 7 tcp6 *:888 *:* root rpcbind 308 4 udp6 *:* *:* root rpcbind 308 5 stream /var/run/rpcbind.sock root rpcbind 308 6 udp6 ::1:111 *:* root rpcbind 308 7 udp6 *:* *:* root rpcbind 308 8 udp6 *:1023 *:* root rpcbind 308 9 tcp6 *:111 *:* root rpcbind 308 10 udp4 127.0.0.1:111 *:* root rpcbind 308 11 udp4 172.16.0.1:111 *:* root rpcbind 308 12 udp4 *:862 *:* root rpcbind 308 13 tcp4 *:111 *:*
Mildly better, but rpcbind is still talking to the outside world. A fact shown by running rpcinfo from a remote host:
# rpcinfo -p nfsbox
program vers proto port service
100000 4 tcp 111 rpcbind
100000 3 tcp 111 rpcbind
100000 2 tcp 111 rpcbind
100000 4 udp 111 rpcbind
100000 3 udp 111 rpcbind
100000 2 udp 111 rpcbind
100000 4 local 111 rpcbind
100000 3 local 111 rpcbind
100000 2 local 111 rpcbind
100005 1 udp 888 mountd
100005 3 udp 888 mountd
100005 1 tcp 888 mountd
100005 3 tcp 888 mountd
100003 2 udp 2049 nfs
100003 3 udp 2049 nfs
100003 2 tcp 2049 nfs
100003 3 tcp 2049 nfs
A quick change to /etc/hosts.allow like so:
# Secure the port mapper rpcbind : 172.16.0.0/255.255.255.0 : allow rpcbind : ALL : deny
Shows libwrap is doing it's job:
# rpcinfo -p nfsbox rpcinfo: can't contact portmapper: RPC: Authentication error; why = Client credential too weak
Now, having done all I can to make NFS inherently secure, the next step is to throw a firewall around the whole thing. Easily done. Just add this to /etc/rc.conf:
firewall_enable="YES" firewall_script="/etc/rc.firewall" firewall_type="/etc/ipfw.rules" firewall_quiet="NO" #change to YES once happy with rules firewall_logging_enable="NO"
Create /etc/ipfw.rules:
add 010 allow ip from 172.16.0.0/24 to any add 100 set 10 unreach 3 udp from any to any 111 add 110 set 10 unreach 3 udp from any to any 888 add 120 set 10 unreach 3 udp from any to any 2049 add 210 set 10 reset tcp from any to any 111 add 220 set 10 reset tcp from any to any 888 add 230 set 10 reset tcp from any to any 2049 add 65534 allow ip from any to any
And start ipfw:
/etc/rc.d/ipfw start
A word of caution about /etc/ipfw.rules, one error anywhere in the file and no rules are loaded. As the default rule is to deny everything this can lead to embarrassment. Especially when you do it twice and the box in question resides in a data centre to which you don't have access...
With NFS secure all that remains is to edit /etc/exports export the filesystems I need:
/export -alldirs -maproot=0 172.16.0.2
Getting mountd to recognise the canges is simple too:
killall -HUP mountd
Job done - once I've tested the client can mount it of course.





