Securing NFSv4 with SSH port forwarding
About
We store our family photos on a Network Attached Storage (NAS) server. There are several available protocols for securely sharing these photos on the home network. I have implemented an architecture based on the Network File System (NFS) protocol. Using NFS in 2022 may seem outdated, but for our use case it’s sufficient.
NOTE:
For now, the architecture depends on SSH port forwarding. In the future, I plan to implement native NFSv4 security features.
The Network File System (NFS) protocol
NFS is a distributed file system protocol used by clients to access files on a remote NFS server. NFS is an old protocol. Version 2 was defined in 1989, and the latest version, NFS 4.2, was published in 2016. The NFS design goals were performance, simplicity, and cross-vendor compatibility. A secure NFS architecture, however, is somewhat complex, and requires a good understanding of the protocol.
When NFSv4 was released in 2000 it was virtually a rewrite of NFS and introduced multiple changes. Most notably, a greater emphasis on security. Also, NFSv4 changed the default transport protocol to TCP, and integrated file locking and the mount protocol into NFS. In addition, when using NFSv4, it is not necessary to use the RPC binding protocols like portmappper
.
NFSv4 is defined in RFC7530 - Network File System (NFS) Version 4 Protocol.
NFSv4 security features
Traditionally, an NFS client has to satisfy two requirements to gain access to exported files on a remote NFS server:
- mount access
- file access
First, NFS restricts which clients that are permitted to mount file systems, by IP address or by host name. Thus, from an authentication perspective, the NFS server relied on the client to authenticate the end-user. Second, the NFS server enforces file system permissions for the end-user. The end-user’s effective user ID and group ID are used to check access to the requested files.
These requirements are implemented in the AUTH_SYS
(or AUTH_UNIX
) security flavour. AUTH_SYS
is the default security flavor for all versions of NFS.
NFS network communication is plain-text by default.
As mentioned in RFC1813 - NFS Version 3 Protocol Specification (8.Security Considerations)
As with the previous protocol revision (version 2), NFS version 3 defers to the authentication provisions of the supporting RPC protocol [RFC1057], and assumes that data privacy and integrity are provided by underlying transport layers as available in each implementation of the protocol.
Note: NFSv4 also exchange information in plain-text when using AUTH_SYS
.
RPC security
The NFS protocol makes use of Remote Procedure Calls (RPC). Using RPC, a client calls a procedure on a remote host across the network. Such procedures could be open
(opens a regular file), or read
(reads data from a file on remote server, and returns the content to the client). For NFSv2 and NFSv3, RPC implementations have included AUTH_NONE
, AUTH_SYS
, AUTH_DH
, and AUTH_KRB4
as security flavors.
For NFSv4, the RPCSEC_GSS
(RFC4121) security flavor was added to secure NFS server operations. RPCSEC_GSS
uses functionality of GSS-API
(RFC2743), and introduces a security model which provides end-to-end authentication. The end-user on the client mutually authenticates to a principal on an NFS server.
NFSv4 may support multiple security mechanisms. NFSv4 servers and clients must support the Kerberos V5 framework which provides authentication, integrity, and privacy. Details in RFC7530 - 3.2.1.1. Kerberos V5 as a Security Triple
AUTH_SYS security considerations
Based on your threat model, the AUTH_SYS
security flavor may not provide sufficient security.
According to RFC5531 - RPC: Remote Procedure Call Protocol Specification Version 2:
AUTH_SYS as described in Appendix A is known to be insecure due to the lack of a verifier to permit the credential to be validated. AUTH_SYS SHOULD NOT be used for services that permit clients to modify data.
The alternative: SSH port forwarding
I have yet to implement RPCSEC_GSS
on my NAS. An alternative solution is to use SSH port forwarding in combination with AUTH_SYS
to protect the authenticity, integrity and confidentiality of NFS server operations.
This blog post describes how to implement NFSv4 + SSH Port Forwarding.
Exported filesystems (/etc/exports)
The NFS server defines remote mounts points and security parameters in /etc/exports
:
V4: <NFSv4 root path on server> -sec=<security flavor> <ip address>
<directory path on server> -mapall=<uid> <ip address>
From a security perspective, the interesting parameters are:
-sec=<security flavor>
<ip address>
-mapall=<uid>
The first component, <NFSv4 root path on server>
, defines the NFSv4 tree root. This parameter is used in combination with <directory path on server>
to export NFSv4 mount points.
The second component, -sec=
and -mapall=<uid>
, configures the security flavour and sets a mapping for all client UIDs (including root) to an UID on the NFS server. The third component (<ip address>
), specifies the host to which the line applies.
Additional configuration options are described in man page exports(5)
The alternative: sharing filesystems using ZFS
ZFS supports sharing datasets. Currently, I prefer to use /etc/exports
due to old habits.
Additional details in man page zfs-share(8)
Access control lists (ACLs)
To access files on an NFS share, the end-user must have the required file system permissions. On FreeBSD, the ACLs can be defined as Access Controls Lists (POSIX®.1e compatible) or NFSv4 ACL.
NFSv4 ACLs are based on NT-style ACLs, and provide a more granular set of access privileges. FreeBSD has extended setfacl
/getfacl
to include functionality for NFSv4 ACLs.
The illumos ZFS Administration Guide has more details on NFSv4 ACLs.
Firewalling
NFSv2 and NFSv3 comprised several separate daemons:
- nfsd (
2049/udp
and2049/tcp
) - rpcbind (
111/udp
and111/tcp
) - mountd (
<mountd_port>/udp
and<mountd_port>/tcp
) - statd (
<statd_port>/udp
and<statd_port>/tcp
) - lockd (
<lockd_port>/udp
and<lockd_port>/tcp
)
NFSv4 simplifies firewall configuration by only requiring 2049/tcp
to be accessible to clients.
The alternative: SSH port forwarding
When using SSH port forwarding, all the aforementioned ports should be blocked in the firewall. The SSH protocol requires that 22/tcp
is accessible to clients.
NFS configuration on NAS server
The NAS server is running FreeBSD 13.
To configure a NFS server that supports NFSv4 only, the following variables are required in /etc/rc.conf
# /etc/rc.conf
...
# NFS
nfs_server_enable="YES"
nfsv4_server_enable="YES"
nfsv4_server_only="YES"
nfsuserd_enable="YES"
mountd_enable="YES"
rpc_lockd_enable="NO"
rpc_statd_enable="NO"
rpcbind_enable="NO"
...
Start and verify nfs services
# Restart nfs and mountd
root@nas: [/root]# service nfsd restart && service mountd restart
Stopping nfsd.
Waiting for PIDS: 953 956.
Starting nfsd.
Stopping mountd.
Waiting for PIDS: 946.
NFSv4 only server
Starting mountd.
root@nas: [/root]#
# Verify running daemon
root@nas: [/root]# sockstat -l | egrep '2049'
root nfsd 4384 5 tcp4 *:2049 *:*
root nfsd 4384 6 tcp6 *:2049 *:*
root@nas: [/root]#
# Verify running mountd
root@nas: [/root]# ps aux | grep -i mount
root 4406 0.0 0.0 12912 2580 - Is 10:35 0:00.00 /usr/sbin/mountd -r -S -R /etc/exports /etc/zfs/exports
root 4431 0.0 0.0 4676 2172 0 R+ 10:36 0:00.01 grep -i mount
root@nas: [/root]#
The mountd
daemon is started with -R
since the mount protocol is not used by NFSv4.
Exporting the file systems
The file systems on the NAS server is exported using NFSv4, Thus, ZFS sharenfs
is set to off
.
root@nas: [/root]# zfs get -p sharenfs zdata/photos
NAME PROPERTY VALUE SOURCE
zdata/photos sharenfs off default
root@nas: [/root]#
The shared file systems are defined in /etc/exports
:
# /etc/exports
V4: /zdata/photos/family/ -sec=sys 127.0.0.1
/zdata/photos/family/lightroom -mapall=1088 127.0.0.1
Note:
The authorized client IP is 127.0.0.1
. When using SSH port forwarding, the client connects to NFS from a local IP address.
Every end-user on the client is mapped to a local NAS user account, photos-mac
.
root@nas: [/root]# cat /etc/exports
photos-mac:\*:1088:1088:photos-mac:/home/photos-mac:/usr/local/libexec/git-core/git-shell
root@nas: [/root]#
Define access control lists
The file system permissions are enforced using NFSv4 ACL. Thus, the acltype
is set to nfsv4
.
root@nas: [/root]# zfs get -p acltype zdata/photos
NAME PROPERTY VALUE SOURCE
zdata/photos acltype nfsv4 default
root@nas: [/root]#
root@nas: [/root]# mount -v | egrep 'zdata/photos'
zdata/photos on /zdata/photos (zfs, NFS exported, local, nfsv4acls, fsid eebb0c06dec104a6)
root@nas: [/root]#
Grant read
, write
, append
and delete
permissions on all files and directories in the family photos directory:
# Grant read, write, append and delete permissions
root@nas: [/root]# setfacl -m u:photos-mac:rx::allow /zdata/
root@nas: [/root]# setfacl -m u:photos-mac:rx::allow /zdata/photos/
root@nas: [/root]# setfacl -m u:photos-mac:rx::allow /zdata/photos/family/
root@nas: [/root]# setfacl -m u:photos-mac:rx::allow /zdata/photos/family/lightroom/
root@nas: [/root]# setfacl -R -m u:photos-mac:rwxpdaARc::allow /zdata/photos/family/lightroom/
# Verify permissions
root@nas: [/root]# getfacl /zdata/photos/family/lightroom/Masters/
# file: /zdata/photos/family/lightroom/Masters/
# owner: root
# group: wheel
user:photos-mac:rwxp-daAR-c---:-------:allow
owner@:rwxp--aARWcCos:-------:allow
group@:r-x---a-R-c--s:-------:allow
everyone@:r-x---a-R-c--s:-------:allow
root@nas: [/root]#
The parameters are described in man page setfacl(1)
.
Connect from client to NAS server
The client is running macOS and has a regular user account photos
. This user establishes a SSH forwarding tunnel, and mounts the exported NFS share as a local file system:
# Set up a SSH forwarding tunnel
photos@Mac-mini ~ % ssh -fN -L 3049:localhost:2049 photos-mac@192.168.1.222
Enter passphrase for key '/Users/photos/.ssh/id_rsa':
photos@Mac-mini ~ %
# Verify tunnel
photos@Mac-mini ~ % netstat -na | egrep '192.168.1.222.22'
tcp4 0 0 192.168.1.122.53313 192.168.1.222.22 ESTABLISHED
photos@Mac-mini ~ % nc -z -v localhost 3049
Connection to localhost port 3049 [tcp/nsws] succeeded!
photos@Mac-mini ~ %
The -N
switch instructs ssh to not execute a remote command. The -f
option backgrounds ssh.
The -L
option tunnels a local application port on the client to a port on a remote server machine.
After establishing the SSH tunnel, the end-user can mount the NFS share:
# Mount NFS share on client
photos@Mac-mini ~ % mount -v -t nfs -o port=3049,vers=4 localhost:/lightroom /Users/photos/mnt
localhost:/lightroom on /Users/photos/mnt (nfs, nodev, nosuid, mounted by photos)
photos@Mac-mini ~ %
# Verify NFS share access
photos@Mac-mini ~ % cd mnt
photos@Mac-mini mnt % ls -la
total 81
drwx------ 4 root wheel 7 Aug 1 15:13 .
drwxr-x---+ 23 photos staff 736 Aug 1 18:48 ..
-rw-r--r-- 1 root wheel 14340 May 15 15:28 .DS_Store
-rw-r--r-- 1 root wheel 0 Jan 24 2014 .localized
drwxr-xr-x 15 root wheel 16 Jul 31 11:37 Masters
photos@Mac-mini mnt %
photos@Mac-mini mnt % file Masters/2022/2022-01-03/P1090547.RW2
Masters/2022/2022-01-13/P0000000.RW2: data
photos@Mac-mini mnt %
Security considerations
SSH port forwarding and NFS
The combination of SSH port forwarding and NFS provides confidentiality and integrity for the network traffic between client and server, and authenticates the end-user. A potential security issue is that every user on the NAS server who can establish a SSH forwarding tunnel, can mount the exported NFS file systems with the same permissions as the photos-mac
user. Thus, it requires that you trust every user account on the NAS server. This also applies to users with a restricted shell like /usr/local/libexec/git-core/git-shell
.
NOTE:
A mitigation technique is to add no-port-forwarding
to ~/.ssh/authorized_keys
for all users who should not be able to mount NFS shares.
More information in man page sshd(8)
.
File locking
The NFS client sends hostname (caller_name
), in each file lock request. When using SSH port forwarding, every request is from source IP address localhost
. Thus, NFS cannot differentiate clients, and locking will no longer work.
Recommended resources
-
Chapter 58, Network file and resource sharing and the TCP/IP network file system (NFS)
The TCP/IP Guide: A Comprehensive, Illustrated Internet Protocols Reference 1st Edition by Charles M. Kozierok -
The Linux NFS NOWTO - 6. Security and NFS (Published: 2002-07-16)