一、安装
服务端安装nfs-utils、rcpbind软件包;
yum -y install nfs-utils rpcbind
二、配置
2.1 通过nfs协议配置nas
vi /etc/sysconfig/nfs
设置各种*port=...参数
# TCP port rpc.lockd should listen on.
LOCKD_TCPPORT=32803
# UDP port rpc.lockd should listen on.
LOCKD_UDPPORT=32769
# Port rpc.statd should listen on.
STATD_PORT=662
# Outgoing port statd should used. The default is port
# is random
STATD_OUTGOING_PORT=2020
既然涉及到端口, 就要确保防火墙没有屏蔽以上端口, 否则的话, 客户端和服务器端无法建立连接.
NAS在这里充当了NFS服务器的角色,而Linux,Solaris和AIX则是NFS客户机。NFS的功能很多,不同的功能对应着不同的daemon。比如一定要有的nfsd和mountd,还有可选的lockd和statd。
每个daemon都需要占用一些端口,但有些daemon是可选的,也许用户根本不会启用它们。所以,NFS并没有给每个NFS daemon保留固定端口(除了nfsd)。而是在系统启动时给需要启用的NFS daemon分配端口,然后把这些端口号告诉RPC daemon。RPC daemon的端口号是固定的111,每个NFS客户机都知道怎么联系它。当客户机需要连接NFS的某个daemon时,就不得不先咨询RPC daemon,获得该NFS daemon对应的端口号,然后再发送NFS请求。
我第一次看到RPC daemon的工作原理,就想起交大管浴室的老头。他的固定地址是门房(相当于端口111),每个要洗澡的学生(NFS客户机)都知道怎么找到他,他会给你一个带号码的钥匙(端口号),有了这个号码,你就可以找到相应的格子(NFS daemon)放衣服了。
很少有人会对自己的共享不加限制,像我一样收获小电影的毕竟是少数,大多数人收获的是恶作剧。NFS通过限制客户机(比如IP地址, hostname等)访问来实现安全控制。下表列举了一些NFS服务器端的端口:
端口号 | 服务 |
---|---|
32803/32769 | 服务 |
662 | status |
111 | portmapper |
20048 | mountd |
2049 | nfs/nfs_acl |
来看连接的建立过程
1)首先服务器端启动RPC服务,并开启111端口
2)服务器端启动NFS服务,并向RPC注册端口信息
3)客户端启动RPC(portmap服务),向服务端的RPC(portmap)服务请求服务端的NFS端口
4)服务端的RPC(portmap)服务反馈NFS端口信息给客户端。
5)客户端通过获取的NFS端口来建立和服务端的NFS连接并进行数据的传输。
举例:
当服务器端, 启动了rpcbind 和 nfs 这两个服务后, 我们查看服务器端网络状况.
$sudo netstat -lntp
tcp 0 0 0.0.0.0:2049 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:111 0.0.0.0:* LISTEN 614/rpcbind
tcp 0 0 0.0.0.0:20048 0.0.0.0:* LISTEN 910/rpc.mountd
tcp 0 0 0.0.0.0:662 0.0.0.0:* LISTEN 877/rpc.statd
rpcbind:
它响应RPC服务的请求和与请求的RPC服务建立连接
nfs
最主要的NFS服务提供程序,这个daemon主要的功能就是管理客户端是否能够使用服务器文件系统挂载信息,其中还包含判断这个登录用户的ID。
rpc.mountd
这个daemon主要功能则是管理NFS的文件系统。当client端顺利通过rpc.nfsd登入主机后,在它可以使用NFS服务器提供规定文件之前,还会经过文件使用权限的认证程序。它会去读取NFS的配置 文件/etc/exports来对比客户端的权限,当通过这一关之后,client端也就取得使用NFS文件的权限。
rpc.statd(非必要)
这个daemon可以用来检查文件的一致性,若发生因为客户端同时使用同一个文件造成文件损坏时,rpc.statd可以用来检测并尝试恢复该文件
可以看到, rpcbind 监听在111端口, nfs监听在2049 端口.
我们在使用rpcinfor -p 查看nfs的服务时, 会看到nfs注册了以下服务,

1 rpcinfo -p 2 3 4 program vers proto port service 5 100000 4 tcp 111 portmapper 6 100000 3 tcp 111 portmapper 7 100000 2 tcp 111 portmapper 8 100000 4 udp 111 portmapper 9 100000 3 udp 111 portmapper 10 100000 2 udp 111 portmapper 11 100005 1 udp 20048 mountd 12 100005 1 tcp 20048 mountd 13 100024 1 udp 662 status 14 100024 1 tcp 662 status 15 100005 2 udp 20048 mountd 16 100005 2 tcp 20048 mountd 17 100005 3 udp 20048 mountd 18 100005 3 tcp 20048 mountd 19 100003 3 tcp 2049 nfs 20 100003 4 tcp 2049 nfs 21 100227 3 tcp 2049 nfs_acl 22 100003 3 udp 2049 nfs 23 100003 4 udp 2049 nfs 24 100227 3 udp 2049 nfs_acl 25 100021 1 udp 32769 nlockmgr 26 100021 3 udp 32769 nlockmgr 27 100021 4 udp 32769 nlockmgr 28 100021 1 tcp 32803 nlockmgr 29 100021 3 tcp 32803 nlockmgr 30 100021 4 tcp 32803 nlockmgr
假设我们现在以vi编辑器打开并修改某个以nfs方式挂载至客户机的文件t的文件test.txt
客户端portmap 首先向服务器端的111端口发起请求, 询问nfs服务的端口号, 服务端portmap会反馈2049, 客户端立即通过2049端口与服务端建立链接.
建立链接后, 服务端进一步发送访问test.txt的请求, 服务段经过nfs_acl鉴权, 如果用户有权限访问, 則放行请求, 否则提示权限不足, 由于是写文件, 需要通过nlockmgr获得文件锁, 否则等待锁释放.
2.2 配置要共享的文件
创建共享目录:
mkdir /shared chmod 777 /shared
注意:初次配置NAS 建议将权限设置为777, 有助于顺利测试后续的挂载, 测试读取,创建,删除,修改文件, 但是这样设置是有安全风险的, 后续熟悉了用户身份映射再回来设置合适的权限. 另外此处我以root用户身份创建的/shared目录, 所有共享目录的owner也是root, 后续等弄明白了身份映射, 也建议回头把owner改为合适的owner. 当前阶段因为权限设置为了777, Owner也不是重点, 不影响将整个流程走通.
配置共享目录细节:
sudo vi /etc/exports #添加如下内容 /shared 192.168.0.0/16(rw,root_squash,all_squash,sync,anonuid=1000,anongid=1000)
加载NFS配置
sudo exportfs -r
初次看到这么一长串其实挺令人费解的, 这些都是什么鬼, 除了rw比较熟悉一点,猜也能猜出来是可读写以外, 其他都是一头雾水.
这里其实不必太纠结, 直接设置为最开放的权限 /shared *(rw) 继续往后走好了, 后续也不会遇到一些莫名其妙的问题, 把流程走通最重要, 后续再回头来将设置调精细, 尤其是初次配置NAS, 这样设置可以避免很多坑, 以免将自己弄得很沮丧.
当你回头来调参数的时候,就需要了解以下内容了.
第一点: NAS 客户端是不需要登陆即可访问共享目录的, 哪服务器端如何知道访问者是谁,访问者该拥有多大权限的呢?
答案就是通过ip 地址和客户端的当前用户id, 和组id , 通过IP 控制是否能访问NAS服务, 通过用户ID控制能访问什么文件, 有多大权限, 当然这种简单的权限控制模型会有缺陷, 要做到相对安全也要看个人的配置能力,以及对NFS的理解程度.
这里我在/etc/exports文件中指定的是一个网段192.168.0.0/16, 什么意思呢? 也就是这个网段的用户可以访问NAS上的此目录, 当然也可以按单个ip地址配置, 可以将网段替换为ip地址, 这样就只有指定ip地址的用户可以访问共享目录这样就精细化了很多, 当然 ip地址是容易伪装, 替换, 以及变化的, 这就是NAS 权限控制比较理想化的地方, 如果是在局域网内,就看管理员如何控制好ip地址的分配, 路由设置等水平了, 所以安不安全要看管理员的水平. 这里也可以配置为通配符, 例如 *, 任何ip过来的用户都可以访问.
刚刚讲到了 ip 地址是NAS 权限控制的重要因子, 另外客户端uid, gid 也是权限控制的重要因子, NAS很好的利用了Linux的权限管理模型, 对熟悉Linux/Unix的系统的用户也降低了学习难度. 首先假设这里配置是no_root_squash, no_all_squash, 这两个选项是什么意思? 先简单介绍这两个选项的作用, 就是不要做身份映射, 简单来说就是, 如果客户端当前是 root用户, 那么他访问共享目录的身份就是root, (当然是不是 root 用户是取决于他的用户id, 而不是用户名, 我们知道所有的linux root 用户的ID都是0, 所属组ID是0, 这里为了便于描述使用用户名代表root用户) , 如果是普通用户 例如zhangsan (uid:999), 那么他操作共享目录的身份就是zhangsan, 那么张三有什么样的权限呢? 还记得我们创建共享目录的时候设置了什么样的访问权限吗? chmod 777 /shared, 张三不是owner, 不属于root组, 张三应该属于others(其他用户) , others对该目录用户读写执行权限. 假设我们创建共享目录的时候是这样 chmod 770 /shared, 那么张三是没有任何权限, 对目录中的文件及文件夹不能进行任何操作. 这就是我为什么在创建共享目录的时候建议大家先授予目录777权限, 权限似乎大的吓人, 但是后续就好发现它的好处, 因为我们在客户端配置,测试的时候, 往往可能就是其他用户, 不是root, 也不属于root的用户, 尤其在windows上访问NAS.
从以上的描述, 不知道各位看官有没有发现一个问题或者叫漏洞( 我担心在本已很复杂的逻辑,再引入一个复杂的问题, 会让人晕掉,所以前面只字未提这个, 现在另起一段来讨论这个问题). 这里先假设客户端有个叫zhangsan(uid:999) 的用户, 服务器端也有zhangsan(uid:999) 的用户, 那很好啊,客户端的张三就像服务器端的张三一样读或写共享目录.接下来的问题就复杂一些了, 假设服务器端压根就没有 zhangsan(uid:999) 的用户, 连uid为999的用户都没有, 那会怎样? 大家可以把流程走通后自己测试一下, 我已经测试过了, 张三依然能访问目录, 而且当张三创建新文件的时候, 会创建一个uid:999的文件, 当我ls -lt 查看此文件的时候, 只能看到文件的 owner是999, 不会显示owner的名字, 如果再进一步使用服务器端用户访问此文件, 如果服务器端的 umask 是0022 除了root 没有一个用户能查看,修改或删除它. 这样其实带来一个好处, 只有客户端用户能访问他所创建的文件, 如果我们严格限制服务器端的 root权限, 理想状况下能很好的保护客户端用户的隐私.
另起一段, 让事情再复杂一些, 假设服务器上没有zhangsan(uid:999) 这个用户, 只有有李四lisi(uid:999) 这个用户, 那么会怎样? 此时, 张三创建的文件, 会显示 owner 是李四(lisi), 如果这个文件里面有张三的隐私的话, 那么张三的隐私有可能被泄露, 如果是钱的哈, 有可能被转走. 这很不安全,NAS为我们留下了一个巨大的安全漏洞, 也给我们提供了解决办法, 那么怎么防止这一点呢, linux 也可以做到, 这就需要研究ACL权限控制了, 这里不做展开.
以上不算最严重的情况, 毕竟服务器端, 恶意篡改的可能性相对比较小, 也容易控制. 下面这种情况就比较糟糕了, 假设现在有多个客户端可以访问共享目录, 这些客户机上分别有 李四 lisi(uid:999) 王五 wangwu(uid:999), 赵六zhaoliu(uid:999) , 那么他们都能看到彼此创建的文件, 如果是隐私或保密数据, 那将是是糟糕的不能再糟糕的一件事情. 难道隐私数据就不能放在NAS上吗? 之前说了, 这取决于管理员的配置水平, NAS权限配置可以精细到单个ip级别, 不同的ip只能访问到不同的目录, ip+uid 可以让用户彼此隔离开来, 或者引入LDAP, 单点登录, 让不同的用户拥有不同的uid也能防止重复的问题, 而且可以很好的结合LDAP身份验证功能. 但是任何事物都有两面性, 假设架设NAS的目的就是为了分享, 为了协同工作, 那么这种设置又能很容易的达到目的. 所以NAS的权限管理可以很灵活, 也可以做到很严谨, 也可能很糟糕, 取决于使用目的以及管理水平.
讲了这么多, 才讲完了no_root_squash, no_all_squash 两个选项, 是不是超级复杂? 这就完了吗? 当然还没有完, 因为权限控制问题本身就很复杂, 在任何一个系统中都是逻辑最复杂最混乱的一块. 当我们试图解决客户端uid重复的时候, 有没有发现一个新的问题, 问题一, 如果按ip+uid 唯一映射共享目录, 可以做到很好的隔离, 但是配置文件会膨胀的非常快, 会相当混乱, 维护起来会相当困难, 复杂性转移到了配置管理了, 有没有? 问题二, 如果采用LDAP, 客户端uid可以实现唯一, 但是我们知道任何客户端的东西都可能被恶意篡改, 难免有不怀好意的用户, 那么我们必须把控制权掌握在自己手中, 不给恶意使用者留下机会. 那要怎么办呢? 这里就是身份映射闪亮登场的时候了. 为什么需要身份映射.
刚刚说了, 在以隐私保护,数据安全为导向的权限设置中,最大的威胁是uid重复. 这里我们引入了LDAP, 也就引入了身份验证, 也尽量避免uid重复, 但是防止不了伪造. 我们也知道NAS 没有引入身份验证的功能, 尽量保持简便灵活. 既然没有引入身份验证, 理论上是不能很好的做到数据隔离的, 更何况我们也有数据共享的必要,协作的必要. 引入身份验证可能使得协助,共享变得困难,复杂. 既然不能保证全体用户的隔离, 我们还是能保证部分敏感用户是隔离的. 假设我们以保护张三的隐私为最高优先级, 那么王五赵六的为次优先级. 那么我们就可以把王五赵六映射为nfsnobody, 张三的映射到全服务器上唯一的一个用户上, 这样就避免了张三与其他用户uid冲突的问题, 服务器端严格限制张三对于的uid的权限, 除了root可以访问,尽量不让其他用户访问张三的隐私数据. 当然如果root用户要作恶, 技术手段是很难防止的了得, 只有通过行政手段,法律措施, 规章制度来保证.
这应该就是引入 root_squash, all_squash, anonuid, anongid的目的, 要搞懂这些选项, 先要弄懂这几个单词的含义很重要, squash 这里采用的是压扁的意思, 想象一下网络上的用户(赵钱孙李,周吴郑王) 像潮水一遍的向NAS涌来, 在进入nas服务之前, 将他们压缩,压扁成一个用户nfsnobody(nfs小人物) 当我们在服务器上安装nfs-utils的时候,默认就会创建一个nfsnobody用户, 如果我们不想使用nfsnobody, 或者一个nfsnobody根本不够用, 我们可以使用 anonuid 指定映射身份. root_squansh 表示无论那个客户端来的root压扁成nfsnobody, all_squash 表示无论哪个客户端来的普通用户压扁成服务器上的nfs小人物, 那么大人物是谁? 就是那些以真实身份访问服务器的用户, 他们的隐私应该得到更好的保护. anonuid 中的anon 就是anonym匿名或无名的缩写(a是否定前缀, nonym跟name同源, 相当于中文的无名), uid 则对于 linux uid (user id), 这样这些选项就容易理解, 不容易配错了. sync选项与权限无关,是用来控制内存数据和硬盘数据是否同步, 要深入了解这个选项, 就要进一步了解Linux 的IO模型, 网络传输协议了, 此处不做展开.
2.3 配置NFS相关服务
2.3.1 设置开机启动
systemctl enable rpcbind systemctl enable nfs
systemctl enable nfs-lock
systemctl enable nfs-idmap
2.3.2 启动服务
systemctl start rpcbind systemctl start nfs
systemctl start nfs-lock
systemctl start nfs-idmap
2.3.3 查看端口占用,以便开着防火墙的时候设置
rpcinfo -p
program vers proto port service 100000 4 tcp 111 portmapper 100000 3 tcp 111 portmapper 100000 2 tcp 111 portmapper 100000 4 udp 111 portmapper 100000 3 udp 111 portmapper 100000 2 udp 111 portmapper 100005 1 udp 20048 mountd 100005 1 tcp 20048 mountd 100005 2 udp 20048 mountd 100005 2 tcp 20048 mountd 100005 3 udp 20048 mountd 100005 3 tcp 20048 mountd 100024 1 udp 662 status 100024 1 tcp 662 status 100003 3 tcp 2049 nfs 100003 4 tcp 2049 nfs 100227 3 tcp 2049 nfs_acl 100003 3 udp 2049 nfs 100003 4 udp 2049 nfs 100227 3 udp 2049 nfs_acl 100021 1 udp 32769 nlockmgr 100021 3 udp 32769 nlockmgr 100021 4 udp 32769 nlockmgr 100021 1 tcp 32803 nlockmgr 100021 3 tcp 32803 nlockmgr 100021 4 tcp 32803 nlockmgr
2.4 NAS文件名字符集问题
前面分析了, 客户端uid不一致可能和服务器端不一致, 会带来很多安全问题. 下面讨论一下客户端与服务器端字符集不一致可能导致的问题. 客户端的字符集可能千奇百怪, 服务器端只能设置一种字符集, 如何以不变应万变呢? 首先我们要搞清楚文件在计算机中是如何存储的, 也不用太深入, 起码要弄明白两个概念, inode, block. 我们经常会见到乱码的问题, 尤其是文件名, 当然如果内容是文本文件, 当使用文本编辑器打开的时候也会遇到乱码的问题, 如果是binary文件, 给机器读取的,到是不必太过担心. 下面我们来分析一下, 为什么会遇到乱码问题. 文件名是存储在inode中的, 二进制数据在传输的过程中, 理论上是不会改变的, 如果客户端是GBK编码的二进制信息, 服务器收到的后会原样保存, 如果客户端和服务器端字符编码不一致, 这时候服务器端可能看起来就是乱码. 这种情况下, 只是NAS 管理员看到文件名很迷糊, 客户端没影响, 这不影响客户的使用, 但是影响管理员的管理工作, 试想如果管理员要给文件移动一个位置, 面对一堆乱码, 确实是很头疼的一件事.
这里让问题再复杂一些, 假设现在有两个客户端同时能访问, 编辑同一个共享文件, 他们的编码方式还不一样, 那么甲保存的文件名, 乙看起来可能就是乱码. 乙修改后甲看起来就是乱码, 如果两个人脾气不好, 有可能打起来, 如果两人都比较温和内向, 也有可能心生怨恨. 这里个人觉得没有什么很好的办法彻底解决乱码的问题, 只有一些折中的方案, 第一点, 尽量不要使用中文命名文件, 不是万不得已尽量不要使用中文来命名文件. 第二点, 服务器端和客户断尽量使用utf8编码, 毕竟他支持的中文字符要全面, 也支持其他各国文字, 唯一的缺点是部分中文字符需要四个字节来存储, 大部分中文常用字符也需要二到三个字节来存储, 考虑到现在计算机的存储相对便宜, cpu的速度很快, 大多数情况都不饱和, 如果你的系统对存储,对性能要求不是十分的苛刻, 服务器端尽量使用utf8, 做到对尽量多的字符提供支持. 客户端如果能统一编码方式为utf8那是最好, 如果不能只能告诉客户端很抱歉, 我们只能做到这种地步了, 最多能在提供一个工具在客户端转码吧, 毕竟utf8编码还可以嗅探出编码格式, 如果是其他编码格式, 可能无能为力. 如果你有更好的解决方案, 欢迎在下方留言.
inode 存储了如下信息:
inode包含文件的元信息,具体来说有以下内容:
* 文件的字节数
* 文件拥有者的User ID
* 文件的Group ID
* 文件的读、写、执行权限
* 文件的时间戳,共有三个:ctime指inode上一次变动的时间,mtime指文件内容上一次变动的时间,atime指文件上一次打开的时间。
* 链接数,即有多少文件名指向这个inode
* 文件数据block的位置
例如我们使用stat命令查看一个文件的inode信息, 我特意创建了一个中文命名的文件, 现在假设服务器上使用的是utf-8编码, 客户端是GBK编码, 那么客户端看到的文件名就可能是乱码.
[root@i-mywts1aa test]# stat 测试.txt
File: ‘测试.txt’
Size: 0 Blocks: 0 IO Block: 4096 regular empty file
Device: 25h/37d Inode: 250655 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2020-11-18 02:36:02.309190000 +0800
Modify: 2020-11-18 02:36:02.309190000 +0800
Change: 2020-11-18 02:36:02.309190000 +0800
Birth: -
三, 客户端安装与设置
3.1 Linux客户端
安装必要软件
yum -y install nfs-utils showmount -e 192.168.1.13 //192.168.1.13 为nfs 服务器ip
单次手动挂载,创建目录,修改权限:
创建挂载点:
mkdir /mnt/data chmod 777 /mnt/data //此处权限需要根据实际情况调整, 777 权限过于开放
挂载:
mount -t nfs 192.168.1.13:/shared /mnt/data
查看挂载:
#df -h文件系统 容量 已用 可用 已用% 挂载点
devtmpfs 898M 0 898M 0% /dev
tmpfs 910M 0 910M 0% /dev/shm
tmpfs 910M 9.6M 901M 2% /run
tmpfs 910M 0 910M 0% /sys/fs/cgroup
/dev/mapper/centos-root 47G 8.5G 39G 18% /
/dev/sda1 1014M 150M 865M 15% /boot
tmpfs 182M 0 182M 0% /run/user/0
192.168.1.13:/shared 27G 2.4G 25G 9% /mnt/data
卸载
umount /mnt/data
开机自动挂载
修改/etc/fstab, 添加一条
192.168.1.13:/shared /data nfs defaults,_rnetdev 1 1
备注:第1个1表示备份文件系统,第2个1表示从/分区的顺序开始fsck磁盘检测,0表示不检测。
_rnetdev 表示主机无法挂载直接跳过,避免无法挂载主机无法启动
3.2 Windows客户端
Windows下面默认没有mount,需要添加功能。
比如Windows 10:(备注: windows 10家庭版除外,家庭版不带nfs功能, 需要专业版或企业版 )
设置->应用->程序和功能->启用或关闭Windows功能:勾选上NFS服务
很多博客都讲了windows上如何挂载 但是没有讲如何取消挂载
删除可以使用图形界面取消, 也可以使用umount 命令 例如:
用法: umount [-f] <-a | drive_letters | network_mounts>
umount G:
-a 删除所有 NFS 网络装入点
-f 强制删除 NFS 网络装入点
四, 遇到的坑
clnt_create: RPC: Port mapper failure – Timed out
STATD_OUTGOING_PORT=2020
原因:端口被防火墙屏蔽,
解决办法: 设置防火墙,接收来自nfs各端口的上行请求
五, 参考文档:
https://www.cnblogs.com/cash/p/13433978.html
https://blog.51cto.com/yttitan/2406403
http://blog.chinaunix.net/uid-1829236-id-3242030.html
http://www.360doc.com/content/12/0830/10/21412_233142313.shtml