当前Apache Hadoop认证(authentication)支持simple和kerberos,simple是默认的,其实是信任操作系统的认证结果(也就是直接使用操作系统的用户)。kerberos是一套第三方的认证系统,我们没有使用。
以下基于hadoop 2.6.0版本。
hadoop权限相关的问题,涉及四个方面:HDFS权限、YARN资源使用权限、Container使用主机资源权限、主机(hadoop节点)之间的权限;
0. hadoop获取user/group方式:(hadoop-common组件的,公用,参见UserGroupInformation类)
user获取:优先从kerberos获取(kerberos模式);从系统HADOOP_USER_NAME变量获取;从java属性HADOOP_USER_NAME获取;获取操作系统当前用户
group获取:从定义的group映射关系获取hadoop.user.group.static.mapping.overrides;从配置的group映射 类获取(hadoop.security.group.mapping);从系统groups user获取
(注意:user的获取是在client上进行的,但是yarn执行task时,需要根据user获取group,这个操作是在NodeManager的节点上进行的)
这是hadoop-common里面的代码,所以hdfs、yarn的用户名相关都使用了这套代码。(参见代码UserGroupInformation$HadoopConfiguration类)
HADOOP_USER_NAME属性是一个很重要的属性。
static final String HADOOP_USER_NAME = "HADOOP_USER_NAME";
static final String HADOOP_PROXY_USER = "HADOOP_PROXY_USER";
1. hdfs文件系统的权限
HDFS Permissions Guide
默认
POSIX模式:
文件: r->读;w->写;x->执行;
目录: r->list; w->创建或删除;x->查看子目录; T/t->不能删除别人的文件或目录
不同于POSIX,没有可执行标志位,所以没有setuid和setgid;
权限继承方式:创建文件或目录,owner是当前用户,group是上级目录的group( When a file or directory is created, its owner is the user identity of the client process, and its group is the group of the parent directory (the BSD rule))
权限验证方式:任何客户端有user和group两个认证信息,访问任何hdfs上的文件要尽心下面的认证(这个操作仅在NameNode进行):
1. 是否owner; or
2. 文件的group是否包含在用户的group中; or
3. 其他认证(hdfs的acl等授权功能)。
用户标识:
如果使用hdfs命令行,默认,simple模式,取决于os,在类unix系统,等同于`whoami`的输出
如果使用hadoop服务,参见:hadoop获取user/group方式
注:用户标识和group不是hdfs的内在特性。hdfs没有任何创建、删除用户的相关操作。
Group Mapping组映射
根据用户获取组的操作时可配置的(hadoop.security.group.mapping property),默认情况,在linux上相当于执行`groups user`。
这个映射在NN进行,所以要在NN配置。
仅与字符串形式进行。这点与Linux稍有不同(linux有group id)。
实现:
全路径检查,且检查每个子路径的权限。
一旦客户端知道文件块,修改文件权限也不能阻止其访问。
Super-User
NN程序启动的用户即为超级用户。权限检测不会失败;hdfs里没有标记谁是固定的超级用户,也就是,谁启动谁就是超级用户。它不必是NN/DN的root用户。
管理员可指定某个组是超级用户组,改组的所有用户都是超级用户(In addition, the administrator my identify a distinguished group using a configuration parameter. If set, members of this group are also super-users)。超级用户可以“扮演”其他用户,行使他们的权限,但是没看到具体有什么用,参见:http://hadoop.apache.org/docs/r1.2.1/Secure_Impersonation.html
Web Server
网页访问的用户和组是可配置的,NN上没有对应的用户标识。但NN会像有这个用户那样操作hdfs
配置
dfs.permissions.enabled = true
dfs.web.ugi = webuser,webgroup
dfs.permissions.superusergroup = supergroup
fs.permissions.umask-mode = 0022
dfs.cluster.administrators = ACL-for-admins
dfs.namenode.acls.enabled = true 默认关闭
2. yarn资源使用的权限
用户名的获取和认证使用了hadoop通用的那套,参见:hadoop获取user/group方式
3. 操作系统相关权限(Container权限)
YARN Secure Containers : LinuxContainerExecutor
虽然是NM启动的container,但是不能访问NM的私有资源。在程序中使用setuid切换用户到 YARN application user,使用cgroup
LinuxContainerExecutor::
launchContainer->verifyUsernamePattern:
linux-container-executor.nonsecure-mode.user-pattern : container的用户名要满足的正则表达式表达式;默认"^[_.A-Za-z0-9][-@_.A-Za-z0-9]{0,255}?[$]?$"都满足
String getRunAsUser(String user) :
user: 使能安全功能(不是simple模式) || !NM_PREFIX +"linux-container-executor.nonsecure-mode.limit-users"
NM_PREFIX +"linux-container-executor.nonsecure-mode.local-user" 配置值(默认nobody)。
执行container命令行:
containerExecutorExe, // @{container-executor} 可执行程序路径(C语言程序),这个程序中会使用setuid/cgroup操作。
runAsUser, //getRunAsUser return
user, //来自hadoop的获取的用户名
Integer .toString(Commands.LAUNCH_CONTAINER.getValue()), //container-executor命令操作码
appId, //应用名字
containerIdStr, containerWorkDir.toString(),
nmPrivateCotainerScriptPath.toUri().getPath().toString(),
// task的脚本,一般是org.apache.hadoop.mapred.MapReduceChildJVM#getVMCommand得到
nmPrivateTokensPath.toUri().getPath().toString(), //认证使用的token
pidFilePath.toString(),
StringUtils.join(",", localDirs),
StringUtils.join(",", logDirs),
resourcesOptions //cgroup相关信息:组名
defaultContainer:
org.apache.hadoop.mapreduce.v2.app.job.impl.TaskAttemptImpl#createContainerLaunchContext
org.apache.hadoop.mapred.MapReduceChildJVM#getVMCommand --task的jvm命令行拼接
sb.writeLocalWrapperScript(launchDst, pidFile);
注意: defaultContainer使用的是与NM相同的用户启动container,所以本地资源是不隔离的
4. hadoop节点间的权限
kerberos: 解决服务器到服务器的认证;防止了用户伪装成Datanode,Tasktracker,去接受JobTracker,Namenode的任务指派。
解决client到服务器的认证
对用户级别上的认证并没有实现
默认是没有限制。
附录:
1. No such user问题。 hadoop本身没有检查用户合法性的功能(除非配置了第三方插件,如kerberos),但是它要获取一个用户的group。默认情况下,调用操作系统的`groups`命令检查。这就表面上看起来要求NM节点上要有这个用户,但事实是只要能找到用户对应的group(作为一个字符串)即可。参见hadoop获取user/group方式,可以知道配置hadoop.user.group.static.mapping.overrides即可指定用户对应的组,轻松解决这个问题。
15/07/29 14:11:57 INFO ParseDriver: Parse Completed
15/07/29 14:11:57 INFO HiveContext: Initializing HiveMetastoreConnection version 0.13.1 using Spark classes.
15/07/29 14:11:58 INFO metastore: Trying to connect to metastore with URI thrift://heju:9083
15/07/29 14:11:58 WARN ShellBasedUnixGroupsMapping: got exception trying to get groups for user bi_etl
org.apache.hadoop.util.Shell$ExitCodeException: id: bi_etl: No such user
at org.apache.hadoop.util.Shell.runCommand(Shell.java:505)
at org.apache.hadoop.util.Shell.run(Shell.java:418)
at org.apache.hadoop.util.Shell$ShellCommandExecutor.execute(Shell.java:650)
at org.apache.hadoop.util.Shell.execCommand(Shell.java:739)
at org.apache.hadoop.util.Shell.execCommand(Shell.java:722)