old-www/HOWTO/NFS-HOWTO/security.html

1501 lines
35 KiB
HTML

<HTML
><HEAD
><TITLE
>Security and NFS</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.76b+
"><LINK
REL="HOME"
TITLE="Linux NFS-HOWTO"
HREF="index.html"><LINK
REL="PREVIOUS"
TITLE="Optimizing NFS Performance"
HREF="performance.html"><LINK
REL="NEXT"
TITLE="Troubleshooting"
HREF="troubleshooting.html"></HEAD
><BODY
CLASS="SECT1"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Linux NFS-HOWTO</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="performance.html"
ACCESSKEY="P"
>Prev</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
></TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="troubleshooting.html"
ACCESSKEY="N"
>Next</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="SECT1"
><H1
CLASS="SECT1"
><A
NAME="SECURITY">6. Security and NFS</H1
><P
> This list of security tips and explanations will not make your site
completely secure. <EM
>NOTHING</EM
> will make your site completely secure. Reading this section
may help you get an idea of the security problems with NFS. This is not
a comprehensive guide and it will always be undergoing changes. If you
have any tips or hints to give us please send them to the HOWTO
maintainer.
</P
><P
> If you are on a network with no access to the outside world (not even a
modem) and you trust all the internal machines and all your users then
this section will be of no use to you. However, its our belief that
there are relatively few networks in this situation so we would suggest
reading this section thoroughly for anyone setting up NFS.
</P
><P
> With NFS, there are two steps required for a client to gain access to
a file contained in a remote directory on the server. The first step is mount
access. Mount access is achieved by the client machine attempting to
attach to the server. The security for this is provided by the
<TT
CLASS="FILENAME"
>/etc/exports</TT
> file. This file lists the names or IP addresses for machines
that are allowed to access a share point. If the client's ip address
matches one of the entries in the access list then it will be allowed to
mount. This is not terribly secure. If someone is capable of spoofing or
taking over a trusted address then they can access your mount points. To
give a real-world example of this type of "authentication": This is
equivalent to someone introducing themselves to you and you believing they
are who they claim to be because they are wearing a sticker that says
"Hello, My Name is ...." Once the machine has mounted a volume, its
operating system will have access to all files on the volume (with the
possible exception of those owned by root; see below) and write access
to those files as well, if the volume was exported with the
<TT
CLASS="USERINPUT"
><B
>rw</B
></TT
> option.
</P
><P
> The second step is file access. This is a function of normal file system
access controls on the client and not a specialized function of NFS.
Once the drive is mounted the user and group permissions on the files
determine access control.
</P
><P
> An example: bob on the server maps to the UserID 9999. Bob
makes a file on the server that is only accessible the user
(the equivalent to typing
<TT
CLASS="USERINPUT"
><B
>chmod 600</B
></TT
> <EM
>filename</EM
>).
A client is allowed to mount the drive where the file is stored.
On the client mary maps to UserID 9999. This means that the client
user mary can access bob's file that is marked as only accessible by him.
It gets worse: If someone has become superuser on the client machine they can
<B
CLASS="COMMAND"
>su - </B
> <EM
>username</EM
>
and become <EM
>any</EM
> user. NFS will be none the wiser.
</P
><P
> Its not all terrible. There are a few measures you can take on the server
to offset the danger of the clients. We will cover those shortly.
</P
><P
> If you don't think the security measures apply to you, you're probably
wrong. In <A
HREF="security.html#PORTMAPPER-SECURITY"
>Section 6.1</A
> we'll cover securing the portmapper,
server and client security in <A
HREF="security.html#SERVER.SECURITY"
>Section 6.2</A
> and <A
HREF="security.html#CLIENT.SECURITY"
>Section 6.3</A
> respectively.
Finally, in <A
HREF="security.html#FIREWALLS"
>Section 6.4</A
> we'll briefly talk about proper firewalling for
your nfs server.
</P
><P
> Finally, it is critical that all of your nfs daemons and client programs
are current. If you think that a flaw is too recently announced for it to
be a problem for you, then you've probably already been compromised.
</P
><P
> A good way to keep up to date on security alerts is to subscribe to the
bugtraq mailinglists. You can read up on how to subscribe and various
other information about bugtraq here:
<A
HREF="http://www.securityfocus.com/forums/bugtraq/faq.html"
TARGET="_top"
>http://www.securityfocus.com/forums/bugtraq/faq.html</A
>
</P
><P
> Additionally searching for <EM
>NFS</EM
> at
<A
HREF="http://www.securityfocus.com"
TARGET="_top"
>securityfocus.com's</A
> search engine will
show you all security reports pertaining to NFS.
</P
><P
> You should also regularly check CERT advisories. See the CERT web page
at <A
HREF="http://www.cert.org"
TARGET="_top"
>www.cert.org</A
>.
</P
><DIV
CLASS="SECT2"
><H2
CLASS="SECT2"
><A
NAME="PORTMAPPER-SECURITY">6.1. The portmapper</H2
><P
> The portmapper keeps a list of what services are running on what ports.
This list is used by a connecting machine to see what ports it wants to
talk to access certain services.
</P
><P
>
The portmapper is not in as bad a shape as a few years ago but it is
still a point of worry for many sys admins. The portmapper, like NFS and
NIS, should not really have connections made to it outside of a trusted
local area network. If you have to expose them to the outside world -
be careful and keep up diligent monitoring of those systems.
</P
><P
> Not all Linux distributions were created equal. Some seemingly up-to-date
distributions do not include a securable portmapper.
The easy way to check if your portmapper is good or not is to run
<EM
>strings(1)</EM
> and see if it reads the relevant files, <TT
CLASS="FILENAME"
>/etc/hosts.deny</TT
> and
<TT
CLASS="FILENAME"
>/etc/hosts.allow</TT
>. Assuming your portmapper is <TT
CLASS="FILENAME"
>/sbin/portmap</TT
> you can
check it with this command:
<TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
> strings /sbin/portmap | grep hosts.
</PRE
></FONT
></TD
></TR
></TABLE
>
</P
><P
> On a securable machine it comes up something like this:
<TABLE
BORDER="1"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="SCREEN"
> /etc/hosts.allow
/etc/hosts.deny
@(#) hosts_ctl.c 1.4 94/12/28 17:42:27
@(#) hosts_access.c 1.21 97/02/12 02:13:22
</PRE
></FONT
></TD
></TR
></TABLE
>
</P
><P
> First we edit <TT
CLASS="FILENAME"
>/etc/hosts.deny</TT
>. It should contain the line
</P
><P
> <TABLE
BORDER="1"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="SCREEN"
> portmap: ALL
</PRE
></FONT
></TD
></TR
></TABLE
>
</P
><P
> which will deny access to everyone. While it is closed run:
<TABLE
BORDER="1"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="SCREEN"
> rpcinfo -p
</PRE
></FONT
></TD
></TR
></TABLE
>
just to check that your portmapper really reads and obeys
this file. Rpcinfo should give no output, or possibly an error message.
The files <TT
CLASS="FILENAME"
>/etc/hosts.allow</TT
> and <TT
CLASS="FILENAME"
>/etc/hosts.deny</TT
>
take effect immediately after you save them. No daemon needs to be restarted.
</P
><P
> Closing the portmapper for everyone is a bit drastic, so we open it
again by editing <TT
CLASS="FILENAME"
>/etc/hosts.allow</TT
>. But first
we need to figure out what to put in it. It should basically list
all machines that should have access to your portmapper. On a run of
the mill Linux system there are very few machines that need any access
for any reason. The portmapper administers <B
CLASS="COMMAND"
>nfsd</B
>,
<B
CLASS="COMMAND"
>mountd</B
>, <B
CLASS="COMMAND"
>ypbind</B
>/<B
CLASS="COMMAND"
>ypserv</B
>,
<B
CLASS="COMMAND"
>rquotad</B
>, <B
CLASS="COMMAND"
>lockd</B
> (which shows up
as <TT
CLASS="COMPUTEROUTPUT"
>nlockmgr</TT
>), <B
CLASS="COMMAND"
>statd</B
>
(which shows up as <TT
CLASS="COMPUTEROUTPUT"
>status</TT
>)
and 'r' services like <B
CLASS="COMMAND"
>ruptime</B
>
and <B
CLASS="COMMAND"
>rusers</B
>.
Of these only <B
CLASS="COMMAND"
>nfsd</B
>, <B
CLASS="COMMAND"
>mountd</B
>,
<B
CLASS="COMMAND"
>ypbind</B
>/<B
CLASS="COMMAND"
>ypserv</B
> and perhaps
<B
CLASS="COMMAND"
>rquotad</B
>,<B
CLASS="COMMAND"
>lockd</B
>
and <B
CLASS="COMMAND"
>statd</B
> are of any consequence. All machines that need
to access services on your machine should be allowed to do that. Let's
say that your machine's address is <EM
>192.168.0.254</EM
> and
that it lives on the subnet <EM
>192.168.0.0</EM
>, and that all
machines on the subnet should have access to it (for an overview of those
terms see the the <A
HREF="http://www.linuxdoc.org/HOWTO/Networking-Overview-HOWTO.html"
TARGET="_top"
>Networking-Overview-HOWTO</A
>). Then we write:
<TABLE
BORDER="1"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="SCREEN"
> portmap: 192.168.0.0/255.255.255.0
</PRE
></FONT
></TD
></TR
></TABLE
>
in <TT
CLASS="FILENAME"
>/etc/hosts.allow</TT
>. If you are not sure what your
network or netmask are, you can use the <B
CLASS="COMMAND"
>ifconfig</B
> command to
determine the netmask and the <B
CLASS="COMMAND"
>netstat</B
> command to
determine the network. For, example, for the
device eth0 on the above machine <B
CLASS="COMMAND"
>ifconfig</B
> should show:
</P
><P
> <TABLE
BORDER="1"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="SCREEN"
> ...
eth0 Link encap:Ethernet HWaddr 00:60:8C:96:D5:56
inet addr:192.168.0.254 Bcast:192.168.0.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:360315 errors:0 dropped:0 overruns:0
TX packets:179274 errors:0 dropped:0 overruns:0
Interrupt:10 Base address:0x320
...
</PRE
></FONT
></TD
></TR
></TABLE
>
and <B
CLASS="COMMAND"
>netstat -rn</B
> should show:
<TABLE
BORDER="1"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="SCREEN"
> Kernel routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
...
192.168.0.0 0.0.0.0 255.255.255.0 U 0 0 174412 eth0
...
</PRE
></FONT
></TD
></TR
></TABLE
>
(The network address is in the first column).
</P
><P
> The <TT
CLASS="FILENAME"
>/etc/hosts.deny</TT
> and <TT
CLASS="FILENAME"
>/etc/hosts.allow</TT
> files are
described in the manual pages of the same names.
</P
><P
> <EM
> IMPORTANT: Do not put anything but IP NUMBERS in the portmap lines of
these files. Host name lookups can indirectly cause portmap activity
which will trigger host name lookups which can indirectly cause
portmap activity which will trigger...
</EM
>
</P
><P
> Versions 0.2.0 and higher of the nfs-utils package also use the
<TT
CLASS="FILENAME"
>hosts.allow</TT
> and <TT
CLASS="FILENAME"
>hosts.deny</TT
>
files, so you should put in entries for <B
CLASS="COMMAND"
>lockd</B
>,
<B
CLASS="COMMAND"
>statd</B
>, <B
CLASS="COMMAND"
>mountd</B
>, and
<B
CLASS="COMMAND"
>rquotad</B
> in these files too. For a complete example,
see <A
HREF="server.html#HOSTS"
>Section 3.2.2</A
>.
</P
><P
> The above things should make your server tighter. The only remaining
problem is if someone gains administrative access to one of your trusted
client machines and is able to send bogus NFS requests. The next section
deals with safeguards against this problem.
</P
></DIV
><DIV
CLASS="SECT2"
><H2
CLASS="SECT2"
><A
NAME="SERVER.SECURITY">6.2. Server security: nfsd and mountd</H2
><P
> On the server we can decide that we don't want to trust any requests
made as root on the client. We can do that by using the
<TT
CLASS="USERINPUT"
><B
>root_squash</B
></TT
> option in <TT
CLASS="FILENAME"
>/etc/exports</TT
>:
<TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
> /home slave1(rw,root_squash)
</PRE
></FONT
></TD
></TR
></TABLE
>
</P
><P
> This is, in fact, the default. It should always be turned on unless you
have a <EM
>very</EM
> good reason to turn it off. To turn it off use the
<TT
CLASS="USERINPUT"
><B
>no_root_squash</B
></TT
> option.
</P
><P
> Now, if a user with <EM
>UID</EM
> 0 (i.e., root's user ID number)
on the client attempts to access (read, write, delete) the file system,
the server substitutes the <EM
>UID</EM
> of the server's 'nobody'
account. Which means that the root user on the client can't access or
change files that only root on the server can access or change. That's
good, and you should probably use <TT
CLASS="USERINPUT"
><B
>root_squash</B
></TT
> on
all the file systems you export. "But the root user on the client can
still use <B
CLASS="COMMAND"
>su</B
> to become any other user and
access and change that users files!" say you. To which the answer is:
Yes, and that's the way it is, and has to be with Unix and NFS. This
has one important implication: All important binaries and files should be
owned by root, and not bin or other non-root account, since the only
account the clients root user cannot access is the servers root
account. In the <EM
>exports(5)</EM
> man page there are several other squash
options listed so that you can decide to mistrust whomever you (don't)
like on the clients.
</P
><P
> The TCP ports 1-1024 are reserved for root's use (and therefore sometimes
referred to as "secure ports") A non-root user cannot bind these ports.
Adding the <TT
CLASS="USERINPUT"
><B
>secure</B
></TT
> option to an
<TT
CLASS="FILENAME"
>/etc/exports</TT
> means that it will only listed to
requests coming from ports 1-1024 on the client, so that a malicious
non-root user on the client cannot come along and open up a spoofed
NFS dialogue on a non-reserved port. This option is set by default.
</P
></DIV
><DIV
CLASS="SECT2"
><H2
CLASS="SECT2"
><A
NAME="CLIENT.SECURITY">6.3. Client Security</H2
><DIV
CLASS="SECT3"
><H3
CLASS="SECT3"
><A
NAME="NOSUID">6.3.1. The nosuid mount option</H3
><P
> On the client we can decide that we don't want to trust the server too
much a couple of ways with options to mount. For example we can
forbid suid programs to work off the NFS file system with the
<TT
CLASS="USERINPUT"
><B
>nosuid</B
></TT
>
option. Some unix programs, such as passwd, are called "suid" programs:
They set the id of the person running them to whomever is the owner of
the file. If a file is owned by root and is suid, then the program will
execute as root, so that they can perform operations (such as writing to
the password file) that only root is allowed to do. Using the
<TT
CLASS="USERINPUT"
><B
>nosuid</B
></TT
>
option is a good idea and you should consider using this with all NFS
mounted disks. It means that the server's root user
cannot make a suid-root
program on the file system, log in to the client as a normal user
and then use the suid-root program to become root on the client too.
One could also forbid execution of files on the mounted file system
altogether with the <TT
CLASS="USERINPUT"
><B
>noexec</B
></TT
> option.
But this is more likely to be impractical than
<TT
CLASS="USERINPUT"
><B
>nosuid</B
></TT
> since a file
system is likely to at least contain some scripts or programs that need
to be executed.
</P
></DIV
><DIV
CLASS="SECT3"
><H3
CLASS="SECT3"
><A
NAME="BROKENSUID">6.3.2. The broken_suid mount option</H3
><P
> Some older programs (<B
CLASS="COMMAND"
>xterm</B
> being one of them) used to rely on the idea
that root can write everywhere. This is will break under new kernels on
NFS mounts. The security implications are that programs that do this
type of suid action can potentially be used to change your apparent uid
on nfs servers doing uid mapping. So the default has been to disable this
<TT
CLASS="USERINPUT"
><B
>broken_suid</B
></TT
> in the linux kernel.
</P
><P
> The long and short of it is this: If you're using an old linux
distribution, some sort of old suid program or an older unix of some
type you <EM
>might</EM
> have to mount from your clients with the
<TT
CLASS="USERINPUT"
><B
>broken_suid</B
></TT
> option to <B
CLASS="COMMAND"
>mount</B
>.
However, most recent unixes and linux distros have <B
CLASS="COMMAND"
>xterm</B
> and such programs
just as a normal executable with no suid status, they call programs to do their setuid work.
</P
><P
> You enter the above options in the options column, with the <TT
CLASS="USERINPUT"
><B
>rsize</B
></TT
> and
<TT
CLASS="USERINPUT"
><B
>wsize</B
></TT
>, separated by commas.
</P
></DIV
><DIV
CLASS="SECT3"
><H3
CLASS="SECT3"
><A
NAME="SECURING-DAEMONS">6.3.3. Securing portmapper, rpc.statd, and rpc.lockd on the client</H3
><P
> In the current (2.2.18+) implementation of NFS, full file locking is
supported. This means that <B
CLASS="COMMAND"
>rpc.statd</B
> and <B
CLASS="COMMAND"
>rpc.lockd</B
>
must be running on the client in order for locks to function correctly.
These services require the portmapper to be running. So, most of the
problems you will find with nfs on the server you may also be plagued with
on the client. Read through the portmapper section above for information on
securing the portmapper.
</P
></DIV
></DIV
><DIV
CLASS="SECT2"
><H2
CLASS="SECT2"
><A
NAME="FIREWALLS">6.4. NFS and firewalls (ipchains and netfilter)</H2
><P
> IPchains (under the 2.2.X kernels) and netfilter (under the 2.4.x
kernels) allow a good level of security - instead of relying on the
daemon (or perhaps its TCP wrapper) to
determine which machines can connect,
the connection attempt is allowed or disallowed at a lower level. In
this case, you can stop the connection much earlier and more globally, which
can protect you from all sorts of attacks.
</P
><P
> Describing how to set up a Linux firewall is well beyond the scope of
this document. Interested readers may wish to read the <A
HREF="http://www.linuxdoc.org/HOWTO/Firewall-HOWTO.html"
TARGET="_top"
>Firewall-HOWTO</A
>
or the <A
HREF="http://www.linuxdoc.org/HOWTO/IPCHAINS-HOWTO.HTML"
TARGET="_top"
>IPCHAINS-HOWTO</A
>.
For users of kernel 2.4 and above you might want to visit the netfilter webpage at:
<A
HREF="http://netfilter.filewatcher.org"
TARGET="_top"
>http://netfilter.filewatcher.org</A
>.
If you are already familiar with the workings of ipchains or netfilter
this section will give you a few tips on how to better setup your
NFS daemons to more easily firewall and protect them.
</P
><P
> A good rule to follow for your firewall configuration is to deny all, and
allow only some - this helps to keep you from accidentally allowing more
than you intended.
</P
><P
> In order to understand how to firewall the NFS daemons, it will help
to breifly review how they bind to ports.</P
><P
>When a daemon starts up, it requests a free port from the portmapper.
The portmapper gets the port for the daemon and keeps track of
the port currently used by that daemon. When other hosts or processes
need to communicate with the daemon, they request the port number
from the portmapper in order to find the
daemon. So the ports will perpetually float because different ports may
be free at different times and so the portmapper will allocate them
differently each time. This is a pain for setting up a firewall. If
you never know where the daemons are going to be then you don't
know precisely which ports to allow access to. This might not be a big deal
for many people running on a protected or isolated LAN. For those
people on a public network, though, this is horrible.</P
><P
>In kernels 2.4.13 and later with nfs-utils 0.3.3 or later you no
longer have to worry about the floating of ports in the portmapper.
Now all of the daemons pertaining to nfs can be "pinned" to a port.
Most of them nicely take a <B
CLASS="COMMAND"
>-p</B
> option when they are started;
those daemons that are started by the kernel take some kernel arguments
or module options. They are described below.</P
><P
>Some of the daemons involved in sharing data via nfs are already
bound to a port. <B
CLASS="COMMAND"
>portmap</B
> is always on port
111 tcp and udp. <B
CLASS="COMMAND"
>nfsd</B
> is
always on port 2049 TCP and UDP (however, as of kernel 2.4.17, NFS over
TCP is considered experimental and is not for use on production machines).</P
><P
>The other daemons, <B
CLASS="COMMAND"
>statd</B
>, <B
CLASS="COMMAND"
>mountd</B
>,
<B
CLASS="COMMAND"
>lockd</B
>, and <B
CLASS="COMMAND"
>rquotad</B
>, will normally move
around to the first available port they are informed of by the portmapper.</P
><P
>To force <B
CLASS="COMMAND"
>statd</B
> to bind to a particular port, use the
<TT
CLASS="USERINPUT"
><B
>-p</B
></TT
>
<EM
>portnum</EM
> option. To force <B
CLASS="COMMAND"
>statd</B
> to
respond on a particular port, additionally use the
<TT
CLASS="USERINPUT"
><B
>-o</B
></TT
> <EM
>portnum</EM
> option when starting it.</P
><P
>To force <B
CLASS="COMMAND"
>mountd</B
> to bind to a particular port use the
<TT
CLASS="USERINPUT"
><B
>-p</B
></TT
> <EM
>portnum</EM
> option.</P
><P
>For example, to have statd broadcast of port 32765 and listen on port
32766, and mountd listen on port 32767, you would type:</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
># statd -p 32765 -o 32766
# mountd -p 32767</PRE
></FONT
></TD
></TR
></TABLE
><P
><B
CLASS="COMMAND"
>lockd</B
> is started by the kernel when it is needed.
Therefore you need
to pass module options (if you have it built as a module) or kernel
options to force <B
CLASS="COMMAND"
>lockd</B
> to listen and respond
only on certain ports.</P
><P
>If you are using loadable modules and you would like to specify these
options in your <TT
CLASS="FILENAME"
>/etc/modules.conf</TT
> file add
a line like this to the file:</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>options lockd nlm_udpport=32768 nlm_tcpport=32768</PRE
></FONT
></TD
></TR
></TABLE
><P
>The above line would specify the udp and tcp port for
<B
CLASS="COMMAND"
>lockd</B
> to be 32768.</P
><P
>If you are not using loadable modules or if you have compiled
<B
CLASS="COMMAND"
>lockd</B
> into the kernel instead of building it
as a module then you will need to pass it an option on the kernel boot line.</P
><P
>It should look something like this:</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
> vmlinuz 3 root=/dev/hda1 lockd.udpport=32768 lockd.tcpport=32768</PRE
></FONT
></TD
></TR
></TABLE
><P
>The port numbers do not have to match but it would simply add
unnecessary confusion if they didn't.</P
><P
>If you are using quotas and using <B
CLASS="COMMAND"
>rpc.quotad</B
> to make these
quotas viewable over nfs you will need to also take it into
account when setting up your firewall. There are two
<B
CLASS="COMMAND"
>rpc.rquotad</B
>
source trees. One of those is maintained in the
<SPAN
CLASS="APPLICATION"
>nfs-utils</SPAN
> tree.
The other in the <SPAN
CLASS="APPLICATION"
>quota-tools</SPAN
> tree.
They do not operate identically.
The one provided with <SPAN
CLASS="APPLICATION"
>nfs-utils</SPAN
> supports
binding the daemon to a port with the <TT
CLASS="USERINPUT"
><B
>-p</B
></TT
>
directive. The one in <SPAN
CLASS="APPLICATION"
>quota-tools</SPAN
> does not.
Consult your distribution's documentation to determine if yours does. </P
><P
>For the sake of this discussion lets describe a network and setup a
firewall to protect our nfs server.
Our nfs server is 192.168.0.42 our client is 192.168.0.45 only.
As in the example above, <B
CLASS="COMMAND"
>statd</B
> has been
started so that it only
binds to port 32765 for incoming requests and it must answer on
port 32766. <B
CLASS="COMMAND"
>mountd</B
> is forced to bind to port 32767.
<B
CLASS="COMMAND"
>lockd</B
>'s module parameters have been set to bind to 32768.
<B
CLASS="COMMAND"
>nfsd</B
> is, of course, on port 2049 and the portmapper is on port 111.</P
><P
>We are not using quotas.</P
><P
>Using <SPAN
CLASS="APPLICATION"
>IPCHAINS</SPAN
>, a simple firewall
might look something like this:</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>ipchains -A input -f -j ACCEPT -s 192.168.0.45
ipchains -A input -s 192.168.0.45 -d 0/0 32765:32768 -p 6 -j ACCEPT
ipchains -A input -s 192.168.0.45 -d 0/0 32765:32768 -p 17 -j ACCEPT
ipchains -A input -s 192.168.0.45 -d 0/0 2049 -p 17 -j ACCEPT
ipchains -A input -s 192.168.0.45 -d 0/0 2049 -p 6 -j ACCEPT
ipchains -A input -s 192.168.0.45 -d 0/0 111 -p 6 -j ACCEPT
ipchains -A input -s 192.168.0.45 -d 0/0 111 -p 17 -j ACCEPT
ipchains -A input -s 0/0 -d 0/0 -p 6 -j DENY -y -l
ipchains -A input -s 0/0 -d 0/0 -p 17 -j DENY -l</PRE
></FONT
></TD
></TR
></TABLE
><P
>The equivalent set of commands in <SPAN
CLASS="APPLICATION"
>netfilter</SPAN
> is:</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>iptables -A INPUT -f -j ACCEPT -s 192.168.0.45
iptables -A INPUT -s 192.168.0.45 -d 0/0 32765:32768 -p 6 -j ACCEPT
iptables -A INPUT -s 192.168.0.45 -d 0/0 32765:32768 -p 17 -j ACCEPT
iptables -A INPUT -s 192.168.0.45 -d 0/0 2049 -p 17 -j ACCEPT
iptables -A INPUT -s 192.168.0.45 -d 0/0 2049 -p 6 -j ACCEPT
iptables -A INPUT -s 192.168.0.45 -d 0/0 111 -p 6 -j ACCEPT
iptables -A INPUT -s 192.168.0.45 -d 0/0 111 -p 17 -j ACCEPT
iptables -A INPUT -s 0/0 -d 0/0 -p 6 -j DENY --syn --log-level 5
iptables -A INPUT -s 0/0 -d 0/0 -p 17 -j DENY --log-level 5</PRE
></FONT
></TD
></TR
></TABLE
><P
>The first line says to accept all packet fragments (except the
first packet fragment which will be treated as a normal packet).
In theory no packet will pass through until it is reassembled,
and it won't be reassembled unless the first packet fragment
is passed. Of course there are attacks that can be generated
by overloading a machine with packet fragments. But NFS won't
work correctly unless you let fragments through. See <A
HREF="troubleshooting.html#SYMPTOM8"
>Section 7.8</A
>
for details.</P
><P
>The other lines allow specific connections from any port on our
client host to the specific ports we have made available on
our server. This means that if, say, 192.158.0.46 attempts to contact
the NFS server it will not be able to mount or see what mounts
are available.</P
><P
>With the new port pinning capabilities it is obviously much easier
to control what hosts are allowed to mount your NFS shares. It is
worth mentioning that NFS is not an encrypted protocol and anyone
on the same physical network could sniff the traffic and reassemble
the information being passed back and forth.
</P
></DIV
><DIV
CLASS="SECT2"
><H2
CLASS="SECT2"
><A
NAME="NFS-SSH">6.5. Tunneling NFS through SSH</H2
><P
>One method of encrypting NFS traffic over a network is to
use the port-forwarding capabilities of <B
CLASS="COMMAND"
>ssh</B
>.
However, as we shall see, doing so has a serious drawback if you do not
utterly and completely trust the local users on your server.</P
><P
>The first step will be to export files to the localhost. For example, to
export the <TT
CLASS="FILENAME"
>/home</TT
> partition, enter the following into
<TT
CLASS="FILENAME"
>/etc/exports</TT
>:
<TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>/home 127.0.0.1(rw)</PRE
></FONT
></TD
></TR
></TABLE
></P
><P
>The next step is to use <B
CLASS="COMMAND"
>ssh</B
> to forward ports. For example,
<B
CLASS="COMMAND"
>ssh</B
> can tell the server to forward to any port on any
machine from a port on the client. Let us assume, as in the previous
section, that our server is 192.168.0.42, and that we have pinned
<B
CLASS="COMMAND"
>mountd</B
> to port 32767
using the argument <TT
CLASS="USERINPUT"
><B
>-p 32767</B
></TT
>. Then, on the client,
we'll type:
<TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
> # ssh root@192.168.0.42 -L 250:localhost:2049 -f sleep 60m
# ssh root@192.168.0.42 -L 251:localhost:32767 -f sleep 60m</PRE
></FONT
></TD
></TR
></TABLE
></P
><P
>The above command causes <B
CLASS="COMMAND"
>ssh</B
> on the client to take
any request directed at the client's port 250 and forward it,
first through <B
CLASS="COMMAND"
>sshd</B
> on the server, and then on
to the server's port 2049. The second line
causes a similar type of forwarding between requests to port 251 on
the client and port 32767 on the server. The
<TT
CLASS="USERINPUT"
><B
>localhost</B
></TT
> is relative to the server; that is,
the forwarding will be done to the server itself. The port could otherwise
have been made to forward to any other machine, and the requests would look to
the outside world as if they were coming from the server. Thus, the requests
will appear to NFSD on the server as if they are coming from the server itself.
Note that in order to bind to a port below 1024 on the client, we have
to run this command as root on the client. Doing this will be necessary
if we have exported our filesystem with the default
<TT
CLASS="USERINPUT"
><B
>secure</B
></TT
> option.</P
><P
>Finally, we are pulling a little trick with the last option,
<TT
CLASS="USERINPUT"
><B
>-f sleep 60m</B
></TT
>. Normally, when
we use <B
CLASS="COMMAND"
>ssh</B
>, even with the <TT
CLASS="USERINPUT"
><B
>-L</B
></TT
> option,
we will open up a shell on the remote machine. But instead, we just want
the port forwarding to execute in the background so that we get our shell
on the client back. So, we tell <B
CLASS="COMMAND"
>ssh</B
> to execute a command
in the background on the server to sleep for 60 minutes. This will cause
the port to be forwarded for 60 minutes until it gets a connection; at that
point, the port will continue to be forwarded until the connection dies or
until the 60 minutes are up, whichever happens later. The above command
could be put in our startup scripts on the client, right after the network
is started.</P
><P
> Next, we have to mount the filesystem on the client. To do this, we tell
the client to mount a filesystem on the localhost, but at a different
port from the usual 2049. Specifically, an entry in <TT
CLASS="FILENAME"
>/etc/fstab</TT
>
would look like:
<TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
> localhost:/home /mnt/home nfs rw,hard,intr,port=250,mountport=251 0 0</PRE
></FONT
></TD
></TR
></TABLE
></P
><P
>Having done this, we can see why the above will be incredibly insecure
if we have <EM
>any</EM
> ordinary users who are able to log in
to the server locally. If they can, there is nothing preventing them from
doing what we did and using <B
CLASS="COMMAND"
>ssh</B
> to forward a privileged
port on their own client machine (where they are legitimately root) to ports
2049 and 32767 on the server. Thus, any ordinary user on the server can
mount our filesystems with the same rights as root on our client.</P
><P
>If you are using an NFS server that does not have a way for ordinary users
to log in, and you wish to use this method, there are two additional caveats:
First, the connection travels from the client to the server via
<B
CLASS="COMMAND"
>sshd</B
>; therefore you will have to leave port 22 (where
<B
CLASS="COMMAND"
>sshd</B
> listens) open to your client on the firewall. However
you do not need to leave the other ports, such as 2049 and 32767, open
anymore. Second, file locking will no longer work. It is not possible
to ask <B
CLASS="COMMAND"
>statd</B
> or the locking manager to make requests
to a particular port for a particular mount; therefore, any locking requests
will cause <B
CLASS="COMMAND"
>statd</B
> to connect to <B
CLASS="COMMAND"
>statd</B
>
on localhost, i.e., itself, and it will fail with an error. Any attempt
to correct this would require a major rewrite of NFS.</P
><P
>It may also be possible to use <SPAN
CLASS="APPLICATION"
>IPSec</SPAN
> to encrypt
network traffic between your client and your server, without compromising
any local security on the server; this will not be taken up here.
See the <A
HREF="http://www.freeswan.org/"
TARGET="_top"
>FreeS/WAN</A
> home page
for details on using IPSec under Linux.</P
></DIV
><DIV
CLASS="SECT2"
><H2
CLASS="SECT2"
><A
NAME="SUMMARY">6.6. Summary</H2
><P
> If you use the <TT
CLASS="FILENAME"
>hosts.allow</TT
>, <TT
CLASS="FILENAME"
>hosts.deny</TT
>,
<TT
CLASS="USERINPUT"
><B
>root_squash</B
></TT
>, <TT
CLASS="USERINPUT"
><B
>nosuid</B
></TT
> and privileged
port features in the portmapper/NFS software, you avoid many of the
presently known bugs in NFS and can almost feel secure about that at
least. But still, after all that: When an intruder has access to your
network, s/he can make strange commands appear in your <TT
CLASS="FILENAME"
>.forward</TT
> or
read your mail when <TT
CLASS="FILENAME"
>/home</TT
> or <TT
CLASS="FILENAME"
>/var/mail</TT
> is
NFS exported. For the same reason, you should never access your PGP private key
over NFS. Or at least you should know the risk involved. And now you know a bit
of it.
</P
><P
> NFS and the portmapper makes up a complex subsystem and therefore it's
not totally unlikely that new bugs will be discovered, either in the
basic design or the implementation we use. There might even be holes
known now, which someone is abusing. But that's life.
</P
></DIV
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="performance.html"
ACCESSKEY="P"
>Prev</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="index.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="troubleshooting.html"
ACCESSKEY="N"
>Next</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>Optimizing NFS Performance</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
>&nbsp;</TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>Troubleshooting</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>