背景

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个群组。

image

源码分析

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)

image

rpc.mountd –manage-gids 工作原理

rpc.mountd daemon 是 NFS (v2, v3) MOUNT 协议的服务端实现。通过 -g--manage-gids 选项,可以实现服务端群组管理。

核心机制

  1. 忽略客户端提供的群组列表
    • 启用 --manage-gids 后,服务端会忽略客户端在 RPC 请求中发送的最多 16 个 GID
  2. 服务端主动查询
    • rpc.mountd 在服务端执行本地查询,从 Name Service 获取用户的完整群组成员关系
    • 支持的 Name Service:/etc/group、LDAP、NIS/NIS+、SSSD
  3. 内核交互
    • 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群组的支持。

image

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 cachevserver cached-cred-negative-ttlvserver 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提效研究所 对该问题的激烈讨论与分享。