Configuring and firewalling a static port NFS server
Published: 2014-12-18Updated: 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.