Configuring and firewalling a static port NFS server


Updated: 2016-12-12

NFS has very basic security checks - up till v3, it relies on IP whitelists, from v4 on you can use the Kerberos protocol for security. We'll be looking at a default standard NFS v3/v4 setup, with just the regular whitelisting in /etc/exports. I assume you already have this set up.

Setting static ports

In its default configuration, NFS does not allow for easy firewalling - its daemons don't use fixed ports. The ports you pick can be as random as you wish; just make sure they don't conflict with what's already defined in /etc/services. For easier firewalling, I use a range going from 4000 to 4004 for all daemons without a fixed port.

Let's start with the statd daemon. Configure /etc/default/nfs-common like this:

STATDOPTS="--port 4000 --outgoing-port 4001"

So that's two ports taken. Now for mountd, edit /etc/default/nfs-kernel-server:

RPCMOUNTDOPTS="--manage-gids --port 4002"

You can assign a fixed port to quotad as well, but chances are you won't be using it. Debian doesn't install the package by default either. If you don't know what it is, then you're definitely not using it.

For lockd and the NFS callback TCP port, you'll either need to set the ports through modprobe or with sysctl.

  • Modprobe

    Create a file called /etc/modprobe.d/nfs.conf and add this:

    options lockd nlm_udpport=4003 nlm_tcpport=4003
    options nfs callback_tcpport=4004
    
  • Sysctl

    Create a file called /etc/sysctl.d/nfs.conf and add this:

    fs.nfs.nlm_udpport=4003
    fs.nfs.nlm_tcpport=4003
    fs.nfs.nfs_callback_tcpport=4004
    

Some of the modules (lockd or nfs) are probably in use, so reboot to get all the ports in the 4000 range.

Now let's have a look at how NFS is behaving. As you can see below, it's all nicely in the 4000-4004 range. The portmapper's default port is 111, we're not touching this.

$ sudo rpcinfo -p|uniq -f 2
program vers proto   port  service
100000    4   tcp    111  portmapper
100000    4   udp    111  portmapper
100024    1   udp   4000  status
100024    1   tcp   4000  status
100003    2   tcp   2049  nfs
100227    2   tcp   2049
100003    2   udp   2049  nfs
100227    2   udp   2049
100021    1   udp   4003  nlockmgr
100021    1   tcp   4003  nlockmgr
100005    1   udp   4002  mountd
100005    1   tcp   4002  mountd
100005    2   udp   4002  mountd
100005    2   tcp   4002  mountd
100005    3   udp   4002  mountd
100005    3   tcp   4002  mountd

Firewalling the NFS server

With the static ports in place, firewalling the server is a piece of cake. I previously discussed setting up iptables when a network interface is brought up, so I won't cover that again. Instead, here are the rules you'd need to open up the necessary ports in the firewall. Keep in mind iptables implements the first matching rule, so if e.g. you'd like to deny a single host in your LAN access to NFS, make sure to blacklist it before you grant full access to the LAN.

Input:

# iptables -A INPUT  -s 192.168.1.0/24 -p tcp -m multiport --dports 111,2049,4000:4004 -m state --state NEW,ESTABLISHED -j ACCEPT
# iptables -A INPUT  -s 192.168.1.0/24 -p udp -m multiport --dports 111,2049,4000:4004 -m state --state NEW,ESTABLISHED -j ACCEPT

If you restrict NFS traffic further (e.g. only allow traffic that is actually headed for the server), you need to open UDP port 111 so NFS browsing (which probes the whole subnet) keeps working:

# -A INPUT  -s 192.168.1.0/24 -d 192.168.1.255 -p udp --dport 111 -m state --state NEW -j ACCEPT

Output:

# iptables -A OUTPUT -d 192.168.1.0/24 -p tcp --sport 111,2049,4000:4004 -m state --state ESTABLISHED -j ACCEPT
# iptables -A OUTPUT -d 192.168.1.0/24 -p udp --sport 111,2049,4000:4004 -m state --state ESTABLISHED -j ACCEPT

If you want to see if any traffic gets blocked, you can add a logging rule. There are multiple log levels; I've found level 4 outputs to /var/log/messages, whereas level 7 gets dumped in dmesg.

#  iptables -A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 4

Adding the fixed ports to /etc/services (optional)

This really is optional, but when calling netstat it will show you something human-readable and not just port numbers. So for some added fanciness, insert something like this into /etc/services below the NFS entries:

# Statically set NFS ports
rpc.statd       4000/tcp
rpc.statd       4000/udp
rpc.statd       4001/tcp
rpc.statd       4001/udp
rpc.mountd      4002/tcp
rpc.mountd      4002/udp
rpc.lockd       4003/tcp
rpc.lockd       4003/udp

Without the names, this is what the netstat output would look like:

# netstat -4 -puntal|grep -e 2049 -e 400
tcp        0      0 0.0.0.0:111             0.0.0.0:*               LISTEN      941/rpcbind     
tcp        0      0 0.0.0.0:4000            0.0.0.0:*               LISTEN      950/rpc.statd   
tcp        0      0 0.0.0.0:2049            0.0.0.0:*               LISTEN      -               
tcp        0      0 0.0.0.0:4002            0.0.0.0:*               LISTEN      1101/rpc.mountd 
tcp        0      0 0.0.0.0:4003            0.0.0.0:*               LISTEN      -               
udp        0      0 0.0.0.0:2049            0.0.0.0:*                           -               
udp        0      0 0.0.0.0:4000            0.0.0.0:*                           950/rpc.statd   
udp        0      0 0.0.0.0:4002            0.0.0.0:*                           1101/rpc.mountd 
udp        0      0 0.0.0.0:4003            0.0.0.0:*                           -               
udp        0      0 0.0.0.0:111             0.0.0.0:*                           941/rpcbind

With the names added:

# netstat -4 -putal|grep -e rpc -e nfs
tcp        0      0 *:sunrpc                *:*                     LISTEN      941/rpcbind     
tcp        0      0 *:rpc.statd             *:*                     LISTEN      950/rpc.statd   
tcp        0      0 *:nfs                   *:*                     LISTEN      -               
tcp        0      0 *:rpc.mountd            *:*                     LISTEN      1101/rpc.mountd 
tcp        0      0 *:rpc.lockd             *:*                     LISTEN      -               
udp        0      0 *:nfs                   *:*                                 -               
udp        0      0 *:rpc.statd             *:*                                 950/rpc.statd   
udp        0      0 *:rpc.mountd            *:*                                 1101/rpc.mountd 
udp        0      0 *:rpc.lockd             *:*                                 -               
udp        0      0 *:sunrpc                *:*                                 941/rpcbind

That's it.