传统地,NFS服务器信任由客户端所发送的UID(NFSv2, NFSv3)或用户名(NFSv4),并且不提供(密码学意义上的)加密。这给予潜在的攻击者可乘之机。Kerberos可被用于弥补上述两个问题。
上文记述了Kerberos KDC的架设。在此文中,将用Kerberos完成对NFS(v4)的鉴权和加密。
假设
- Kerberos KDC的域名是
kdc.oxlab.org
- NFS服务器的域名是
n.oxlab.org
- NFS客户端的域名是
r.oxlab.org
- 其他来自上文的(与KDC相关的)假设
NFSv4
设置过程大抵按照ArchWiki上的NFS一文1的第2, 3章节完成。仅使用NFSv4,并不使用NFSv3。在此过程中有两点需要注意:
- 在
/etc/idmapd.conf
中设置域名。须确保客户端和服务器配置相同域名。本例中,设置为oxlab.org
。 - 执行
systemctl mask rpcbind.socket rpcbind.service nfs-server.service
以确保停用NFSv3。
在此之后,服务器端新产生的监听端口应仅有TCP/2049
(NFS),而没有111
(portmapper),如有后者则表明未停用NFSv3。
可能的问题: 无法执行chown
这是由于NFS的idmapd没有被启动造成的。nfs-utils上游提供的nfs-idmapd.service
(一般位于/usr/lib/systemd/system/nfs-idmapd.service
)内容如下:
[Unit]
Description=NFSv4 ID-name mapping service
DefaultDependencies=no
Requires=rpc_pipefs.target
After=rpc_pipefs.target local-fs.target network-online.target
Wants=network-online.target
BindsTo=nfs-server.service
[Service]
Type=forking
ExecStart=/usr/sbin/rpc.idmapd
其中,BindsTo=nfs-server.service
一行造成了这个问题。nfs-server.service
系NFSv3服务器,而idmapd被用于NFSv4,且上文已将nfs-server.service
遮蔽(systemctl mask
),故nfs-idmapd.service
未被启动。
可将/usr/lib/systemd/system/nfs-idmapd.service
复制到/etc/systemd/system/nfs-idmapd.service
,并删去其中BindsTo=nfs-server.service
一行,或将其修改为BindsTo=nfsv4-server.service
,再执行systemctl daemon-reload
便可解决。
至此,一个工作正常的NFSv4服务器/客户端被架设。
NFSv4 + Kerberos: 挂载
为客户端和服务器创建Kerberos principals,并加入global keytab (/etc/krb5.keytab
)
# kadmin5
addprinc -randkey nfs/n.oxlab.org
addprinc -randkey host/n.oxlab.org # 非必要
addprinc -randkey host/r.oxlab.org
在客户端执行systemctl enable --now nfs-client.target gssproxy.service
,在服务器执行systemctl enable --now gssproxy.service
。之后在客户端挂载服务器上导出(export)的目录,添加-o vers=4,sec=krb5p
为挂载选项以使用Kerberos加密。
此时,挂载可以正常完成,但任何用户,包括root
,无法访问挂载的目录。
可能导致无法挂载的问题
- 主机名与Kerberos principals不匹配,或未正确设置DNS解析: 向
/etc/hosts
添加相关字段以解决。 - KDC/服务器/客户端的系统时间不同步或导致Kerberos不能正常工作,启用NTP以防止这种情形。
使客户端的主机密钥映射为root
对服务器的/etc/krb5.conf
做如下修改(添加了以auth_to_local
开始的两行),便可使客户端的主机密钥(host/r.oxlab.org
)被映射为服务器的root
用户23。这样,在客户端使用root
便可以访问挂载的目录了——这相当于在服务器上使用root
访问。
[libdefaults]
default_realm = OXLAB.ORG
[realms]
# use "kdc = ..." if realm admins haven't put SRV records into DNS
OXLAB.ORG = {
admin_server = kdc.oxlab.org
kdc = kdc.oxlab.org
default_principal_flags = +preauth
auth_to_local = RULE:[2:$1/$2@$0](host/r.oxlab.org@OXLAB.ORG)s/.*/root/
auth_to_local = DEFAULT
}
[domain_realm]
oxlab.org = OXLAB.ORG
.oxlab.org = OXLAB.ORG
.n.oxlab.org = OXLAB.ORG
.r.oxlab.org = OXLAB.ORG
[logging]
# kdc = SYSLOG:NOTICE
# admin_server = SYSLOG:NOTICE
# default = SYSLOG:NOTICE
出于安全考量,不建议这样做。
至此,使用Kerberos鉴权和加密的NFSv4配置完了。然而,(除root
以外)没有用户能够访问这个挂载点,因此我们还需为每个用户导入Kerberos principal。
NFSv4 + Kerberos: 用户鉴权
为用户(本例中为leo
和jenny
,他们的UID分别是1000
和1001
)创建Kerberos principal并设置密码。
# kadmin
addprinc leo
addprinc jenny
使用ktutil
将两用户的密码分别添加到与其UID对应的GSS-Proxy keytab中4。需要使用root
用户以确保相关文件可写。
# ktutil
addent -password -p leo -k 1 -f
wkt /var/lib/gssproxy/clients/1000.keytab
q
# ktutil
addent -password -p jenny -k 1 -f
wkt /var/lib/gssproxy/clients/1001.keytab
q
为rpc.gssd
设置环境变量GSS_USE_PROXY=yes
以令其使用GSS-Proxy5。在采用systemd的发行版,可创建/etc/systemd/system/rpc-gssd.service.d/gssproxy.conf
并填入一下内容,后执行systemctl daemon-reload; systemctl restart rpc-gssd.service
[Service]
Environment="GSS_USE_PROXY=yes"
至此,用户leo
和jenny
也可以正常地访问他们位于NFS服务器上的内容了——以他们自己的身份,而非root
,就像在服务器上一样。
可能的问题: systemctl daemon-reload
卡住
在客户端通过/etc/fstab
挂载使用了Kerberos的NFS后,运行systemctl daemon-reload
可能十分缓慢,须等待约90秒。(systemd默认的DefaultDeviceTimeoutSec
)
在执行systemctl daemon-reload
时,systemd会对挂载点(包括NFS)运行statfs()
。如将systemd的log level调高至debug(systemctl log-level debug
),可见NFS相关的target出错并最终超时,可能系依赖关系问题导致。
使用systemd.mount
而非/etc/fstab
,并正确配置依赖似乎可以缓解这个问题。以下文件(位于客户端的/etc/systemd/system/mnt.mount)将服务器的/
挂载到客户端的/mnt
[Unit]
Description=NFS mount: /mnt
Wants=nss-lookup.target nfs-client.target
After=nss-lookup.target nfs-client.target
[Mount]
What=n.oxlab.org:/
Where=/mnt
Options=defaults,sec=krb5p,nosuid,noatime,nofail
Type=nfs4
TimeoutSec=20
[Install]
WantedBy=multi-user.target
可能的问题: 性能相关
NFSv4默认的读/写块大小皆为1MiB(1048576)。在一些情况下,减小这个值可能提告性能。
例如,在笔者的系统上,设置rsize=8192,wsize=8192
能显著提告性能。
- https://wiki.archlinux.org/title/NFS ↩︎
- https://web.mit.edu/Kerberos/krb5-latest/doc/admin/conf_files/krb5_conf.html ↩︎
- https://access.redhat.com/articles/4040141 ↩︎
- https://web.mit.edu/kerberos/krb5-1.12/doc/admin/admin_commands/kadmin_local.html#ktadd ↩︎
- https://github.com/gssapi/gssproxy/blob/main/docs/NFS.md#nfs-client ↩︎