背景
NFS(Network File System)的 AUTH_SYS(前身为 AUTH_UNIX)认证方式有 16 个辅助群组(supplemental groups)的限制,而 AUTH_GSS(RPCSEC_GSS with Kerberos)认证方式则有 32 个辅助群组的限制。
很多 IC 设计公司使用 AUTH_SYS 方式,都遇到了超过 16 个群组无法使用的问题。这个限制源于 1980 年代 UNIX 操作系统的能力约束,当时支持的辅助群组数量从 8 个演进到 12 个,最终固定为 16 个,这一历史遗留限制至今仍反映在 NFS AUTH_SYS 协议中。
认证方式对比
| 特性 | AUTH_SYS (AUTH_UNIX) | AUTH_GSS (Kerberos) |
|---|---|---|
| 默认辅助群组限制 | 16 个 | 32 个 |
| 安全性 | 低(客户端声明的身份,服务端直接信任) | 高(Kerberos 加密认证) |
| 扩展群组支持 | 可通过服务端查询实现(最高 1024) | 可通过服务端查询实现(最高 1024) |
| 协议定义 | RFC 5531 | RFC 7530 + RFC 2203 |
| 主要限制 | 协议固定 16 群组 | Kerberos token bloat |
分析
问题现象
1
2
3
4
5
6
7
8
9
10
[wanlinwang@VM-AlmaLinux8-tmpl-wanlinwang ~]$ id #从返回结果可知,q是第16群组,r是第17群组。
uid=1001(wanlinwang) gid=1001(p) groups=1001(p),1002(system),1003(b),1004(c),1005(d),1006(e),1007(f),1008(h),1009(i),1010(j),1011(k),1012(l),1013(m),1014(n),1015(o),1016(q),1017(r),1018(s),1019(a),1020(z)
[wanlinwang@VM-AlmaLinux8-tmpl-wanlinwang ~]$ ls -ld /tools/{testq,a}
drwxrwx--- 2 root r 2 Mar 31 11:16 /tools/a
drwxrwx--- 2 root q 2 Mar 31 11:16 /tools/testq
[wanlinwang@VM-AlmaLinux8-tmpl-wanlinwang ~]$ cd /tools/a
-bash: cd: /tools/a: Permission denied
[wanlinwang@VM-AlmaLinux8-tmpl-wanlinwang ~]$ cd /tools/testq
[wanlinwang@VM-AlmaLinux8-tmpl-wanlinwang testq]$
RPC包分析
认证方式是AUTH_UNIX(AUTH_SYS),只传递了16个群组。
源码分析
RFC 5531 协议定义
从 RFC 5531 的 authsys_parms 数据结构可看出,gids 数组大小被硬编码为 16:
1
2
3
4
5
6
7
struct authsys_parms {
unsigned int stamp; // 时间戳
string machinename<255>; // 客户端主机名
unsigned int uid; // 用户 ID
unsigned int gid; // 主群组 ID
unsigned int gids<16>; // 辅助群组 ID 数组(最多 16 个)
};
协议行为
NFS 客户端发送的内容:
- 1 个 UID(用户 ID)
- 1 个主 GID(primary Group ID)
- 最多 16 个辅助 GID(supplemental Group IDs)
超出限制时的行为:
- 如果用户实际属于超过 16 个群组,NFS 客户端会截断(truncate)群组列表
- 被截断的群组信息不会被发送到服务端
- 导致用户无法访问需要这些被截断群组权限的文件/目录
为何不可调整:
[!WARNING] 16 群组限制是 NFS 协议本身的约束,不是可配置参数。在 AUTH_SYS 协议层面,这个限制是不可调整的(non-tunable)。
解决方案
自建 NFS(Linux NFS Server)
rpc.mountd –manage-gids 工作原理
rpc.mountd daemon 是 NFS (v2, v3) MOUNT 协议的服务端实现。通过 -g 或 --manage-gids 选项,可以实现服务端群组管理。
核心机制
- 忽略客户端提供的群组列表
- 启用
--manage-gids后,服务端会忽略客户端在 RPC 请求中发送的最多 16 个 GID
- 启用
- 服务端主动查询
rpc.mountd在服务端执行本地查询,从 Name Service 获取用户的完整群组成员关系- 支持的 Name Service:
/etc/group、LDAP、NIS/NIS+、SSSD
- 内核交互
rpc.mountd通过/proc/net/rpc/auth.unix.gid/channel与 Linux 内核通信- 将完整的 GID 列表提供给内核,用于权限检查
nfsd内核模块维护认证和授权数据的缓存
配置方法
方法 1:命令行参数
1
2
3
4
# 启动 rpc.mountd 时添加 -g 选项
rpc.mountd -g
# 或
rpc.mountd --manage-gids
方法 2:配置文件(推荐)
1
2
3
4
5
6
# 编辑 /etc/nfs.conf(RHEL 8/9, Ubuntu 20.04+)
[mountd]
manage-gids = True
# 或编辑 /etc/sysconfig/nfs(较老版本)
RPCMOUNTDOPTS="-g"
方法 3:systemd 服务配置
1
2
3
4
5
6
7
# 编辑 /etc/systemd/system/nfs-server.service.d/override.conf
[Service]
Environment="RPCMOUNTDOPTS=-g"
# 重载并重启服务
systemctl daemon-reload
systemctl restart nfs-server
前置要求
| 要求 | 说明 |
|---|---|
| Linux 内核版本 | ≥ 2.6.21 |
| Name Service 配置 | /etc/nsswitch.conf 正确配置 group 查询源 |
| LDAP/NIS 可用性 | 若使用外部 Name Service,需确保服务可达 |
| UID/GID 一致性 | 客户端和服务端的 UID/GID 映射必须一致 |
验证配置
1
2
3
4
5
6
# 检查 rpc.mountd 是否启用了 -g 选项
ps aux | grep rpc.mountd
# 测试 Name Service 查询
getent group <groupname>
id <username>
NFSv4 行为说明
NFSv4 的 nfsd 没有显式的 --manage-gids 选项,但其行为类似:
- NFSv4 使用
idmapd进行 UID/GID 映射 - 配合 RPCSEC_GSS(Kerberos)认证时,默认会查询完整的群组成员关系
- 可通过
/etc/idmapd.conf配置映射行为
NetApp
1)必须为NFS Vserver配置LDAP或NIS并使其正常运行。也可以本地SVM UID与群组成员文件。
2)LDAP或NIS服务器必须 为所有用户配置关联的组。
3)配置ns-switch包含 LDAP 或 NIS 进来,
1
2
3
4
5
6
7
8
vs1::> set -privilege advanced
Warning: These advanced commands are potentially dangerous; use
them only when directed to do so by NetApp personnel.
Do you want to continue? {y|n}: y
vs1::*> vserver services name-service ns-switch modify -vserver <svm_name> -database passwd -sources files,nis
vs1::*> vserver services name-service ns-switch modify -vserver <svm_name> -database group -sources files,nis
vs1::*> vserver services name-service ns-switch show
4)通过这两个选项,来打开超过16群组的支持。
1
2
3
4
5
6
7
8
9
10
11
vs1::> set -privilege advanced
Warning: These advanced commands are potentially dangerous; use
them only when directed to do so by NetApp personnel.
Do you want to continue? {y|n}: y
vs1::*> vserver nfs modify -vserver vs1 -auth-sys-extended-groups enabled -extended-groups-limit 512
vs1::*> vserver nfs show -vserver vs1 -fields auth-sys-extended-groups,extended-groups-limit
vserver auth-sys-extended-groups extended-groups-limit
------- ------------------------ ---------------------
vs1 enabled 512
5)调整缓存失效期限(可选但重要)
缓存机制说明
某用户启用了 NetApp 超过 16 群组的支持后发现:
- 群组是先前已加好的 → 访问正常 ✅
- 群组是刚加入的 → 访问失败 ❌
根本原因: Name Service 缓存、凭据缓存失效期限过长。用户在新加群组后几分钟内验证时,缓存仍是旧数据,因此访问被拒绝。
三种缓存类型
| 缓存类型 | 默认 TTL | 作用 | 性能影响 |
|---|---|---|---|
| Name Service Cache | 2 小时 | 缓存从 LDAP/NIS 查询的群组成员关系 | TTL 越短,LDAP/NIS 负载越高 |
| Cached Credential (Negative) | 2 小时 | 缓存认证失败的结果(避免重复查询) | 影响错误权限修正的生效时间 |
| Cached Credential (Positive) | 24 小时 | 缓存认证成功的凭据(含完整 GID 列表) | 影响新增群组权限的生效时间 |
性能权衡
缓存 TTL 过长的问题:
- 群组变更生效慢(用户体验差)
- 安全风险:移除的群组权限延迟失效
缓存 TTL 过短的问题:
- Name Service(LDAP/NIS)负载增加
- NFS 性能下降(频繁查询群组)
- 在高并发元数据操作(metadata-heavy workloads)时尤为明显
推荐配置:
- 开发/测试环境:5-15 分钟(快速响应变更)
- 生产环境:30-60 分钟(平衡性能与时效性)
- 高负载环境:保持默认或更长(减少 LDAP/NIS 压力)
与群组相关的三种缓存分别是:name-service cache、vserver cached-cred-negative-ttl、vserver cached-cred-positive-ttl。
查询命令:
1
2
3
vs1::*> vserver services name-service cache group-membership settings show -vserver <svm_name> #初始值为2小时。
vs1::*> vserver nfs show -vserver <svm_name> -fields cache-cred-negative-ttl #初始值为2小时。
vs1::*> vserver nfs show -vserver <svm_name> -fields cache-cred-positive-ttl #初始值为24小时。
修改命令
1
2
3
vs1::*> vserver services name-service cache group-membership settings modify -grplist-ttl 15m #修改为15min。
vs1::*> vserver nfs modify -vserver <svm_name> -cached-cred-negative-ttl 900000 #单位:毫秒,等于15min。
vs1::*> vserver nfs modify -vserver <svm_name> -cached-cred-positive-ttl 900000 #单位:毫秒,等于15min。
修改完再使用查询命令,查看是否已更改。
验证命令
1
2
3
4
vs1::*> vserver services name-service cache group-membership show -vserver <svm_name> -user <username>
vs1::*> vserver services name-service getxxbyy getgrlist -node <node_name> -vserver <svm_name> -use-cache true -username <username>
vs1::*> vserver services name-service getxxbyy getgrlist -node <node_name> -vserver <svm_name> -use-cache false -username <username>
vs1::*> vserver nfs credentials show -node <node_name> -vserver <svm_name> -unix-user-name <username>
总结
核心思想
不修改 NFS RPC 协议的数据结构,而是让服务端主动向 Name Service 查询用户的完整群组成员关系。
解决的问题
1. 突破 16 群组限制
- 客户端仍然只发送最多 16 个 GID(受协议限制)
- 服务端忽略这些 GID,改为查询 LDAP/NIS 获取完整列表
- 支持最高 1024 个群组(不同版本的 ONTAP 可能有所不同)
2. 修复 VNC Session 群组延迟问题
传统问题: 用户在已登录的 VNC session 中新加入群组后,执行 groups 命令仍看不到新群组(需重新登录)。
服务端查询方案:
- 即使客户端的 session 中
groups命令不显示新群组 - 用户仍能访问需要新群组权限的目录
- 原因:权限检查在服务端完成,服务端实时查询 Name Service
1
2
3
4
5
6
# 用户场景示例
[user@client ~]$ groups # 客户端 session 中看不到新群组 "newgroup"
user wheel oldgroup1 oldgroup2
[user@client ~]$ cd /nfs/project/restricted_by_newgroup
# 访问成功!因为服务端从 LDAP 查到了 "newgroup" 成员关系
实施要点
| 要素 | Linux NFS | NetApp ONTAP |
|---|---|---|
| 关键选项 | rpc.mountd -g |
auth-sys-extended-groups enabled |
| Name Service | LDAP/NIS/SSSD | LDAP/NIS(必须配置) |
| 内核要求 | ≥ 2.6.21 | ONTAP 9+ |
| 缓存调优 | 通过 sssd.conf | cached-cred-*-ttl 参数 |
| 性能影响 | 单位数百分比 | 单位数百分比 |
安全性提升
传统 AUTH_SYS 问题:
- 客户端声明 “我是 UID 1000,属于这 16 个群组”
- 服务端无条件信任,容易被伪造
服务端查询方案:
- 客户端声明 UID,服务端独立验证群组成员关系
- 降低客户端伪造群组的风险
- 但仍不如 AUTH_GSS(Kerberos) 安全
[!IMPORTANT] 对于高安全要求环境,建议迁移到 NFSv4 + RPCSEC_GSS (Kerberos),实现真正的加密认证和授权。
参考资料:
https://thinksystem.lenovofiles.com/storage/help/index.jsp?topic=%2Fnfs_file_access_reference_guide%2F1D3D018C-DF37-4C87-A789-58526A46B1A9_.html
https://www.netapp.com/pdf.html?item=/media/10720-tr-4067.pdf
https://kb.netapp.com/onprem/ontap/da/NAS/How_does_AUTH_SYS_Extended_Groups_change_NFS_authentication
https://datatracker.ietf.org/doc/html/rfc5531 P25 defines authsys_parms data structure, which limit the number of secondary groups up to 16.
https://access.redhat.com/articles/625273
https://docs.netapp.com/us-en/ontap/nfs-config/configure-name-service-switch-table-task.html
https://kb.netapp.com/onprem/ontap/da/NAS/NFS_access_is_getting_denied_after_enabling_auth-sys-extended-groups
致谢
感谢 EDACAD提效研究所 对该问题的激烈讨论与分享。