Search

moon
Creative Commons License powered by blosxom valid xhtml 1.1 valid css FreeBSD Vim

 BREADCRUMBS: /home/weblog

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.

timestamp: 2005-01-10 12:04
URL:http://lizard.org.uk/weblog/freebsd/nfs-server.html