hdfs 多租户_HDFS权限管理实践_weixin_39548972的博客-程序员宅基地

技术标签: hdfs 多租户  

作为一个分布式文件系统,HDFS也集成了一套兼容POSIX的权限管理系统。客户端在进行每次文件操时,系统会从用户身份认证和数据访问授权两个环节(数据加密这里不做介绍)进行验证: 客户端的操作请求会首先通过本地的用户身份验证机制来获得“凭证”(类似于身份证书),然后系统根据此“凭证”分辨出合法的用户名,再据此查看该用户所访问的数据是否已经授权。一旦这个流程中的某个环节出现异常,客户端的操作请求便会失败。本文以社区Hadoop 2.5.x 版本为例,介绍 HDFS 的权限管理中的相关内容,以及实际应用中的权限分配策略和实践。

用户身份认证

用户身份认证独立于HDFS之外,也就说HDFS并不负责用户身份合法性检查,但HDFS会通过相关接口来获取相关的用户身份,然后用于后续的权限管理。用户是否合法,完全取决于集群使用认证体系。目前社区支持两种身份认证,即简单认证(Simple)和 Kerberos 。

简单认证 基于客户端所在的Linux/Unix系统的登录用户名来进行认证。只要用户能正常登录就认证成功。这样客户端与NameNode交互时,会将用户的登录账号(通过类似whoami的命令来获取)作为合法用户名传递至Namenode。 这意味着使用不同的账号登录到同一个客户端,会产生不同的用户名,故在多租户条件这种认证会导致权限混淆;同时恶意用户也可以伪造其他人的用户名非法获得相应的权限,对数据安全造成极大的隐患。线上生产环境一般不会使用。

Kerberos 是一个网络认证协议,其使用密钥加密技术为客户端和服务端应用提供强认证功能。它有一个管理端(AdminServer)用于管理所有需要认证的账号信息,另外还有若干的密钥分发服务器(KDC)用于提供认证和分发密钥服务。 用户从 Kerberos 管理员处获取对应的 Kerberos 账号名或者密钥文件,然后通过 kinit 等方式认证Kerberos,拿到TGT(ticket-granting-ticket)票据。客户端会将这些信息传输到NameNode端,NameNode在获取到Kerberos认证信息后,将principle首部截取出来作为用户对应的用户名。譬如使用 da/[email protected] 认证成功后, da作为principle的首部会作为该客户端的用户名使用。 服务端进程在启动时通过 JAVA GSSAPI 认证 Kerberos ,同时定期轮询 TGT 的有效期,并再次认证以保证服务持续可用。进程间的 RPC 通信也通过 Kerberos 进行认证,这里不做赘述。 使用Kerberos可以极大增强HDFS的安全性,特别是在多租户的生产环境下。

以下为开启Kerberos认证的配置参数:

hadoop.security.authentication

kerberos

Set the authentication for the cluster. Valid values are: simple or

kerberos.

hadoop.security.authorization

true

Enable authorization for different protocols.

用户组映射

在用户身份验证成功之后,接下来会检查该用户所拥有的权限。HDFS 的文件权限与 Linux/Unix 系统类似,也是采用UGO模型,分成用户、组和其他权限。但与 Linux/Unix 系统不同,HDFS的用户和组都是使用字符串存储的,在 Linux/Unix 上通用的UID和GID是无法在HDFS使用的。此外,HDFS 的组需要通过外部的用户组关联(Group Mapping)服务来获取。用户到组的映射可以使用系统自带的方案(使用NameNode服务器上的用户组系统),也可以通过其他实现类似功能的插件(LDAP、Ranger等)方式来代替。在拿到用户名后,NN会通过用户组关联服务获取该用户所对应的用户组列表,并用于后期的用户组权限校验。下面是两种主要的实现方式 。

基于Linux/Unix系统的用户和用户组

Linux/Unix 系统上的用户和用户组信息存储在/etc/passwd 和 /etc/group 文件中。默认情况下,HDFS 会使用 ShellBasedUnixGroupsMappings 服务,即通过调用外部的 Shell 命令(id -gn xxx && id -Gn xxx)来获取用户的所有用户组列表。 此方案的优点在于组映射服务十分稳定,不易受外部服务的影响。但是用户和用户组管理涉及到root权限等,同时会在服务器上生成大量的用户组,后续管理,特别是自动化运维方面会有较大影响。

基于使用LDAP协议的数据库

OpenLDAP是一个开源LDAP的数据库,通过phpLDAPadmin等管理工具或相关接口可以方便地添加用户和修改用户组。HDFS 可以使用 LdapGroupsMappings 来使用 LDAP 服务。通过配置LDAP的相关属性,可以通过接口来直接获取到某个用户所有的用户组列表(memberOf)。 使用LDAP的不足在于需要保障LDAP服务的可用性和性能,关于LDAP的管理和使用将会后续再作介绍。 不同的LDAP有不同的实现,需要使用不同类型的LDAP Schema来构建,譬如示例中使用的是Person和GroupOfNames类型而不是PosixAccount和PosixGroup类型 以下是开启LDAP关联的配置文件:

hadoop.security.group.mapping

org.apache.hadoop.security.LdapGroupsMapping

hadoop.security.group.mapping.ldap.bind.user

cn=Manager,dc=hadoop,dc=apache,dc=org

hadoop.security.group.mapping.ldap.bind.password.file

/etc/hadoop/conf/ldap-conn-pass.txt

–>

hadoop.security.group.mapping.ldap.bind.password

hadoop

hadoop.security.group.mapping.ldap.url

ldap://localhost:389/dc=hadoop,dc=apache,dc=org

hadoop.security.group.mapping.ldap.url

ldap://localhost:389/dc=hadoop,dc=apache,dc=org

hadoop.security.group.mapping.ldap.base

hadoop.security.group.mapping.ldap.search.filter.user

(&(|(objectclass=person)(objectclass=applicationProcess))(cn={0}))

hadoop.security.group.mapping.ldap.search.filter.group

(objectclass=groupOfNames)

hadoop.security.group.mapping.ldap.search.attr.member

member

hadoop.security.group.mapping.ldap.search.attr.group.name

cn

UGO 权限管理

HDFS的文件权限与Linux/Unix系统的UGO模型类型类似,我们使用FS Shell查看目录,可以看到如下内容:

Found 8 items

drwxr-x--- - portal portal_1_2 0 2016-08-15 20:16 /user/portal/ODM/ZY/ODM_ZY_ALL_LOG/month=

drwxr-x--- - portal portal_1_2 0 2016-07-12 15:59 /user/portal/ODM/ZY/ODM_ZY_ALL_LOG/month=201604

drwxr-x--- - portal portal_1_2 0 2016-07-12 17:27 /user/portal/ODM/ZY/ODM_ZY_ALL_LOG/month=201605

drwxr-x--- - portal portal_1_2 0 2016-07-12 19:13 /user/portal/ODM/ZY/ODM_ZY_ALL_LOG/month=201606

drwxr-x--- - portal portal_1_2 0 2016-08-12 20:09 /user/portal/ODM/ZY/ODM_ZY_ALL_LOG/month=201607

drwxr-x--- - portal portal_1_2 0 2016-08-31 01:15 /user/portal/ODM/ZY/ODM_ZY_ALL_LOG/month=201608

但是与传统的POSIX模式相比,HDFS没有setuid和setgid实现。但是在目录中可以设置粘连位(Sticky bit)。 通过设置粘连位简化了目录权限管理,可以让不同的用户共享特定目录的读写权限。但只有子目录的属主才有删除权限。如/tmp目录:

drwxrwxrwt - hdfs hdfs 0 2016-10-11 05:14 /tmp

/tmp下面的一些子目录的权限如下:

-rw-r--r-- 3 censor hdfs 3 2016-08-08 11:04 /tmp/1.txt

-rw-r----- 3 mammut hdfs 10240 2016-09-20 17:18 /tmp/20160920171832.tar

drwxr-x--- - recsys hdfs 0 2015-09-10 13:47 /tmp/data1

与Linux/Unix系统类似,HDFS也提供了umask掩码,用于设置在HDFS中默认新建的文件和目录权限位。为了配合用户组的权限限制,建议将其设置成027,即默认的的新确保新目录或文件生成时权限位750或640。配置如下:

dfs.umask

027

dfs.umask is deprecated,use fs.permissions.umask-mode instead.

默认来说,只有启动Namenode进程的用户才有超级用户权限,也就是hdfs用户。但很多操作实际上都需要超级用户的权限(如fsck等),故HDFS也可以配置超级用户组,所有在该用户组里面的用户都可以以超级用户权限来操作HDFS(操作时要慎重)。 除了部分操作对用户名有限制之外 开启超级用户组

dfs.permissions.superusergroup

hdfs

UGO 权限相关操作

变更目录或文件的权限位hadoop fs -chmod 750 /user/portal/foo

变更目录或文件的属主或用户组hadoop fs -chown :portal /user/portal/foo

变更用户组hadoop fs -chgrp portal_group1 /user/portal/foo

需要注意的是,使用这个命令的用户必须是超级用户,或者是该文件的属主,同时也是该用户组的成员。另外目录的权限组变更后,需要手动刷新用户组才能让变更生效。

ACL权限管理

HDFS使用用户组来控制权限可以满足大部分场景下的数据安全性要求,但是对于一些复杂的权限需求则无能为力。实际应用中有这么两种问题:

对于一个目录,可能会有两种权限需求,一种是只读,一种是读写,但用户组权限只能设定为其中之一;

为了开通某个目录的组只读权限,必须开通父级级目录的其他权限组的只读权限,但这样会导致父级新增的子目录额外带上了其他权限组的只读权限,从而带来非法读的隐患。

为了解决HDFS的细粒度权限控制需求,HDFS提供了类似的POSIX ACL特性。一条ACL规则由若干ACL条目组成,每个条目指定一个用户或用户组的权限位。ACL条目由类型名,可选名称和权限字符串组成,以:为分隔符。

user::rw-

user:bruce:rwx #effective:r--

group::r-x #effective:r--

group:sales:rwx #effective:r--

mask::r--

other::r--

第一部分由固定的类型名构成,有user,group,other,mask,default等选项。mask条目会过滤掉所有命名的用户和用户组,以及未命名的用户组权限。第二部分可以指定类型名称,如用户名,用户组名等(other类型不需要名称),这部分是可选项,若不指定特定的用户名或用户组,则表示只对该文件属主或目录的用户组生效。第三部分就是权限位。 若该条规则应用到foo文件,foo文件的属主有读写权限,foo文件的用户组有只读和执行权限(对于目录),其他用户也是只读权限;但bruce用户的权限经过mask过滤后只有只读权限,sales组也是只读权限。

default类型是一个特殊的类型,且只应用在目录上,用于在创建子目录和文件时为其应用该默认的ACL规则。权限复制发生在文件产生之时,在这之后对父级目录的ACL操作,不会影响子目录已存在的ACL规则。 另外每个ACL规则都有mask条目,如果用户在设置ACL时没有显式声明,那么系统会自动地添加一条mask规则。在含有ACL规则的文件上通过chmod变更权限会改变mask值。因为mask要作为一个过滤器来更有效地限制所有的扩展ACL条目,如果仅仅改变组条目,这会导致Other部分的ACL规则出现缺漏。

当设置了ACL规则之后,目录或文件的权限位后面会出现一个“+”号,如下:

drwxr-xr-x+ - da hdfs 0 2016-10-02 12:00 /user/da/da_hivesrc

开启ACL的配置如下:

dfs.namenode.acls.enabled

true

ACL相关操作

为目录添加访问权限hadoop fs -setfacl -m user:abc:r-x

为目录添加可继承的权限hadoop fs -setfacl -m default:user:abc:r-x,default:group:xxx:r-x,default:other::r-x /user/hadoop

删除目录权限hadoop fs -setfacl -b /user/hadoop

删除特定权限,保留其他全下hadoop fs -setfacl -x user:abc:rwx /user/hadoop注意:配置ACL权限后即可生效,不需要刷新用户组

权限优先级

权限检查会在每次操作时进行,客户端会隐式地传送用户身份到Namenode。当客户端开始读取某一文件时,它会首先向Namenode发送请求来查找该文件的第一个block,查找该文件额外blocks的请求可能会失败。因为权限的缘故,所以客户端对文件的访问权限可能会在请求之间被收回。更改权限并不会撤销已知文件块的客户端访问权限。

权限判断的前后顺序通过以下代码实现

private void check(INodeAttributes inode, String path, FsAction access

) throws AccessControlException{

if (inode == null) {

return;

}

final FsPermission mode = inode.getFsPermission();

final AclFeature aclFeature = inode.getAclFeature();

if (aclFeature != null) {

// It's possible that the inode has a default ACL but no access ACL.

int firstEntry = aclFeature.getEntryAt(0);

if (AclEntryStatusFormat.getScope(firstEntry) == AclEntryScope.ACCESS) {

checkAccessAcl(inode, path, access, mode, aclFeature);

return;

}

}

if (getUser().equals(inode.getUserName())) { //user class

if (mode.getUserAction().implies(access)) { return; }

}

else if (getGroups().contains(inode.getGroupName())){ //group class

if (mode.getGroupAction().implies(access)) { return; }

}

else { //other class

if (mode.getOtherAction().implies(access)) { return; }

}

throw new AccessControlException(

toAccessControlString(inode, path, access, mode));

}

从代码即可看出,权限首先会判断ACL规则,然后再判断权限位,根据先用户,再组,再其他的顺序进行。

首先检查是否为超级用户(在之前的步骤)

再次检查用户是否一致,然后验证用户权限位

再次检查文件组名在用户所在的用户组列表中,然后验证用户组权限位

最后检查其他组权限位

否则抛出权限异常,访问失败

当开启了ACL后,检查用户权限的流程变更为如下:

当用户名和文件属主完全匹配时,则检验用户权限

当用户名匹配了文件ACL规则中的某个User条目中的用户名时,检查该条目下的用户权限与mask掩码计算后的权限是否合法

当文件的组名匹配了该用户的用户组列表中的某个成员,检查该条目下的Group权限与mask掩码计算计算后的权限是否合法

如果ACL规则中的命名用户组存在于该用户组列表中,并且该条目下的Group权限与mask掩码计算计算后的权限验证成功,则会使用该ACL条目中的Group权限

如果文件组名或命名的组ACL规则匹配了用户的用户组,但是并未通过权限检查,那么访问被禁止

最后检查其他权限位

详细的代码实现可以查看 FSPermissionChecker#checkAccessAcl 方法

总结

HDFS权限管理策略总结成以下几点:

为不同的文件目录设置属主和权限位,将数据通过不同的用户权限隔离开来。

对于用户间共享的数据,优先使用用户组权限实现。一般来说,不同的目录对应到不同的用户组。在设置了用户组权限的目录下,新建文件和子目录会继承当前目录的用户组和权限位。

由于只设置需要共享目录的权限,该共享目录的上级或父目录需要通过递归方式添加只读ACL。这样可以避免开通不必要的其他组权限,导致数据权限出现安全隐患。

对于特定的共享目录,用户组中的用户可能有些有只读权限,有些是读写权限。这种情况下,用户的写权限通过ACL额外指定。所有用户的读权限通过用户组来指定接口

如果上述权限还需要在子目录中继承下去,则需要设定用户写权限的default规则(尽量少用,做到一个账号写,多个账号读即可)。

用户组名与目录名绑定,这样可以方便在有其他人需要访问该目录时,可以通过变更用户组成员解决。

使用ACL的最佳实践: 使用传统的权限位来实现最大的权限管理需求,对一些特殊的权限规则定义少量的ACLs来加强权限控制。因为相比于使用权限位,使用ACL会在NameNode端占用额外的内存。故总体的原则是,在能使用组解决问题时,尽量使用组,特别是只读场合和需要权限继承的场景。

参考文档

本文来自网易实践者社区,经作者金川授权发布。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_39548972/article/details/111494030

智能推荐

如何自动安装linux系统,Linux全自动安装操作实例_weixin_39887183的博客-程序员宅基地

手动安装Linux系统费时费力,需要操作的步骤非常多,使用kickstart等工具就能实现Linux系统的全自动安装,下面小编就给大家介绍下Linux全自动安装操作实例,一起来学习下吧。原理:使用光盘安装linux系统过程:第一步,POST自检第二步,MBR引导,这里使用的GRUB是CDROM中isolinux/文件夹中的grub.conf。第三步,启动带有安装、升级、修复等选项的选择菜单,这是由...

centos7搭建confluence_www120113的博客-程序员宅基地

https://www.cnblogs.com/heaven-xi/p/11147073.html备份路径: /var/atlassian/application-data/confluence/backups安装java环境tar -zxvf jdk-8u211-linux-x64.tar.gz -C /usr/local/ln -s /usr/local/jdk1.8.0_211/ /usr/local/jdkvim /etc/profileJAVA_HOME=/usr/local/jdk

开课吧:学习C语言应该从哪些方面入手?_kaikeba的博客-程序员宅基地_c语言要从什么开始学

C语言属于高级程序语言的一种,它的前身是“ALGOL”。其创始人是布朗·W·卡尼汉和丹尼斯·M·利奇。C语言问世时是带有很大的局限性,因为它只能用于UNIX系统上。然而随着科学技术的进步,计算机工业的发展,C语言逐渐脱离UNIX。1987年美国标准化协会制定了C语言的国际标准,简称“ANSI C”,从此以后它便成为一种广泛使用的程序语言。学习C语言必须从以下几方面入手:1、多看代码在有一定基础以后一定要多看别人的代码。注意代码中的算法和数据结构。毕竟学C之后的关口就是算法和数据结构。提到数据结构,指针

ES脑裂问题_weixin_34167819的博客-程序员宅基地

脑裂:一个集群中的不同节点对于集群的状态有了不一样的理解ES集群的总体状态是red,本来9个节点的集群在结果中只显示4个节点在线;正常情况下,集群中的所有节点应该对集群中的master的选择是一致的,这样获得的状态信息也应该是一致的,不一样的状态信息,说明不同的节点对master的选择出现了异常-----也就是所谓的脑裂问题,这样的脑裂状态直接让节点失去了集群的正确状态,导致集群不能...

IDEA中Git的常用场景使用_左落的博客-程序员宅基地

IDEA中Git的常用场景使用 工作中多人使用版本控制软件协作开发,常见的应用场景归纳如下:假设小组中有两个人,组长小张,组员小袁场景一:小张创建项目并提交到远程Git仓库场景二:小袁从远程Git仓库上获取项目源码场景三:小袁修改了部分源码,提交到远程仓库场景四:小张从远程仓库获取小袁的提交场景五:小袁接受了一个新功能的任务,创建了一个分支并在分支上开发场景六:小袁把分支提交到远程Git仓库场景七:小张获取小袁提交的分支场景八:小张把分支合并到主干 下面来看以...

golang zip 解压、压缩文件_狮子QH的博客-程序员宅基地_golang 解压

package im_saas_copy_appimport ("archive/zip""io""os""strings")//压缩文件//files 文件数组,可以是不同dir下的文件或者文件夹//dest 压缩文件存放地址func Compress(files []*os.File, dest string) error { d, _ := os.Create(dest) defer d.Close() w := zip.NewWriter(d) defer w.Clo

随便推点

COMP SCI 2ME3, SFWR ENG_weixin_30920513的博客-程序员宅基地

Assignment 4COMP SCI 2ME3, SFWR ENG 2AA4March 29, 2019Assigned: March 22, 2019Spec and Code: April 9, 2019Last Revised: March 29, 2019All submissions are made through git, using your own repo located ...

centos7.2部署docker-17.06.0-ce的bug:Error response from daemon: oci runtime error: container_linux.go:2..._weixin_30501857的博客-程序员宅基地

现象:操作系统:centos 7.2 kernel3.10.0-327.el7.x86_64mesos:1.3.0docker:docker-17.06.0-ce在做mesos验证时,通过marathon下发容器,发现在多个mesos-slave节点上下发容器均以失败告终。marathon:mesos:分析:#在任意1个mesos节点上查看docker...

JAVA中一些术语的中英文对照_数据结构一些常见术语的中英文对照_叶翼的博客-程序员宅基地

数据 Data数据元素 Data element数据项 Data item数据结构 Data structure逻辑结构 Logical structure数据类型 Data type指针 Pointer顺序存储结构 Sequential storage structure链状存储结构 Linked storage struc...

使用 maven 报错 ArtifactTransferException Failure to transfer_JDWL20090304的博客-程序员宅基地

转载链接:ArtifactTransferException: Failure to transfer xml-apis:xml-apis:jar:1.0.b2 from http://192.168.137.217/nexus/content/groups/public/ was cached in the local repository, resolution will

redis做方法缓存_一个小白QAQ的博客-程序员宅基地_redis做缓存

redis做方法缓存为什么要拿redis做缓存?​ redis是一个完全基于内存、数据结构简单、采用单线程的工作方式(避免了不必要的上下文切换)、使用IO多路复用的一个key-value类型的数据库。查询速度要远比mysql这种关系型数据库要快得多。​ 系统绝大多数场景下都是读多写少,而mysql能够承受的并发量在每秒两三千(百度得到的数据)的时候就会面临宕机的风险了,并且查询速度极慢。1、查询流程​ 在请求达到后端之后,对需要进行缓存的接口,会先去redis中找有无数据,没有的话会继续走正常

【C语言篇】学习计算机之路——第一个程序_MAX在码字的博客-程序员宅基地

序我这一生所追求的,只不过是在一个有你的时间,一个有你在的地方。嗨,这里是狐狸~~今天是2021年12月28日,距离2022年只剩3天啦,大家都准备怎么跨年呢,我估计要在公司跨年了,唉,生活不易啊,好了,废话不多说,2022年快到了,同学们也快放寒假了,今天开始我会一步一步的告诉大家怎么去学习编程,让大家可以充实的过一个寒假。编程语言概述编程语言说到语言我都会想到在生活中用到的自然语言,如中文,英语等自然语言自然语言它是人和人交流不可缺少的工具而编程语言是和计算机交流

推荐文章

热门文章

相关标签