Sunday, October 24, 2010

NFS Server

DELIVERABLE
NFS server sharing user home directories and selected nfsshare directory.

INSTALLATION
[root@server ~]# yum install nfs-utils

[root@server ~]# chkconfig nfs on

[root@server ~]# service nfs start
Starting NFS services: [ OK ]
Starting NFS quotas: [ OK ]
Starting NFS daemon: [ OK ]
Starting NFS mountd: [ OK ]

IPTABLES
NFS depends on a few rpc services. Therefore, the ports on which they listen have to be explicitly defined. This can be done in /ets/sysconfig/nfs. I use ports above 4001 for this purpose.
[root@server ~]# grep -v ^# /etc/sysconfig/nfs
RQUOTAD_PORT=4001
LOCKD_TCPPORT=4002
LOCKD_UDPPORT=4002
MOUNTD_PORT=4003
STATD_PORT=4004

Let's restart NFS:
[root@server ~]# service nfs restart
Shutting down NFS mountd: [ OK ]
Shutting down NFS daemon: [ OK ]
Shutting down NFS quotas: [ OK ]
Shutting down NFS services: [FAILED]
Starting NFS services: [ OK ]
Starting NFS quotas: [ OK ]
Starting NFS daemon: [ OK ]
Starting NFS mountd: [ OK ]

NFS failed to shutdown cleanly. This is a well-known issue and occures when exports is empty. More information here. Seems that the fix was pushed to Fedora 14, which is due out on November 2. Let's check whether all the services switched to the desired ports:
[root@server ~]# rpcinfo -p
program vers proto port
100000 2 tcp 111 portmapper
100000 2 udp 111 portmapper
100024 1 udp 775 status
100024 1 tcp 778 status
100011 1 udp 4001 rquotad
100011 2 udp 4001 rquotad
100011 1 tcp 4001 rquotad
100011 2 tcp 4001 rquotad
100003 2 udp 2049 nfs
100003 3 udp 2049 nfs
100003 4 udp 2049 nfs
100021 1 udp 4002 nlockmgr
100021 3 udp 4002 nlockmgr
100021 4 udp 4002 nlockmgr
100021 1 tcp 4002 nlockmgr
100021 3 tcp 4002 nlockmgr
100021 4 tcp 4002 nlockmgr
100003 2 tcp 2049 nfs
100003 3 tcp 2049 nfs
100003 4 tcp 2049 nfs
100005 1 udp 4003 mountd
100005 1 tcp 4003 mountd
100005 2 udp 4003 mountd
100005 2 tcp 4003 mountd
100005 3 udp 4003 mountd
100005 3 tcp 4003 mountd

And here is a gotcha! As you can see the status ports are still 775 and 778, although configuration file commands something else. To fix that we need to restart nfslock service, which governs statd daemon. Many times it was enough to restart nfs only to have all the changes in /etc/sysconfig/nfs take effect. However the last two installations of RHEL 5.4 required also this additional step.
[root@server ~]# service nfslock restart
Stopping NFS locking: [ OK ]
Stopping NFS statd: [ OK ]
Starting NFS statd: [ OK ]

Finally, we can define the ports that need to be open. These are:
nfs 2049
portmap 111
rpc services: 4001:4004
[root@server ~]# iptables -I MYCHAIN -s 192.168.1.0/24 -p tcp --dport 111 -j ACCEPT
[root@server ~]# iptables -I MYCHAIN -s 192.168.1.0/24 -p udp --dport 111 -j ACCEPT
[root@server ~]# iptables -I MYCHAIN -s 192.168.1.0/24 -p tcp --dport 2049 -j ACCEPT
[root@server ~]# iptables -I MYCHAIN -s 192.168.1.0/24 -p udp --dport 2049 -j ACCEPT
[root@server ~]# iptables -I MYCHAIN -s 192.168.1.0/24 -p tcp --dport 4001:4004 -j ACCEPT
[root@server ~]# iptables -I MYCHAIN -s 192.168.1.0/24 -p udp --dport 4001:4004 -j ACCEPT
[root@server ~]# service iptables save
Saving firewall rules to /etc/sysconfig/iptables: [ OK ]

SELINUX

To check whether service can be protected by SELINUX we can check the bottom of selinux man page or simply:
[root@server ~]# man -k _selinux # equivalent to apropos _selinux
ftpd_selinux (8) - Security-Enhanced Linux policy for ftp daemons
httpd_selinux (8) - Security Enhanced Linux Policy for the httpd daemon
kerberos_selinux (8) - Security Enhanced Linux Policy for Kerberos
named_selinux (8) - Security Enhanced Linux Policy for the Internet Name server (named) daemon
nfs_selinux (8) - Security Enhanced Linux Policy for NFS
pam_selinux (8) - PAM module to set the default security context
rsync_selinux (8) - Security Enhanced Linux Policy for the rsync daemon
samba_selinux (8) - Security Enhanced Linux Policy for Samba
ypbind_selinux (8) - Security Enhanced Linux Policy for NIS

Let's examine nfs-related booleans:
[root@server ~]# getsebool -a |grep nfs
allow_ftpd_use_nfs --> off
allow_nfsd_anon_write --> off
httpd_use_nfs --> off
nfs_export_all_ro --> on
nfs_export_all_rw --> on
nfsd_disable_trans --> off
qemu_use_nfs --> on
samba_share_nfs --> off
use_nfs_home_dirs --> off
virt_use_nfs --> off

The one that should draw your attention is use_nfs_home_dirs. Flip this one on:
[root@server ~]# setsebool -P use_nfs_home_dirs on

DIRECTORY EXPORT
What is shared on your NFS server is defined in /etc/exports. Create a directory /nfsshare, export it and verify:

Create nfsshare directory and sample file:
[root@server ~]# mkdir /nfsshare
[root@server ~]# touch /nfsshare/mynfsfile
[root@server ~]# chmod 777 /nfsshare/

Edit /etc/exports:
[root@server ~]# cat /etc/exports
/nfsshare *(rw,sync)
/home *(rw,sync)

Export the shares. Can be done also with service nfs restart:
[root@server ~]# exportfs -va
exporting *:/nfsshare
exporting *:/home

Verify:
[root@server ~]# showmount -e localhost
Export list for localhost:
/home *
/nfsshare *

On piotr.example.com:
[root@piotr ~]# showmount -e server.example.com
Export list for server.example.com:
/home *
/nfsshare *

All seems fine, lets mount nfsshare under /mnt/nfsshare:
[root@piotr ~]# mkdir /mnt/nfsshare
[root@piotr ~]# mount -t nfs server.example.com:/nfsshare /mnt/nfsshare/
[root@piotr ~]# ll /mnt/nfsshare/
total 4
-rw-r--r-- 1 root root 0 Oct 24 14:44 mynfsfile

[root@piotr ~]# mount -t nfs server.example.com:/home /home/

The resources that are remotely mounted can be viewed with:
[root@server ~]# showmount -a
All mount points on server.example.com:
192.168.1.2:/home
192.168.1.2:/nfsshare


ACCESS RESTRICTION
This can be achieved in multiple ways. Iptables , although more difficult to manage seems to be the safest choice. Then we have /etc/exports file where we can define what is shared and to whom. Additionally, tcp wrappers can be used. To test the confguration we need to deny all access to all services in /etc/hosts.deny and list the services and hosts that are allowed in /etc/hosts.allow. If the matching rule is not found in /etc/hosts.allow and /etc/hosts.deny does not exists, by fault of omission the access is granted. The proper settings in my setup are as follows:
[piotr@server ~]$ grep -v ^# /etc/hosts.allow
mountd,portmap:    192.168.1.
 
[piotr@server ~]$ grep -v ^# /etc/hosts.deny
ALL:    ALL
 

No comments:

Post a Comment