Written by: algebnaly
Date: 2025-06-02T17:29:18.000Z
我一种想用NFS在我的各个机器之间共享文件, 但是最简单的NFS配置是不带加密的, 这不安全. 尽管可以使用加密的隧道来实现加密文件传输, 但是局域网内的恶意设备仍然可以伪造IP来强行挂载. 当然我们可以使用iptables来限制nfsv4端口仅在tun设备上暴露来提高安全性. 而且这种配置相当简单直接,只需要一个加密的隧道, 和一行iptables就行, 比下文中提到的使用krb5的方法简单多了, 我专门写了一篇博客来记录我遇到的问题足以说明这其中有多少坑.
但我仍然对于NFSv4+krb5的配置有执念, 以至于我不得不对Linux内核进行调试来理解我遇到的问题.
注意, 下面的描述不是非常严格, 只描述大致的过程, 例如keytab文件一般放在/etc/krb5.keytab,可以通过配置放在其它位置, 而我则假设文件都放在默认的位置.
在使用NFSv4+krb5的配置中,挂载nfs共享目录需要一个machine-cred, 例如host/server1.com@EXAMPLE.ORG.
内核通过upcall调用rpc-gssd来获取machine-cred, rpc-gssd需要构建出machine-cred的principal,
具体的办法是利用客户端的hostname, 首先通过getaddrinfo这个posix接口获取hostname对应的ai_canonname, 获得full_hostname, 接着查找/etc/krb5.keytab,看看是否有对应的principal, 它会尝试
full_hostname$@EXAMPLE.ORGroot/full_hostname@EXAMPLE.ORGnfs/full_hostname@EXAMPLE.ORGhost/full_hostname@EXAMPLE.ORG按如上顺序查找, 如果找到了principal, 那么挂载应该就没问题了.
这里的坑在于我习惯使用短hostname, 例如机器的完全限定域名(FQDN, Fully Qualified Domain Name)是server1.example.org, 我在/etc/hostname里写的是server1, 而在/etc/krb5.keytab里记录的则是
host/server1.example.org@EXAMPLE.ORG, 如果不做其它配置, getaddrinfo返回的ai_canonname可能只是server1,而非FQDN, 导致挂载失败.
解决办法就是在/etc/hosts添加如下的行
127.0.0.1 server1.example.org server1
这应该是getaddrinfo的非标准行为, 但我懒得继续研究getaddrinfo的文档了.
挂载完成之后, 访问该共享目录的用户需要持有用户principal, 例如alici@EXAMPLE.ORG
使用kinit获取用户principal就可以访问共享目录了.
这是可能是因为NFS服务设置了allsquash选项, 导致所有的用户都被映射到匿名用户