1、简介
阿里云在3月份推出了NAS服务,可以让用户无需对现有应用做任何修改,就可以使用具备无限容量及性能扩展、单一命名空间、多共享、高可靠和高可用等特性的分布式文件系统。目前阿里云NAS服务只支持NFS,后续会支持更多的协议。
由于NFS协议经过了较长时间的发展,目前已经发展了多个版本,不同版本间可能会有不同的处理方式。另外,Linux kernel不同的版本下对于NFS协议的实现可能也会有稍微差别。为了帮助用户更好地使用阿里云NAS文件存储服务,我们推出系列文档来介绍阿里云NAS的使用。
首先介绍阿里云NAS服务文件权限校验的使用。阿里云NAS目前使用标准的NFS协议,支持标准的UNIX文件权限校验方法。由于NFS协议不同的版本实现方式不太相同,所以对于某些版本的NFS Client一些功能不能完全支持。
由于NFS V4版本的实现机制,在较早版本的NFS Client上,如果使用NFS V4挂载,会存在两个问题: ① client不能正确显示文件owner和group,会显示成匿名用户; ② 调用chown和chgrp时,会把文件的owner和group修改成匿名用户。所以建议用户使用阿里云NAS服务时,尽量选择高版本的Kernel。如果必须使用存在上述问题的Kernel时,可以使用NFS V3方式挂载来避免上述问题。
接下来首先分析上述问题的原因,然后通过选择阿里云两个版本(CentOS 5.10和CentOS 6.5)的ecs vm来验证上述问题。
2、NFS协议文件权限校验机制
NFS协议支持Linux文件系统本身的权限校验。在NFS3协议中,使用AUTH_SYS方式进行权限验证。NFS请求把nfs client本地的user ID(uid)和一组组ID(gids)发送给nfs server。在NFS Server上按UNIX权限校验方式进行权限检查,把结果返回给nfs client。Nfs client和nfs server之间传送文件owner和group信息时使用数字uid和gids。这样的缺点是要求不同的client必须有相同的user-uid映射关系,如果两个client上,不同的用户有相同的uid,它们在nfs server上的权限验证是相同的,对于所有的文件有相同的权限。NFS V3文件权限校验方式如下图所示。
Linux使用uid来表示进程,对于每一个NFS请求,NFS client都会把当前的euid和egids发送到nfs server。linux系统中每个进程都有2个ID,分别为用户ID(uid)和有效用户ID(euid),UID表示进程的创建者(创建简称的用户uid),而EUID表示进程对于文件和资源的访问权限(等同于哪个用户的权限)。
为了解决不同的client有不同的name-uid的映射关系,在nfs v4协议中,通过idmap服务,client和server传输文件的owner信息时,使用字符串,而不再使用数字uid和gids,比如user@nfs_domain,group@nfs_domain。NFS Server收到字符串的owner和group时,再把字符串信息转换成数字uid和gids。使用字符串代替数字uid和gids,增加了灵活性,通过idmap服务允许client和server接入NIS和LDAP服务。具体流程见下图。
对于公有云的NAS服务,是没有用户的name->uid的映射关系的,所以要求用户只能发送数字的uid和gids,如果用户发送过来的文件owner信息是string,在server端也只能把用户映射成nobody。但糟糕的是较早版本的nfs client中,nfs v4协议发送文件的owner信息时,必须使用idmap转换成string,如果用户不使用idmap服务,nfs client就会把数字uid映射成nobody发送过来。另外,对于server发送过来的数字uid和gid,也会映射成nobody。
这个是较早版本的NFS client实现方式:
if (iap->ia_valid & ATTR_UID) {
owner_namelen = nfs_map_uid_to_name(server->nfs_client, iap->ia_uid, owner_name);
if (owner_namelen < 0) {
dprintk("nfs: couldn't resolve uid %d to string\n",
iap->ia_uid);
strcpy(owner_name, "nobody");
owner_namelen = sizeof("nobody") - 1;
/* goto out; */
}
len += 4 + (XDR_QUADLEN(owner_namelen) << 2);
}
如果通过idmap查找name-uid映射关系失败时,会把username应射成nobody来处理。
这种强制使用idmap的行为对用户使用来说是很不友好的,而且也和以前版本的NFS协议处理方式不兼容。所以在后续的版本中,Linux kernel对这种方式进行了修改。如果用户选择关闭idmaper,则client把数字uid和gids按字符串的形式发送给Server。如果NFS server发送给client的是数字uid和gid的话,client也会接受,不会像以前强制转换成nobody处理。详情可以参考如下网址:
Trond Myklebust (5):
NFSv4: If the server sends us a numeric uid/gid then accept it
NFSv4: Send unmapped uid/gids to the server if the idmapper fails
NFSv4: cleanup idmapper functions to take an nfs_server argument
NFSv4: Propagate the error NFS4ERR_BADOWNER to nfs4_do_setattr
NFSv4: Send unmapped uid/gids to the server when using auth_sys
代码层面的修改,是在调用nfs_idmap_lookup_name时,添加了一个判断条件。
int nfs_map_uid_to_name(struct nfs_client *clp, __u32 uid, char *buf, size_t buflen)
{
- return nfs_idmap_lookup_name(uid, "user", buf, buflen);
+ int ret;
+ ret = nfs_idmap_lookup_name(uid, "user", buf, buflen);
+ if (ret < 0)
+ ret = nfs_map_numeric_to_string(uid, buf, buflen);
+ return ret;
}
3、测试验证
按照上述分析,由于早期的kernel版本,如果不使用idmap,文件的owner会转换成nobody发送给server。由于阿里云NAS现在没有用户name->uid的映射关系,现在只支持数字的uid和gids,所以在一些较早的kernel版本上使用阿里云NAS服务,会遇到用户和组信息无法正确识别和转换的问题。使用nfs v4挂载时,较早版本的kernel主要有两个问题: ① nfs client无法显示文件的uid和gid,会全部显示成匿名用户; ② nfs client做chown,chgrp操作时,会把文件的owner和group修改成匿名用户。
接下来,用阿里云提供的Centos镜像的两个发行版(CentOS 5.10和CentOS 6.5)来验证上述问题。这两个发行版对应的内核版本分别为2.6.18和2.6.32。对于nfs v4,CentOS 5.10强制使用idmap,CentOS 6.5允许使用数字uid和gids。
CentOS 5.10
CentOS 6.5
3.1文件owner和group显示问题
在CentOS 5.10上创建两个普通用户Tom和Alice,然后使用NFS V4挂载。
首先创建owner为Tom的文件,使用ll命令,可以看到Tom.txt的uid和gid都是4294967294,这个数字代表匿名用户。
用户Alice看到这个文件uid和gid也都是匿名用户。
按照上面的分析,这种情况下uid和gid只是没有正确显示,在server保存的uid和gid还是正确的,所以文件权限校验还是正确的。测试证明虽然显示的都是匿名用户,但用户Tom能够继续修改这个文件,而Alice是没有权限修改的。
然后,我们看一下使用NFS V3挂载时,显示的文件owner和group。从下面的截图可以看出,使用NFS V3方式进行挂载是没有问题的。用户Tom和用户Alice看到的都是这个文件的owner和group是Tom。
我们再在另外一台机器上(CentOS 6.5)使用NFS V4和NFS V3两种方式挂载,看一下结果。先使用NFS V4挂载,但在CentOS 6.5上看到文件Tom.txt属于用户Bill。
按照上面的分析,NAS Server返回文件的owner和group是数字的uid和gid,只是linux在显示时按照/etc/passwd里面的uid-name关系来现实,所以在CentOS 6.5和CentOS 5.10上,用户Bill和用户Tom的uid和gid应该是相同的。
如果CentOS 6.5机器上没有用户的uid和gid是502,这个时候执行ls命令的时候文件的owner和group直接显示数字uid和gid。
上面是用户在较早版本的内核上使用NFS V4新创建的一个文件,但糟糕的是对于已经存在的文件也有这样的问题。
在CentOS 5.10上使用NFS V4挂载,ls整个文件夹,所有的文件都显示匿名用户。
在CentOS 5.10上使用NFS V3挂载,没有问题。
Centos 6.5上NFS V3和NFS V4两种方式挂载,结果相同,都没有问题。
综上所述,较早版本的Kernel上,使用NFS V4方式挂载,所有文件的uid和gid都会显示为匿名用户,不过文件的权限校验是正确的。
3.2修改文件的owner和group
除了显示的问题外,较早版本的Kernel上,使用NFS V4方式挂载,chown和chgrp也会有问题。
继续使用上面的文件,在CentOS 5.10上,使用NFS V4方式挂载,把Tom.txt文件的owner和group改为Alice。
执行完之后,显示确实是Alice,看起来像是成功了,但其实是不对的。
使用NFSV3 方式挂载,看到Tom.txt文件的owner和group都变成了nobody(匿名用户)。
在CentOS 6.5上,看到同样的结果。
按照前面的分析,在较早版本的Kernel上,使用NFS V4挂载,调用chown会把用户的uid和gid转换成匿名用户发送给NFS Server。但为什么又显示成功了呢。这里怀疑是nfs client的cache的问题,把nfs client的inode的cache清空,确实显示成匿名用户,不再显示成Alice了。
清空inode
Alice和Tom看到的都是匿名用户。
综上所述,在较早版本的kernel上,使用NFS V4方式挂载时,修改文件的owner和group会把文件的owner和group都变成匿名用户。如果确实需要修改文件的owner和group呢,可以使用NFS V3方式挂载
使用NFS V3挂载,可以修改成功,文件权限校验也是正确的。
在Centos 6.5上查看该文件的owner和group,显示为503,503即为Centos 5.10 vm上用户Alice的uid和gid。
使用NFS V3挂载修改owner和group后,再使用NFS V4方式挂载,依然显示成匿名用户,但权限是正确的,用户Alice可以修改这个文件。
上面的问题是低版本的内核问题导致的,接下来验证一下在CentOS 6.5上,使用NFS V4方式挂载,修改文件的owner的行为。
从下面的截图可以看出用户Andy创建的文件,把owner和group修改为用户Mike后,文件的owner和group显示和文件权限校验都是没有问题的。
在CentOS 5.10上使用NFS V3进行挂载看到文件的uid和gid是数字501,这个是CentOS 6.5 vm上用户Mike的uid和gid。
最后在CentOS 5.10上使用NFS V4挂载,显示的依然是匿名用户。
4、结论
1、在CentOS 5.10上,使用NFS V4进行挂载,所有文件的owner和group都会显示为匿名用户,但权限校验是正确的。
2、在CentOS 5.10上,使用NFS V4进行挂载,调用chown和chgrp操作,会把文件的uid和gid改成匿名用户。
3、用户使用阿里云NAS服务时,尽量选择高版本的Kernel。如果必须使用存在上述问题的Kernel时,可以使用NFS V3方式挂载来避免上述问题。