概述
作为分布式文件系统,HDFS实现了一套兼容POSIX的文件权限模型,包括粗粒度的POSIX UGO模型和细粒度的POSIX ACLs协议。
客户端在每次进行文件操作时,HDFS会从用户身份认证、用户组映射和数据访问鉴权三个环节进行验证: 客户端的操作请求会首先从本地系统获取用户名,然后服务端将用户名匹配上组信息,最后查看所访问的数据是否已经授权给该用户。一旦这个流程中的某个环节出现异常,客户端的操作请求便会失败。
本文以Hadoop 3.1.1版本为例,介绍 HDFS 权限管理的相关内容以及权限分配的应用实践。
用户身份认证
用户身份认证并不属于HDFS的范畴,也就是说HDFS并不负责用户身份的合法性检查,它只是会依赖相关系统来获取用户身份,从而用于后续的鉴权。而对于身份认证,完全取决于其采用的认证系统。目前HDFS有支持两种用户身份认证:简单认证和kerberos认证。
简单认证基于客户端进程所在的Linux/Unix系统的当前用户名来进行认证。只要用户能正常登录操作系统就认证成功。这样客户端与NameNode交互时,会将用户的登录账号(与whoami命令输出一致)作为合法用户名传给Namenode。 这样的认证机制存在恶意用户可以伪造其他人的用户名的风险,对数据安全造成极大的隐患,线上生产环境一般不会使用。
kerberos认证kerberos是一个网络认证协议,其使用密钥加密技术为客户端和服务端应用提供强认证功能。它有一个管理端(AdminServer)用于管理所有需要认证的账号信息,另外还有若干的密钥分发服务器(KDC)用于提供认证和分发密钥服务。 用户从 Kerberos 管理员处获取对应的 Kerberos 账号名或者密钥文件,然后通过 kinit 等方式认证Kerberos,拿到TGT(ticket-granting-ticket)票据。客户端会将TGT信息传输到NN端,NN在获取到认证信息后,将principle首部截取出来作为客户端的用户名。例如使用 todd/[email protected]认证成功后, da作为principle的首部会作为该客户端的用户名使用。 使用Kerberos可以极大增强HDFS的安全性,特别是在多租户的生产环境下。
用户组映射
因为HDFS采用与Linux/Unix系统类似的文件权限模型,也就是UGO模型,分成用户、组和其他,所以在拿到用户名后,NN会通过获取该用户所对应的组列表。HDFS中组的获取是通过外部Group Mapping服务来获取,目前社区对用户到组的映射有主要有两种实现方式:1)使用系统自带的方案(即NameNode服务器上的用户组系统),2)使用三方服务如LDAP,通过参数hadoop.security.group.mapping来进行设置。下面重点讲解下这两种实现方式。
基于Linux/Unix系统的用户和组实现Linux/Unix 系统上的用户和用户组信息存储在/etc/passwd 和 /etc/group 文件中。默认情况下,HDFS 会使用org.apache.hadoop.security.ShellBasedUnixGroupsMapping服务,其原理是在NN上调用Shell 命令groups来获取用户的组列表。 此方案的优点在于组映射服务十分稳定,不易受外部服务的影响。但是用户和用户组管理需要root权限,同时会在服务器上生成大量的用户组,后续管理,特别是自动化运维方面会有较大影响。
基于LDAP数据库的用户和组实现OpenLDAP是一个开源LDAP的数据库,可以通过phpLDAPadmin等管理工具或相关接口方便地添加用户和修改用户组。HDFS通过配置org.apache.hadoop.security.LdapGroupsMapping来使用 LDAP 服务,可以通过接口来直接获取到某个用户的组列表。使用LDAP的不足在于需要保障LDAP服务的可用性和性能。
数据授权(数据权限管理)
UGO权限管理- HDFS的文件权限与Linux/Unix系统的UGO模型类似,我们使用FS Shell查看目录,可以看到如下内容:
drwxrwxrwt - yarn hadoop 0 2020-01-20 15:42 /app-logs
drwxr-xr-x - yarn hadoop 0 2020-01-20 15:40 /ats
drwxr-xr-x - hdfs hdfs 0 2020-01-20 15:40 /hdp
drwxr-xr-x - mapred hdfs 0 2020-01-20 15:40 /mapred
drwxrwxrwx - mapred hadoop 0 2020-01-20 15:40 /mr-history
drwxrwxrwx - hdfs hdfs 0 2020-01-20 15:41 /tmp
drwxr-xr-x - hdfs hdfs 0 2020-01-20 15:40 /user
drwxr-xr-x - hdfs hdfs 0 2020-01-20 15:40 /warehouse
- 但是与传统的POSIX模式相比,HDFS没有setuid和setgid实现
- 与Linux/Uninx类似,HDFS在目录中也可以设置粘连位(Sticky bit)。 通过设置粘连位可以让不同的用户共享特定目录的读写权限,而只有子目录的属主才有删除权限。类似linux下/tmp目录一般设置粘连位,hdfs也应该将/tmp目录设置粘连位来共享读写而限制随便删除,通过hdfs dfs -chmod o+t /tmp设置后如下:
drwxrwxrwt - hdfs hdfs 0 2016-10-11 05:14 /tmp
/tmp下面的一些子目录的权限如下:
drwxr-xr-x - hdfs hdfs 0 2020-02-12 15:47 /tmp/entity-file-history
drwxr-x--- - hive hdfs 0 2020-02-14 22:30 /tmp/hive
drwxr-x--- - spark hdfs 0 2020-02-14 22:28 /tmp/spark
- 与Linux/Unix类似,HDFS也提供了umask掩码,用于设置在HDFS中默认新建的文件和目录权限位。为了配合用户组的权限限制,建议将其设置成027。配置如下:
<property>
注意:这个umask配置是客户端可以配置的,即客户端自己主宰创建文件或目录的权限。
关于022和027的解释:如果umask是022(默认值),那么新文件的模式就是644,新目录的模式就是755,即umask擦除掉了group和other的写权限。如果umask是027,那么新文件的模式就是650,新目录的模式就是750,即umask擦除掉了group的写权限,以及other的读写执行权限。
- HDFS也有与linux/uinx系统root账号类似的超级用户。默认来说,只有启动Namenode进程的用户才有超级用户权限,也就是hdfs用户。但很多操作实际上都需要超级用户的权限(如fsck等),故HDFS也可以配置超级用户组,除了部分操作(如hdfs dfsadmin -report命令)对用户名有限制之外,所有在该用户组里面的用户都可以以超级用户权限来操作HDFS。开启超级用户组的参数如下:
<property>
注意:必须在NN节点上将用户添加到superusergroup。
UGO 权限相关操作- hadoop fs -chmod 750 /user/dw_dev/foo
- hadoop fs -chown dw_dev:hdfs /user/dw_dev/foo
- hadoop fs -chgrp hdfs /user/dw_dev/foo
除了支持传统的POSIX权限模型之外,HDFS还支持POSIX ACLs (Access Control Lists)。ACLs增强了传统的权限模型,通过为特定的用户或组设置不同的权限来控制对HDFS文件的访问,即可以做到更加灵活和细粒度的权限控制:允许用户为用户和组的任意组合定义访问控制,而不是单个用户(所有者)或单个组。
默认情况下对ACLs的支持是关闭的,可以通过设置dfs.namenode.acls.enabled为true来打开。
ACLs应用场景HDFS使用UGO这种用户组的权限管理模型可以满足大多数场景的安全性要求,但对于一些复杂场景无法胜任,实际企业应用中存在如下问题:
对于一个目录,可能会有两种权限需求,一种是只读,一种是读写,但用户组权限只能设定为其中之一;
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组也是只读权限。
user::rwx
group::r-x
other::r-x
default:user::rwx
default:user:bruce:rwx #effective:r-x
default:group::r-x
default:group:sales:rwx #effective:r-x
default:mask::r-x
default:other::r-x
default类型是一个特殊的类型,且只应用在目录上,用于在创建子目录和文件时为其应用该默认的ACL规则。权限复制发生在文件产生之时,在这之后对父级目录的ACL操作,不会影响子目录已存在的ACL规则。 另外每个ACL规则都有mask条目,如果用户在设置ACL时没有显式声明,那么系统会自动地添加一条mask规则。在含有ACL规则的文件上通过chmod变更权限会改变mask值。因为mask要作为一个过滤器来更有效地限制所有的扩展ACL条目,如果仅仅改变组条目,这会导致Other部分的ACL规则出现缺漏。
当设置了ACL规则之后,目录或文件的权限位后面会出现一个“+”号,如下:
drwxrwx---+ - hive hadoop 0 2020-02-13 03:12 /warehouse/tablespace/managed/hive
ACL相关操作
1.查看目录权限
hadoop fs -setfacl /user/dw_dev
2.为目录添加访问权限
hadoop fs -setfacl -m user:public:r-x /user/dw_dev
3.为目录添加可继承的权限
hadoop fs -setfacl -m default:user:public:r-x,default:group:public:r-x,default:other::r-x /user/dw_dev
4.删除目录权限
hdfs dfs -setfacl -b /user/dw_dev
5.删除特定权限,保留其他权限
hdfs dfs -setfacl -x user:public:r-x /user/dw_dev
数据鉴权(数据访问权限检查)
以HDFS Client为例,来分析下HDFS鉴权的过程
在hdfs client分析:hdfs dfs -ls一文中,我们已经知道client在创建出FileSystem对象后,就会去调用fs.listStatus方法去列取目录信息。listStatus底层是通过RPC调用到NameNode的listStatus方法,那么ls的鉴权肯定就是在NameNode的listStatus方法中进行的了。
进入DistributedFileSystem.listStatus方法
//DistributedFileSystem.java
再进入listStatusInternal(p)
//DistributedFileSystem.java
再进入dfs.listPaths(src, HdfsFileStatus.EMPTY_NAME)
//DFSClient.java
再进入listPaths(src, startAfter, false)
//DFSClient.java
namenode.getListing最终是调用到了NameNodeRPCServer端了
//NameNodeRpcServer.java
进入namesystem.getListing
DirectoryListing
终于看到AccessControlException出现了,看来getListingInt
static
先来看下fsd.getPermissionChecker()
FSPermissionChecker
看到remoteUser信息是从RPC连接中获取到的。
接下来看鉴权的过程fsd.isPermissionEnabled()
在NameNodeServer端获取到了remoteUGI后,就是和path的ugi信息做匹配了,很简单,就不一步步的分析了。
参考文档
HDFS Permissions Guide
Hadoop Groups Mapping
【Linux】理解setuid()、setgid()和sticky位 - puyangsky - 博客园
Linux SetUID(SUID)文件特殊权限用法详解
Linux SetGID(SGID)文件特殊权限用法详解
Linux Stick BIT(SBIT)文件特殊权限用法详解
HDFS Extended ACLs