2006 年 10 月 23 日
网络文件系统(NFS)从 20 世纪 80 年代中期开始就已成为免费操作系统的一部分,并且成为了专有 UNIX 系统的最爱。了解 NFS 方面的知识十分重要,其原因很简单:能够在 UNIX 网络之间实现无缝访问对于系统来说非常关键。在本文中我们将学习 NFS 最新的发行版 NFSv4 如何解决很多关键问题,尤其是版本 2 和版本 3 中都十分突出的安全性问题。
我们很容易把文件系统认为是想当然就有的。我们在计算机上工作,计算机让我们能够访问打印机、照相机、数据库、远程传感器、望远镜、编译器和移动电话。这些设备几乎没什么共性 —— 实际上,其中很多都是在 Internet 得到广泛应用之后才成为了现实的(例如,综合了小型计算机功能的照相机和移动电话)。然而,它们都需要某种类型的文件系统来安全地存储和访问数据。
通常来说,我们都不会真的去问这样的问题:数据、使用数据的应用程序以及将数据呈现给我们的接口是如何存储在计算机上的?很多用户都(不无道理地)将文件系统当作是一面将自己与以位和字节形式保存的原始数据分隔开来的墙。连接文件系统所使用的协议栈对于大部分用户来说通常都是一个黑盒子,实际上对于大部分程序员来说也是如此。在所有这些设备之间进行互联也就相当于启用了文件系统之间的通信。
网络文件系统
从很多方面讲,通信都不仅仅是信息的长距离传输。网络协议也并不是使通用通信成为可能的惟一手段。毕竟,每个计算机系统都必须将数据报翻译成另外一端的操作系统可以理解的内容。TCP 是一种高效的传输协议,但是它并没有被优化来协助快速文件访问和启用应用程序软件的远程控制。
分布式计算和网络计算的比较
传统的网络协议对于计算在计算机之间(实际上是网络上)分发的方法所能做的贡献不多。只有那些蹩脚的程序员才会依赖于传输协议和光纤电缆来进行并行计算。相反,我们通常都依赖于一个连续模型,其中链接层的协议在连接初始化完成后进行接管,并要在网卡之间进行相当复杂的握手。并行计算和分布式文件系统都不再识别 IP 或以太网了。现在,只要事关性能,我们就可以忽略它们。然而,安全性问题却另当别论。
文件访问在计算机系统之间的组织方式仍然是个谜。现在,不管所访问的文件是在一台计算机上还是在多台合理分布的计算机上,对于访问系统来说都应该没什么区别。文件系统的语义和文件系统的数据结构现在已经成为了两个完全不同的主题。在 Plan 9 安装上的或在 Andrew 文件系统(AFS)风格的分布式文件系统上的文件系统语义隐藏了文件的组织方式和文件系统到硬件和网络的映射方式。NFS 并不需要隐藏文件和目录在远程文件系统上的存储方法,但是它也没有公开存储文件系统、目录和文件的实际硬件。
NFS:UNIX 问题的一个解决方案
分布式文件系统访问需要使用多个命令来使用户可以将网络上一台计算机中的目录挂载到自己的系统上来。Sun Microsystems 在很多年之前就面临了这种挑战,当时它正开始着手推广称为 远程过程调用(RPC)的技术和 NFS。
Sun 公司需要解决的根本问题是如何将几台 UNIX 机器连接在一起,从而构成一个无缝的分布式工作环境,而不需要重新编写 UNIX 文件系统的语义,同时也不用添加太多分布式文件系统特有的数据结构。当然,要想让 UNIX 工作站的网络看起来像一个大系统是不可能的:在保留每个系统的完整性的同时,要让用户能够在其他计算机的目录上进行操作,而且不会体验到不可接受的延时或任何的工作流程限制。
当然,NFS 所做的远远不止于实现了对文本文件的访问,我们还可以通过 NFS 来分发 “可运行的” 应用程序。必须要有一些安全过程来支持网络以防对可执行程序的恶意接管。但是这一切究竟是如何实现的呢?
NFS 是一个 RPC 标准
NFS 传统上是作为一个 RFC 应用程序来定义的,它要求 NFS 服务器使用 TCP 协议,NFS 客户机使用 TCP 或另外一种可以避免网络拥塞的协议。Internet 工程任务组(IETF)在 RFC 1832 发布了 PRC 的 Request for Comments (RFC)。另外一个对于 NFS 实现来说至关重要的标准则描述了 NFS 所使用的数据格式;它已经在 RFC 1831 中以 “External Data Representation”(XDR)文档的形式发布了。
其他一些 RFC 是关于在 NFS 会话过程中交换验证信息所需要的安全性和加密算法的。这里我们先来关注一下 NFS 的基本机制,相关的一个协议是 Mount 协议,它是在 RFC 1813 的附录 1 中描述的。
这个 RFC 告诉我们哪些协议让 NFS 得以工作,但是它并没有告诉我们 NFS 目前是如何工作的。 NFS 协议已经被定义为 IETF 标准的事实多少说明了它的重要性。最新的 NFS 发行版依然还是版本 3,RFC 的发展也没有超出 RFC 的描述报告阶段,因此 REC 一直被认为是一个限于 Sun Microsystems 众多的工程人员研究的对象和一种专有 UNIX 变种。Sun NFS 从 1985 年开始已经推出了很多版本,因此很多年以来一直在最当前的文件系统种类中处于领先地位。Sun Microsystems 在 1998 年将 NFS 的控制权转交给了 IETF,许多 NSF 版本 4(NFSv4)的活动都是在 IETF 的支持下进行的。
因此,现在的 RPC 和 NFS 版本反映了 Sun 公司之外的公司和兴趣团体的意愿。不过,很多 Sun 公司的工程师仍然对 NFS 的开发保持着极大的兴趣。
NFS 版本 3
版本 3 的 NFS(NFSv3)是无状态的,而 NFSv4 是有状态的。现在这一事实并不会引起太大争议:尽管 NFS 构建于的 TCP/IP 世界一直都是无状态的,这也恰恰是一些流量分析和安全性软件公司运转得很好的原因之一。
NFSv3 必须要依赖于几个辅助协议实现对远程计算机上目录的无缝加载,而不会太过依赖于底层的文件系统机制。NFS 在这种尝试中并非一直都成功。举例来说, Mount 协议调用初始文件句柄,而 Network Lock Manager 协议解决文件锁定,这两个操作都需要状态,而 NFSv3 却并没有提供状态。因此,在没有提供类似的数据流机制的协议层需要进行复杂的交互。现在,如果再考虑到在 Microsoft® Windows® 中创建的文件和目录与 UNIX 上创建的文件和目录有很大的差异的这一事实,那么事情就变得更加复杂了。
NFSv3 必须要使用几个端口来协调一些辅助协议,这样端口和协议层的以及与它们相关的安全问题就更加复杂了。目前,这个操作模型已经被舍弃了,以前在各个端口上要进行的辅助协议的所有操作在 NFSv4 中都可以使用一个知名端口来进行的。
NFSv3 也已经准备好进行启用了 Unicode 的文件系统操作了 —— 这直到二十世纪九十年代还是相当理论的一个优势。总之,NFS 对于 UNIX 文件系统语义映射得非常好,并且促进了分布式文件系统实现之间的竞争,例如 AFS 和 Samba。虽然 Windows 的支持很差,不过 Samba 文件服务器已经解决了在 UNIX 和 Windows 系统之间访问共享文件的问题。
NFS 版本 4
正如我们指出的一样,NFSv4 是有状态的。有几个根本的改变使之成为可能。我们前面提到过必须调用辅助协议,因为用户层的进程已经被舍弃了。相反,每个文件打开操作以及相当多的 RPC 调用都被转换成了内核层的文件系统操作。
所有的 NFS 版本都以 RPC 客户机和服务器操作的形式定义了每个任务单元。每个 NFSv3 请求都需要相当多的 RPC 调用和端口打开调用才能产生结果。版本 4 通过引入一个所谓的 复合操作 来简化了这个过程,它包含了很多文件系统对象操作。当然,这样做的直接影响是在网络上传输的 RPC 调用和数据会少很多,不过每个 RPC 调用所携带的数据都要比实际需要的数据要多。根据评估说明,NFSv3 RPC 调用所需要的次数是 NFSv4 复合 RPC 过程所需要的客户机-服务器交互次数的 5 倍。
RPC 变得已经不再那么重要,实际上它常被用作是封装在 NFSv4 堆栈中的很多操作的一个包装程序。这种变化还使得协议栈更少地依赖于底层的文件系统语义。但是这些变化并不意味着要忽视其他操作系统的文件系统操作:例如,Windows 共享就需要有状态的打开调用。有状态并不仅仅有助于进行流量分析,而且在文件系统语义中,可以更容易跟踪文件系统的操作。有状态的 打开调用让客户机可以对文件的数据和状态进行缓冲 —— 否则就必须在服务器上进行这种操作。在真实的世界中,Windows 客户机普遍存在,而 NFS 服务器可以与 Windows 无缝、透明地共享数据,因此花一些时间在 NFS 的配置上很值得。
使用 NFS
NFS 的设置与 Samba 非常类似。在服务器端,定义了要导出(或共享)的文件系统或目录;客户机端要将这些共享的目录挂载到本地系统上。当远程客户机挂载一个使用 NFS 共享的目录时,这个目录的访问方式与其他本地文件系统是完全相同的。在服务器端设置 NFS 是一个相当简单的过程。只需要创建或编辑 /etc/exports 文件,并启动 NFS 守护进程。要设置一个更加安全的 NFS 服务,还需要编辑 /etc/hosts.allow 和 /etc/hosts.deny 。NFS 的客户机端只需要运行 mount
命令。更多信息和选项,请查看 Linux® 手册页。
NFS 服务器
/etc/exports 文件中的项的格式相当简单。要共享一个文件系统,只需要编辑 /etc/exports 并使用下面的格式给出这个文件系统(和选项)即可:
directory (or file system) client1 (option1, option2) client2 (option1, option2) |
常用选项
有几个常用的选项可以对 NFS 实现进行定制。这些选项包括:
secure
: 这个选项是缺省选项,它使用了 1024 以下的 TCP/IP 端口实现 NFS 的连接。指定insecure
可以禁用这个选项。rw
: 这个选项允许 NFS 客户机进行读/写访问。缺省选项是只读的。async
: 这个选项可以改进性能,但是如果没有完全关闭 NFS 守护进程就重新启动了 NFS 服务器,这也可能会造成数据丢失。缺省设置为sync
。no_wdelay
: 这个选项关闭写延时。如果设置了async
,那么 NFS 就会忽略这个选项。nohide
: 如果将一个目录挂载到另外一个目录之上,那么原来的目录通常就被隐藏起来或看起来像空的一样。要禁用这种行为,需启用hide
选项。no_subtree_check
: 这个选项关闭子树检查,子树检查会执行一些不想忽略的安全性检查。缺省选项是启用子树检查。no_auth_nlm
: 这个选项也可以作为insecure_locks
指定,它告诉 NFS 守护进程不要对加锁请求进行认证。如果关心安全性问题,就要避免使用这个选项。缺省选项是auth_nlm
或secure_locks
。mp (mountpoint=path)
: 通过显式地声明这个选项,NFS 要求挂载所导出的目录。fsid=num
: 这个选项通常都在 NFS 故障恢复的情况中使用。如果希望实现 NFS 的故障恢复,请参考 NFS 文档。
用户映射
通过 NFS 中的用户映射,可以将伪或实际用户和组的标识赋给一个正在对 NFS 卷进行操作的用户。这个 NFS 用户具有映射所允许的用户和组的许可权限。对 NFS 卷使用一个通用的用户/组可以提供一定的安全性和灵活性,而不会带来很多管理负荷。
在使用 NFS 挂载的文件系统上的文件时,用户的访问通常都会受到限制,这就是说用户都是以匿名用户的身份来对文件进行访问的,这些用户缺省情况下对这些文件只有只读权限。这种行为对于 root 用户来说尤其重要。然而,实际上的确存在这种情况:希望用户以 root 用户或所定义的其他用户的身份访问远程文件系统上的文件。NFS 允许指定访问远程文件的用户——通过用户标识号(UID)和组标识号(GID),可以禁用正常的 squash 行为。
用户映射的选项包括:
root_squash
: 这个选项不允许 root 用户访问挂载上来的 NFS 卷。no_root_squash
: 这个选项允许 root 用户访问挂载上来的 NFS 卷。all_squash
: 这个选项对于公共访问的 NFS 卷来说非常有用,它会限制所有的 UID 和 GID,只使用匿名用户。缺省设置是no_all_squash
。anonuid
和anongid
: 这两个选项将匿名 UID 和 GID 修改成特定用户和组帐号。
清单 1 给出了 /etc/exports 的例子。
清单 1. /etc/exports 的例子
/opt/files 192.168.0.* /opt/files 192.168.0.120 /opt/files 192.168.0.125(rw, all_squash, anonuid=210, anongid=100) /opt/files *(ro, insecure, all_squash) |
第一项将 /opt/files 目录导出给 192.168.0 网络中的所有主机。下一项将 /opt/files 导出给一台主机:192.168.0.120。第三项指定了主机 192.168.0.125,并将对文件的读写权限授权给 user id=210
且 group id=100
的用户。最后一项针对一个公共目录,它只有只读权限并只能允许以匿名帐号的身份访问。
NFS 客户机
![]() |
|
要使用 NFS 作为客户机,客户机机器必须要运行 rpc.statd 和 portmap 进程。可以执行一个简单的 ps -ef
命令来检查系统是否运行了这两个守护进程。如果它们正在运行(应该如此),那么就可以使用下面的通用命令来挂载服务器上导出的目录:
mount server:directory local mount point |
通常来说,必须以 root 用户的身份来挂载文件系统。在远程计算机上,可以使用下面的命令(假设 NFS 服务器的 IP 地址是 192.168.0.100):
mount 192.168.0.100:/opt/files /mnt |
您所使用的发行版可能会要求在挂载文件系统时指定文件系统的类型。如果出现这种情况,请执行下面的命令:
mount -t nfs 192.168.0.100:/opt/files /mnt |
如果服务器端已经正确设置好了,那么远程文件系统应该可以毫无问题地加载。现在,执行 cd
命令切换到 /mnt 目录中,然后执行 ls
命令来查看文件。要永久挂载,必须编辑 /etc/fstab 文件,并创建一个类似于下面的项:
192.168.0.100:/opt/files /mnt nfs rw 0 0 |
注意: 有关 /etc/fstab 的更多信息,请参考 fstab 的手册页。
对 NFS 的批评
![]() |
|
对于 NFSv3 的安全性存在大量的批评。尽管 NFSv3 服务器是在 TCP 上运行的,但是也完全可以在 Internet 上运行 NFSv3 网络。不幸的是,这必须要打开多个端口,因而会导致几个众所周知的安全性问题。通过让 2049 端口成为 NFS 的强制端口,就可以跨过防火墙来使用 NFSv4,而不用太过注意其他协议(例如 Mount 协议)正在侦听哪些端口。因此,丢弃 Mount 协议具有几方面的正面影响:
- 强制的强认证机制: NFSv4 强制强认证机制。Kerberos 非常常见,低层基础设施公钥机制(Lower Infrastructure Public Key Mechanism,LIPKEY)也必须要支持。NFSv3 只支持 UNIX 型的标准加密来对访问进行认证 —— 这在大型网络中会导致一些主要的安全问题。
- 强制的 Microsoft Windows NT 型的访问控制列表(ACL)方案:尽管 NFSv3 允许对认证进行强加密,但是它并没有推动 Windows NT 型的 ACL 访问方案。可移植操作系统接口(POSIX)风格的 ACL 一段时间也曾实现过,但是一直都没有得到广泛采用。NFSv4 强制采用了 Windows NT 型的 ACL 方案。
- 协商的认证类型和机制: NFSv4 使对认证类型和机制进行协商成为可能。在 NSFv3 中,只能手工确定采用哪种加密类型。系统管理员然后必须对加密和安全协议进行协调。
NFS 仍然是不对等的吗?
NFSv4 正在开始取代很多 UNIX 和 Linux 系统上的 NFSv3。作为一个网络文件系统,NSFv4 有几个竞争对手。考虑到通用 Internet 文件系统(CIFS)/服务器消息块(SMB)是 Windows 和 Linux 上专有的系统,它们都可以认为是 NFSv4 的强劲对手。AFS 从来都没有太多的商业影响,它所关注的是的分布式文件系统的一些元素,而此文件系统可以简化数据迁移和复制。
从内核发展到 2.2 版本开始,产品级 Linux 版本的 NFS 就已经存在了,但是 Linux 内核版本的一大失误是对于 NFSv3 的采纳太晚了。实际上,Linux 花了相当长时间才能完全支持 NSFv3 。在 NSFv4 出现时,这个问题快速得到了解决,现在不仅仅是 Solaris、AIX 和 FreeBSD 可以提供对 NSFv4 的全面支持了。
NFS 目前已经被认为是一项非常成熟的技术,它有一个非常突出的优点:非常安全、可用性好,很多用户都发现这种只需要一次安全登录就可以访问网络和其设施的操作方式非常方便,即使文件和应用程序存在于其他操作系统或计算机也毫无影响。虽然与分布式文件系统比起来,这可能看起来像是个缺点,因为在分布式系统中对用户隐藏系统的结构,但不要忘了许多应用程序都要使用来自不同操作系统和计算机的文件。NFS 使得在不同操作系统上工作变得简单了,同时不需要太过担心文件系统语义及其性能特点。
参考资料
学习- 您可以参阅本文在 developerWorks 全球站点上的 英文原文 。
- 主要的 NFSv4 门户 包含了有关 NFSv4 的所有技术文档和 RFC 的链接。
- 分布式文件系统 需要花费一点精力才能理解。可以在 Wikipedia 上找到您所需的内容。
- RFC 1832 概述了 XDR 标准。
- RFC 1831 概述了 RPC 标准。
- RFC 1813, 附录 I: Mount 协议 概述了 Mount 协议(现已废弃)。
- RFC 2743 概述了 GSS-API。
获得产品和技术
- OpenAFS 是 AFS 的一个开源版本,是另外一个分布式文件系统。
- SAMBA 可以认为是一个文件系统,它可以实现 NFS 的一些功能。