使用Stunnel TLS加密NFSv4

NFS客户端和服务器在默认配置下通过明文连接推送文件流量,该默认配置与敏感数据不兼容。 TLS可以包装此流量,最终带来协议安全性。在使用云提供商的NFS工具之前,请查看所有NFS使用情况并在必要时进行保护。


网络文件系统(NFS)是UNIX中最流行的文件共享协议。数十年来,Linux早于旧版本,最现代的v4版本可以轻松地进行防火墙保护,并提供了无缝操作远程文件所需的几乎所有功能,就好像它们是本地的一样。


NFSv4缺少的最明显的功能是本机独立加密。由于缺少Kerberos,因此该协议仅以明文形式运行,因此在现代环境中存在无法接受的安全风险。 NFS在这个缺点中并不孤单,因为我已经在上一篇文章中介绍了明文SMB。与SMB相比,Stunnel上的NFS在更大范围的OS版本上提供了更好的加密(如果与现代OpenSSL一起使用,则可能是AES-GCM),而协议上没有购买付费更新或较新OS版本的压力。


NFS是一种极为常见的NAS协议,并且在云存储中对其提供了广泛的支持。尽管Amazon EC2支持明文和加密的NFS,但Google Cloud在其记录的过程中并未提及数据安全性,并且Microsoft Azure和Oracle Cloud最近针对该协议发起了重大举措,这引起了人们的怀疑。在不受信任的网络上(甚至在托管服务提供商内部)使用这些功能时,必须假定,如果对内容的兴趣最小,则敌对方将捕获,存储和重构易受攻击的流量。幸运的是,通过隧道将基于TCP的NFS与TLS加密包装起来虽然不明显,但却很简单。


通过隧道在NFS上建立隧道的性能损失非常小-通过加密的NFSv4.2连接传输Oracle Linux安装ISO的速度与纯文本速度的5%之内。熔断器-sshfs的性能更为惊人,它在传输速度上甚至击败了纯文本NFSv4.2。 NFS在可靠性,动态idmap和弹性方面仍然优于sshfs,但是FUSE和OpenSSH提供的性能远远超出预期。


安装

大多数NFS客户端和服务器代码已经存在于Linux内核中,包括与Sun原始v2和v3服务器以及v4兼容的实现。运行中的NFS服务器确实需要由微小的/usr/sbin/rpc.nfsd二进制文件启动的几个nfsd进程,该二进制文件带有很少的参数,并且主要作为用户空间占位符运行,以调度内核中的文件服务器线程。客户端(将在其中发出TCP数据流的位置)和服务器上都需要使用隧道隧道二进制文件。一些客户端也将需要运行rpc.portmapdæmon,但是大多数客户端现在可以不用它。


在Oracle Linux 7.5及其对等端(CentOS,Scientific Linux,Red Hat)上,可以使用以下命令安装实用程序(可能已经安装了nfs-utils软件包):


yum install nfs-utils stunnel


Ubuntu似乎甚至需要安装完整的nfs-kernel-server才能运行客户端。


如果希望NFS服务在引导时启动,请使用systemd通过以下命令启用它们:


systemctl enable rpcbind
systemctl enable nfs-server
systemctl enable nfs-lock
systemctl enable nfs-idmap


您可以使用相应的启动命令来启动服务(现在不要启动它们):

systemctl start rpcbind
systemctl start nfs-server
systemctl start nfs-lock
systemctl start nfs-idmap

如果要允许通过TCP和UDP的明文NFS进入服务器,请使用以下命令重新配置防火墙。 如果您仅打算通过通道TLS或明文TCP(而不是UDP)允许加密的NFS,请不要运行以下命令:

firewall-cmd --permanent --zone=public --add-service=nfs
firewall-cmd --reload

或者,如果要通过TCP端口2049测试明文NFS,请改为运行以下命令:

iptables -w -I INPUT -p tcp --dport 2049 --syn -j ACCEPT

iptables调用将无法在重新启动后继续运行,并且将不允许UDP传输,但是Firewall-cmd更改将保持不变并提供全功能的NFS访问。


明文NFSv4

我应该从承认该协议未被普遍赞赏开始,开始我对NFSv4的介绍。尽管Linux内核开发人员普遍批评NFS指出了多个版本中的许多主要缺陷,但是OpenBSD项目负责人Theo de Raadt对OpenBSD发行版中v4的状态发表了以下评论:


NFSv4对每个人都是一个巨大的笑话。...NFSv4不在我们的路线图上。他们不断添加[expativeive],这是一个荒谬的肿协议。在大约十年中,真正开始对其进行审核的人们将看到它所隐藏的所有错误。


NFSv4团队成员遵循的设计过程与IPV6人员采用的方法相匹配。 (例如,一旦犯了一个错误,并且有4个人正在运行测试代码,这是一个事实,不能再次更改。)结果是一块未经精制的垃圾。


很多时候,一个人的垃圾是另一个人的财富。尽管Theo de Raadt是一位很有远见的人,并且我们将OpenSSH的使用归功于他,但NFSv4是在隧道TLS上运行的最简单的NFS实现。


NFSv3和更早版本是“无状态”文件服务器-服务器仅记录读取和写入操作,不保留有关客户端使用情况的状态。 NFS广泛使用了Sun ONC RPC(开放网络连接远程过程调用),它由rpc.portmap守护程序与其他几个支持过程协调来实现文件锁定,状态报告,崩溃恢复和ID映射-这些是不同的服务器进程在单独的端口上运行,这些端口将客户端状态信息与文件服务器保持分开。在2008年的一个讨论线程中提出了在v3及更低版本上使用stunnel的问题,其中一个线程参与者提到了他就此主题编写的文档,此文档已被存档。隧道v3的过程非常复杂。


NFSv4将这些有状态活动带入了主协议,并且使用它的客户端不需要与较旧的v3 lockd,statd或任何其他单独的RPC服务进行连接。本地rpc.idmapd是维护适当的所有权和权限所必需的,但是idmapd不需要远程网络连接,除了v4客户端维护的TCP连接已经提供的通道外。


NFS最初在端口2049上通过UDP(不可靠数据报协议)运行,以期望本地网络上的数据包丢失不会严重干扰NFS流量。当高流量导致数据包丢失时,基于UDP的NFS可能会遭受严重损失。 NFSv3新增了在TCP(传输控制协议)上运行的功能,由于对恶劣条件的耐受性更高,Linux上默认将端口2049上的TCP传输。在某些使用场景中,UDP效率更高(有关详细信息,请参见man 5 nfs),但是UDP在stunnel中不起作用,因此在此不做介绍。


首先,配置一个NFS服务器提供给客户端的目录。使用以下命令在服务器计算机上创建并填充目录:


mkdir /home/share

chmod 777 /home/share

cp /etc/services /etc/nsswitch.conf /etc/hosts /home/share

编辑文件/ etc / exports,以便它为客户端的IP地址提供读/写共享:
/home/share 192.168.2.100 (fsid=0,rw)

fsid对NFSv4挂载非常有帮助,在man导出手册页中进行了解释:“对于NFSv4,有一个专有的文件系统,它是所有导出文件系统的根。这是用fsid = root或fsid = 0指定的 两者的含义完全相同。” 建立根fsid将使您的导出工作更加顺畅。


为了说明起见,请定义一个小的Shell函数,并使用它检查rpc进程。 确认没有任何知名的NFS程序正在运行后,启动NFS服务器,然后观察还启动了什么:

fsid对NFSv4挂载非常有帮助,在man导出手册页中进行了解释:“对于NFSv4,有一个专有的文件系统,它是所有导出文件系统的根。这是用fsid = root或fsid = 0指定的 两者的含义完全相同。” 建立根fsid将使您的导出工作更加顺畅。


为了说明起见,请定义一个小的Shell函数,并使用它检查rpc进程。 确认没有任何知名的NFS程序正在运行后,启动NFS服务器,然后观察还启动了什么:

# function pps { typeset a IFS=\| ; ps ax | while read a
do case $a in *$1*|+([!0-9])) echo $a;; esac; done }

# pps rpc
  PID TTY      STAT   TIME COMMAND
  598 ?        S<     0:00 [rpciod]

# systemctl start nfs-server

# pps rpc
  PID TTY      STAT   TIME COMMAND
  598 ?        S<     0:00 [rpciod]
15120 ?        Ss     0:00 /usr/sbin/rpc.statd --no-notify
15131 ?        Ss     0:00 /usr/sbin/rpc.idmapd
15143 ?        Ss     0:00 /sbin/rpcbind -w
15158 ?        Ss     0:00 /usr/sbin/rpc.mountd

显然,与v3相关的守护程序是由Oracle Linux 7下的主文件服务器单元启动的。不要为它们的存在感到惊讶。


在客户端上,您可以将一个条目添加到/ etc / fstab文件中,以定义远程安装-它必须包含服务器的主机名或IP地址,以及(稍后使用)TCP端口号:

192.168.1.200:/ /home/share nfs noauto,vers=4.2,proto=tcp,port=2049 0 0

上面的fstab条目将允许您安装服务器,假定所有防火墙都允许流量并且它们可以相互ping通:

# mount /home/share

# ls -l /home/share
total 664
-rw-r--r--. 1 root root    158 May 16 11:34 hosts
-rw-r--r--. 1 root root   1746 May 16 11:34 nsswitch.conf
-rw-r--r--. 1 root root 670293 May 16 11:34 services

# cp /etc/yum.conf /home/share

# ls -l /home/share

上面的nfsnobody是“ root南瓜”的示例,其中服务器将客户端root帐户的活动转换为非特权用户。 壁球有几种类型,通常是意外情况。


以下是Oracle Linux 5(已停产和不受支持)的示例,其中所有权限都被压缩:

# ll /some/share
total 44604
-rwxr-xr-x   1 nobody nobody  1638192 Jul 28  2016 7za.16.02
-rw-r--r--   1 nobody nobody    57280 Oct 18  2017 fuse-sshfs-2.4-1.el5.i386.rpm
-rwxr--r--   1 nobody nobody   233066 May  2  2017 Oracle_LMS_Collection_Tool.zip

发生这种情况是因为必须在/etc/idmapd.conf文件中指定一个idmap“域”。 默认情况下,通过删除主机名前缀,从完全合格域名(FQDN)中获取NFS域。 如果两个服务器位于单独的DNS域中,则它们的NFSv4安装始终将被完全压缩。 要更正此问题,请手动指定NFS域:

# service rpcidmapd stop
Stopping RPC idmapd:                                       [  OK  ]

# grep ^Domain /etc/idmapd.conf
Domain = master_nfs_domain.yourco.com

# service rpcidmapd start
Starting RPC idmapd:                                       [  OK  ]

# umount /some/share
# mount /some/share

# ls -l /some/share
total 44604
-rwxr-xr-x   1 cfisher grp     1638192 Jul 28  2016 7za.16.02
-rw-r--r--   1 cfisher grp       57280 Oct 18  2017 fuse-sshfs-2.4-1.el5.i386.rpm
-rwxr--r--   1 root    root     233066 May  2  2017 Oracle_LMS_Collection_Tool.zip

请注意,NFSv3及以下版本无法通过这种方式工作。 默认情况下,数字用户和组ID保留在没有idmap访问的普通装载中。 尽管保持uid / gid同步仍然很重要,但是NFSv4不再允许数字映射,因此不要因主动压缩而感到惊讶。


较早的Linux内核在NFSv4挂载中使用略微不同的fstab语法。 在Oracle Linux 5下,请注意(不建议使用)nfs4挂载类型下方,并且缺少vers选项:

server:/ /share nfs4 noauto,proto=tcp,port=2049 0 0

在关闭本节之前,我想返回到客户端上的fstab条目:

192.168.1.100:/ /home/share nfs noauto,vers=4.2,proto=tcp,port=2049 0 0

vers = 4.2请求NFS协议的最新版本,如果服务器上不可用,该版本将失败。 如果您使用的是旧服务器,请减少此版本。 客户端主要负责确定连接的协议版本和功能设置(尽管服务器可以在/etc/nfs.conf和/ etc / sysconfig / nfs中启用/禁用特定的NFS版本和系统范围内的某些功能)。


上面的noauto可以通过在启动时默认不挂载它们来防止由于无法访问的NFS服务器而导致的启动延迟。 我的建议是始终使用noauto来避免引导挂在“ NFS服务器未响应”上。 有一个“后台安装”选项很有用,但我更喜欢在(Vixie)crontab中为根目录重新启动,以确保NFS不会干扰获得登录名或以其他方式启动本地服务。 您可以使用以下crontab条目完成此操作:

@reboot /sbin/mount /home/share

更合适的方法是将所有自定义启动都放在单个脚本中,然后将脚本添加为重新启动条目。 确保按照偏好和延迟容忍的顺序将NFS挂载放置在最后(您可以将特别有问题的挂载作为后台进程启动)。


有些人表示对各种来源的NFS自动安装程序的亲和力。 我没有足够的安装来证明维护多个客户端自动安装配置的合理性,因此在此省略了此类讨论。 幸运的是,如果您要遵循这里的规定,可以对大多数的自动安装程序进行兼容。


带有tunnel的TLS上的NFSv4

TCP连接离开客户端之前的侦听将需要用于本地端点的端口。 还必须在服务器上为TLS服务选择一个新端口。 作为参考,以下端口似乎与NFS相关:

# egrep -i '([^a-z]nfs|nfs[^a-z])' /etc/services

nfs             2049/tcp  nfsd shilp # Network File System
nfs             2049/udp  nfsd shilp # Network File System
nfs             2049/sctp nfsd shilp # Network File System
picknfs         1598/tcp             # picknfs
picknfs         1598/udp             # picknfs
3d-nfsd         2323/tcp             # 3d-nfsd
3d-nfsd         2323/udp             # 3d-nfsd
mediacntrlnfsd  2363/tcp             # Media Central NFSD
mediacntrlnfsd  2363/udp             # Media Central NFSD
winfs           5009/tcp             # Microsoft Windows Filesystem
winfs           5009/udp             # Microsoft Windows Filesystem
enfs            5233/tcp             # Etinnae Network File Service
mountd          20048/tcp            # NFS mount protocol
mountd          20048/udp            # NFS mount protocol
nfsrdma         20049/tcp            # (NFS) over RDMA
nfsrdma         20049/udp            # (NFS) over RDMA
nfsrdma         20049/sctp           # (NFS) over RDMA

为了轻松读取netstat,我打开了服务器上的端口2363,并将客户端安装重定向到其本地端口2323。您可能不希望您的NFS流量易于识别-如果这样,请选择不相关的端口。


至少,隧道TLS服务器必须提供一个密钥对。 我实际上生成了一个有效期为十年的单一自签名密钥对,并将其分发给服务器和所有客户端,这些密钥对将充当“本地协议密钥”,所有成员都必须出示该密钥对并验证所有连接的参与者的正确性。 在这里,我生成一个示例密钥:

$ openssl req -newkey rsa:4096 -x509 -days 3650 -nodes \
  -out nfs-tls.pem -keyout nfs-tls.pem
Generating a 4096 bit RSA private key
.................................................++
...................................++
writing new private key to 'nfs-tls.pem'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:US
State or Province Name (full name) []:IL
Locality Name (eg, city) [Default City]:Chicago
Organization Name (eg, company) [Default Company Ltd]:NFS-TLS
Organizational Unit Name (eg, section) []:CHI
Common Name (eg, your name or your server's hostname) []:nfs-tls
Email Address []:foo@bar.org

上面的命令生成的密钥类似于以下输出。 将文件移动到/ etc / stunnel目录,并将其设置为root的400只读权限。 请勿复制以下内容; 它仅用于演示目的,您必须生成自己的:


# f=nfs-tls.pem; cat $f ; chmod 400 $f ; mv $f /etc/stunnel
-----BEGIN PRIVATE KEY-----
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
NqwdAo0hNa3SsNtiM4Z3TM0RzDLw6fw=
-----END PRIVATE KEY-----

-----BEGIN CERTIFICATE-----
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
-----END CERTIFICATE-----


在文件服务器上,将同一共享的导出添加到localhost。 设置不安全选项,该选项将允许来自1024以上的客户端端口的连接(我暂时讨论了其后果)。 如果要删除明文导出,请确保首先卸载客户端:


$ cat /etc/exports

/home/share  192.168.2.100(fsid=0,ro)
/home/share 127.0.0.1(fsid=0,ro,insecure)

运行以下命令以将共享激活到本地主机:

exportfs -a

在端口2363上添加一个inetd样式的套接字激活单元,以十分钟的超时启动stunnel:

$ cat /etc/systemd/system/MC-nfsd.socket

[Unit]
Description=NFS over stunnel/TLS server

[Socket]
ListenStream=2363
Accept=yes
TimeoutSec=600

[Install]
WantedBy=sockets.target

使用即将定义的设置文件配置套接字以启动stunnel:

$ cat /etc/systemd/system/MC-nfsd@.service

[Unit]
Description=NFS over stunnel/TLS server

[Service]
ExecStart=-/bin/stunnel /etc/stunnel/MC-nfsd.conf
StandardInput=socket

启动套接字,并使用以下命令启用它以在启动时自动启动:

systemctl start MC-nfsd.socket
systemctl enable MC-nfsd.socket


打开端口2363以允许加密的NFS通过防火墙:

iptables -w -I INPUT -p tcp --dport 2363 --syn -j ACCEPT

为NFS服务器创建以下路径控制文件:

$ cat /etc/stunnel/MC-nfsd.conf

#GLOBAL#######################################################

TIMEOUTidle     =       600
renegotiation   =       no
        FIPS    =       no
        options =       NO_SSLv2
        options =       NO_SSLv3
        options =       SINGLE_DH_USE
        options =       SINGLE_ECDH_USE
        options =       CIPHER_SERVER_PREFERENCE
        syslog  =       yes
        debug   =       0
        setuid  =       nobody
        setgid  =       nobody
        chroot  =       /var/empty/stunnel

        libwrap =       yes
        service =       MC-nfsd
        ; cd /var/empty; mkdir -p stunnel/etc; cd stunnel/etc;
        ; echo 'MC-nfsd: ALL EXCEPT 192.168.2.100' >> hosts.deny;
        ; chcon -t stunnel_etc_t hosts.deny

        curve   =       secp521r1
; https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/
↪ciphers=ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+
↪AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS

#CREDENTIALS##################################################

        verify  =       4
        CAfile  =       /etc/stunnel/nfs-tls.pem
        cert    =       /etc/stunnel/nfs-tls.pem

#ROLE#########################################################

        connect =       127.0.0.1:2049

创建chroot()目录,其中stunnel将删除特权:

# mkdir /var/empty/stunnel

尝试与端口2363进行本地明文套接字连接; 隧道配置问题将出现在这里:


# nc localhost 2363
Clients allowed=500
stunnel 4.56 on x86_64-redhat-linux-gnu platform
Compiled/running with OpenSSL 1.0.1e-fips 11 Feb 2013
Threading:PTHREAD Sockets:POLL,IPv6 SSL:ENGINE,OCSP,FIPS
 ↪Auth:LIBWRAP
Reading configuration from file /etc/stunnel/MC-nfsd.conf
FIPS mode is disabled
Compression not enabled
Snagged 64 random bytes from /dev/urandom
PRNG seeded successfully
Initializing inetd mode configuration
Certificate: /etc/stunnel/nfs-tls.pem
Error reading certificate file: /etc/stunnel/nfs-tls.pem
error queue: 140DC002: error:140DC002:SSL
 routines:SSL_CTX_use_certificate_chain_file:system lib
error queue: 20074002: error:20074002:BIO
 routines:FILE_CTRL:system lib
SSL_CTX_use_certificate_chain_file: 200100D:
 error:0200100D:system library:fopen:Permission denied
Service [MC-nfsd]: Failed to initialize SSL context
str_stats: 11 block(s), 355 data byte(s), 638 control byte(s)

在这种情况下,启用了SELinux,并且键上的类型阻止了tunnel读取它。 需要使用chcon命令来解决此问题:

# cd /etc/stunnel

# ls -lZ
-rw-r--r--. root root XXX:XXX:stunnel_etc_t:s0 MC-nfsd.conf
-r--------. root root XXX:XXX:user_home_t:s0 nfs-tls.pem

# chcon -t stunnel_etc_t nfs-tls.pem

# ls -lZ
-rw-r--r--. root root XXX:XXX:stunnel_etc_t:s0 MC-nfsd.conf
-r--------. root root XXX:XXX:stunnel_etc_t:s0 nfs-tls.pem

当您可以无误运行netcat时,就可以开始使用客户端了。 在NFS客户端上添加inetd样式的套接字激活单元:

$ cat /etc/systemd/system/3d-nfsd.socket

[Unit]
Description=NFS over stunnel/TLS client

[Socket]
ListenStream=2323
Accept=yes
TimeoutSec=300

[Install]
WantedBy=sockets.target

使用即将定义的设置文件配置套接字以启动stunnel:

$ cat /etc/systemd/system/3d-nfsd@.service

[Unit]
Description=NFS over stunnel/TLS client

[Service]
ExecStart=-/bin/stunnel /etc/stunnel/3d-nfsd.conf
StandardInput=socket

为NFS客户端创建一个通道控制文件:

$ cat /etc/stunnel/3d-nfsd.conf

#GLOBAL#######################################################

sslVersion      =       TLSv1.2
TIMEOUTidle     =       600
renegotiation   =       no
        FIPS    =       no
        options =       NO_SSLv2
        options =       NO_SSLv3
        options =       SINGLE_DH_USE
        options =       SINGLE_ECDH_USE
        options =       CIPHER_SERVER_PREFERENCE
        syslog  =       yes
        debug   =       0
        setuid  =       nobody
        setgid  =       nobody
        chroot  =       /var/empty/stunnel

        libwrap =       yes
        service =       3d-nfsd
        ; cd /var/empty; mkdir -p stunnel/etc; cd stunnel/etc;
        ; echo '3d-nfsd: ALL EXCEPT 127.0.0.1' >> hosts.deny;
        ; chcon -t stunnel_etc_t hosts.deny

        curve   =       secp521r1
; https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/
↪ciphers=ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:
↪ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS

#CREDENTIALS##################################################

        verify  =       4
        CAfile  =       /etc/stunnel/nfs-tls.pem
        cert    =       /etc/stunnel/nfs-tls.pem

#ROLE#########################################################

        client  =       yes
        connect =       nfs-server.yourco.com:2363

注意:我之前用IP地址192.168.1.100引用服务器,但是在它上面是nfs-server.yourco.com,请使用您喜欢的任何形式的主机名。


最新的Ubuntu配备了“ stunnel4”,实际上是stunnel版本5.44。 它不能与NO_SSLv2或SINGLE _ * _ USE选项中的任何一个一起运行(必须将其删除),并且上面的setgid选项应在其中使用组“ nogroup”。


修改/ home / share的fstab条目以连接到本地stunnel:

$ grep share /etc/fstab
localhost:/ /home/share nfs noauto,vers=4.2,proto=tcp,port=2323 0 0

挂载该卷,并检查是否有隧道程序,然后检查活动的网络连接:

# mount /home/share

# pps stun
  PID TTY      STAT   TIME COMMAND
 5870 ?        Ss     0:00 /bin/stunnel /etc/stunnel/3d-nfsd.conf

# netstat -ap | grep nfsd
tcp        0      0 localhost:860        localhost:3d-nfsd
 ↪ESTABLISHED -
tcp        0      0 squib:48804          192.168.:mediacntrlnfsd
 ↪ESTABLISHED 5870/stunnel
tcp6       0      0 [::]:3d-nfsd         [::]:*
 ↪LISTEN      1/init
tcp6       0      0 localhost:3d-nfsd    localhost:860
 ↪ESTABLISHED 1/init

# ls -l /home/share/
total 676
-rw-r--r-- 1 root    root       158 May 21 18:58 hosts
-rw-rw-r-- 1 cfisher cfisher   5359 May 21 19:22 nfs-tls.pem
-rw-r--r-- 1 root    root      1760 May 21 18:58 nsswitch.conf
-rw-r--r-- 1 nobody  nogroup   1921 May 21 19:17 passwd
-rw-r--r-- 1 root    root    670293 May 21 18:58 services

另外,检查服务器的通道过程和网络状态:

# pps stun
  PID TTY    STAT   TIME COMMAND
16282 ?      Ss     0:00 /bin/stunnel /etc/stunnel/MC-nfsd.conf

# netstat -ap | grep nfsd
tcp6       0      0 [::]:mediacntrlnfsd     [::]:*
 ↪LISTEN      1/systemd
tcp6       0      0 192.168.:mediacntrlnfsd 192.168.0.24:48824
 ↪ESTABLISHED 1/systemd

压缩权限可能会记录在您的系统日志中:

rpc.idmapd[4321]: nss_getpwnam: name 'cfisher@yourhost'
  does not map into domain 'localdomain'

为了解决这个问题,您需要在/etc/idmapd.conf中手动设置域。


NFS客户端上的主要问题是任何本地用户能否通过SSH或其他端口转发工具连接到NFS端点。 他们可以将其转发到他们选择的服务器(并在他们的控制下)以安装和操作远程文件服务器。 客户端上的任何本地用户都可以:

# telnet localhost 2323
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.

Connection closed by foreign host.

连接到端点的能力赋予了对其进行控制的能力。


没有本机stunnel选项来限制客户端对特权端口的访问,但是您可以编写自己的包装程序来限制此访问-它在验证传入端口具有特权之后调用exec()函数以启动stunnel,并传递活动端口。 替换过程的文件描述符。 要使用此包装器,请放置以下文件:

# cat /bin/pstunnel.c

#include <stdio.h>
#include <unistd.h>
#include <arpa/inet.h>


int main(int argc, char *argv[], char *envp[])
{
 struct sockaddr_storage addr;
 socklen_t len = sizeof addr;
 int port = 65535, bad = 0;

 if(getpeername(fileno(stdin), (struct sockaddr *) &addr, &len)) bad = 1;
 else if(addr.ss_family == AF_INET) //IPv4
 {
  struct sockaddr_in *s = (struct sockaddr_in *) &addr;
  port = ntohs(s->sin_port);
 }
 else if(addr.ss_family == AF_INET6) //IPv6
 {
  struct sockaddr_in6 *s = (struct sockaddr_in6 *) &addr;
  port = ntohs(s->sin6_port);
 }
 else bad = 1;

 if(!bad && port < IPPORT_RESERVED) execve("/bin/stunnel", argv, envp);
 else printf("Nope.\n");
}

使用以下命令编译特权包装器:

# cd /bin

# cc -s -O2 -DFORTIFY_SOURCE=2 -Wall -o pstunnel pstunnel.c

修改套接字单元文件以调用特权包装器:

# cat /etc/systemd/system/3d-nfsd@.service
[Unit]
Description=NFS over stunnel/TLS client

[Service]
ExecStart=-/bin/pstunnel /etc/stunnel/3d-nfsd.conf
StandardInput=socket

然后重新加载systemd以识别修改后的单元:

# systemctl daemon-reload

来自非特权客户端的连接现在被阻止,但安装请求仍将通过:

# telnet localhost 2323
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Nope.
Connection closed by foreign host.

# mount /home/share

# pps stun
  PID TTY      STAT   TIME COMMAND
 2483 ?        Ss     0:00 /bin/pstunnel /etc/stunnel/3d-nfsd.conf

# umount /home/share

注意argv [0]将保留包装器的名称。


除了简单地打印“ Nope”之外,您还可以调整包装器,以触发通知,告知非特权用户正在滥用您的端点,这很重要。


pstunnel.c包装器无法在Oracle Linux 5下正常工作。netstat将报告任何活动的NFS挂载源自特权客户端端口,但是在移到xinetd中的特权包装器之后,挂载尝试将失败。观察到的解决方法是在不使用包装程序的情况下进行安装,将xinetd配置切换为pstunnel,然后允许stunnel超时到期,从而导致产生新的stunnel,以服务现有连接以强制执行特权端口。出现此问题的原因似乎是在建立挂载时建立了初步的非特权客户端连接(也许nfsconf中的STATD_OUTGOING_PORT参数是罪魁祸首)。该解决方法在其他操作系统上可能很有用,因此即使Oracle Linux 5不在支持范围内,我也将其包括在此处。


如果您使用的系统不使用防火墙阻止与2323端点的远程连接,则应使用客户端通道控制文件中上面记录的libwrap功能来限制对本地主机的访问。 libwrap功能在服务器上不太有用,在服务器上必须提供RSA密钥对,然后才能允许访问。


请注意,Microsoft Windows具有可用的NFS客户端,但该平台未遵守对1024以下特权端口的限制-允许任何Windows用户从这些受限端口发起连接,因此低端口筛选将不是有效的安全控制。如果将NFS卷导出到Windows客户端,则必须信任该客户端的所有用户。


还请注意,NFS服务器上的不安全选项将允许本地用户在那里进行类似的恶作剧。 Linux iptables具有一个所有者匹配模块,该模块可以锁定到root用户,可以类似地保护服务器的易受攻击的端口2049。如果您不能保护NFS服务器免受用户建立颠覆性本地连接的影响,则您不应有任何不受信任的本地用户。


最后,请注意,Stunnel控制文件中的以下套接字选项对于NFS可能非常有用:

socket  =       a:TCP_NODELAY=1
socket  =       a:SO_KEEPALIVE=1

NODELAY选项禁用Nagle算法,该算法可防止NFS流量延迟(以(可能)发送“ tinygrams”为代价)—隧道不会等待发送完整的数据包,这将对少量数据进行操作反应更快。如果您将不断交换大量数据,则此选项可能没有帮助。


NFSv4具有深层的文件锁定和“委托”功能,客户端可以无限期地从服务器“检出”文件。如果另一个客户端请求文件,则服务器必须能够与客户端联系以取消委托并获取当前内容,如果通道连接关闭,则不会发生。如果客户端具有服务器的活动,则客户端可以自动重新启动连接,但是相反情况并非如此,这可能会影响锁定和委派。尽管服务器可以使用命令echo'0'> / proc / sys / fs / leases-enable在系统范围内禁用委派,但KEEPALIVE选项可能是一个有用的替代方法,它留给读者作为研究主题。


绩效基准

对于那些真正关心数据安全的人来说,性能是无关紧要的。明文连接上不允许包含敏感信息。尽管如此,了解加密开销必须付出的代价还是很重要的,因此我已经进行了一些简单的测试,涉及NFSv4,以明确惩罚措施。


Linux曾经有一个完全在用户空间中实现的NFS服务器,但是为了提高性能,它已移至Linux 2.2的内核中(仍在积极开发中的用户空间NFS服务器对于特定的应用程序(特别是FUSE)很有用。我原本以为会迫使每边的通道返回用户空间而造成严重的速度损失,但是影响远远小于预期。


我的测试是在运行最新版本的Oracle Unbreakable Enterprise Kernel v4(UEK)的两台HP DL360 G9服务器上执行的。该测试涉及在明文NFS和TLS下将Oracle Linux 7.5安装ISO的副本推送到服务器。


我试图通过NFS发送任何数据之前先清除客户端和服务器上的缓存:

# sync && echo 3 > /proc/sys/vm/drop_caches

我从先前的测试中删除了服务器上的任何ISO副本:

# rm /home/share/V975367-01.iso
rm: remove regular file '/home/share/V975367-01.iso' y

然后,我在客户端上验证了Oracle提供的sha256 ISO哈希,以便将ISO的内容放入客户端的缓冲区高速缓存中:

# tail -1 sha256
D0CC4493DB10C2A49084F872083ED9ED6A09CC065064C009734712B9EF357886
 ↪V975367-01.iso

# sha256sum -c < sha256
V975367-01.iso: OK

此时,我通过明文NFSv4.2连接安装了服务器:

# tail -1 /etc/fstab
1.2.3.4:/ /home/share nfs noauto,vers=4.2,proto=tcp,port=2049 0 0

# mount /home/share

然后,我运行了该副本的三个迭代,每次运行之间都清除了缓存:

# time cp V975367-01.iso /home/share

real    0m39.697s
user    0m0.005s
sys     0m2.173s


# time cp V975367-01.iso /home/share

real    0m39.927s
user    0m0.005s
sys     0m2.159s

# time cp V975367-01.iso /home/share

real    0m39.489s
user    0m0.001s
sys     0m2.218s

通过明文连接移动ISO的平均挂钟时间为39.70秒。 然后,我重新配置为使用stunnel:

# tail -1 /etc/fstab
localhost:/ /home/share nfs noauto,vers=4.2,proto=tcp,port=2323 0 0

# mount /home/share

并再次运行测试:

# time cp V975367-01.iso /home/share

real    0m39.476s
user    0m0.002s
sys     0m2.265s

# time cp V975367-01.iso /home/share

real    0m40.376s
user    0m0.005s
sys     0m2.189s


# time cp V975367-01.iso /home/share

real    0m41.971s
user    0m0.001s
sys     0m2.894s

加密连接的平均时间为40.61,相差2.2%(几乎不需付出高昂的代价)。


DL380服务器具有可实现AES-NI本机指令的CPU,这可能会提高性能。 配置高日志记录的隧道(设置debug = debug),使用的报告密码为ECDHE-RSA-AES256-GCM-SHA384。 没有OpenSSL识别的AES-NI的系统将无法很好地执行此操作。


我还使用EPEL存储库中的fuse-sshfs测试了此活动。 我卸载了NFS,安装了RPM,然后重新连接到远程目标:

# sshfs cfisher@192.168.1.100:/home/share /home/share
The authenticity of host '192.168.1.100 (192.168.1.100)' can't be established.
ECDSA key fingerprint is
 ↪4c:90:f8:48:2e:03:f5:31:30:c1:73:a3:5e:da:42:d3.
Are you sure you want to continue connecting (yes/no)? yes
cfisher@1.2.3.4's password:

然后,我重新运行测试:

# time cp V975367-01.iso /home/share

real    0m38.727s
user    0m0.039s
sys     0m4.733s


# time cp V975367-01.iso /home/share

real    0m39.498s
user    0m0.035s
sys     0m4.751s


# time cp V975367-01.iso /home/share

real    0m39.536s
user    0m0.030s
sys     0m4.763s


标签: 教程

作者头像
南宫俊逸创始人

君子好学,自强不息~

上一篇:如何尝试没有经典安装的Linux
下一篇:NETGEAR 48 端口千兆智能托管加交换机(GS750E)

发表评论

vidnami 在线视频创作工具--做海外推广营销视频必备工具

image.png


我们的折扣优惠是向观众推广Vidnami的绝妙方式。他们将即时访问 25% 的 Vidnami, 再加上我们的视频营销包免费。最棒的是,您将获得所有销售额的50%!

https://www.vidnami.com/c/Mr_xiaoxiao-vn-buy-discount 

期待各位的加入,让原创发挥活力,让阅读更有价值!登录注册
登录
用户名
密码
注册
用户名
密码
确认密码
邮箱
验证码
找回密码
用户名
邮箱
※ 重置链接将发送到邮箱