一文搞懂hadoop中的用户

原创
2022/04/23 00:13
阅读数 1.3K

又有一段时间没有更新了,最近忙着搬砖的同时,也填了一些坑,其中不少坑是有关联的,甚至其中有一个配置项接连引发了两三个问题,后续打算逐个总结输出,这里先进行一些铺垫~

【hadoop的用户概述】


在hadoop中,客户端不管是向hdfs请求上传下载文件,还是向yarn提交任务、下载查看任务的日志,都会指定一个用户来进行操作。

在开启了ACL鉴权机制后,hdfs的namenode,yarn的resourcemanager还会根据请求的用户信息来进行权限校验,查看该用户是否有权限进行对应的操作。

那么,客户端中的用户信息是如何指定的,又是如何在rpc通信中传递给服务端的,本文就来聊聊hadoop中用户相关的内容。

【如何指定用户】


客户端中用户信息的指定可分为两种场景,不启用kerberos认证的场景和启用kerberos认证的场景。

1. 非kerberos认证场景

在不启用kerberos认证的场景中,客户端依次通过环境变量配置参数以及当前运行程序的系统用户来获取用于hadoop操作的用户信息。

  • 环境变量(HADOOP_USER_NAME)

  • 配置参数属性(-DHADOOP_USER_NAME=xxx)

  • 当前运行程序的系统用户

一个示例如下所示:

[root@nn-0 /]# cat test.sh
#!/bin/bash

# "use -D"
export HADOOP_CLIENT_OPTS=-DHADOOP_USER_NAME=bigdata
hdfs dfs -mkdir /test1

# "use env"
export HADOOP_USER_NAME=hncscwc
hdfs dfs -mkdir /test2
unset HADOOP_USER_NAME

# "use system user"
unset HADOOP_CLIENT_OPTS
hdfs dfs -mkdir /test3

# "list directory"
hdfs dfs -ls /
[root@nn-0 /]# sh test.sh
Found 6 items
drwxr-xr-x - root supergroup 0 2022-04-07 15:44 /benchmarks
drwxr-xr-x - root supergroup 0 2022-04-07 15:44 /history
drwxr-xr-x - bigdata supergroup 0 2022-04-21 14:16 /test1
drwxr-xr-x - hncscwc supergroup 0 2022-04-21 14:16 /test2
drwxr-xr-x - root supergroup 0 2022-04-21 14:16 /test3
drwx------ - root supergroup 0 2022-04-07 15:44 /tmp

注1:由于使用了hdfs自带的命令,因此是通过HADOOP_CLIENT_OPTS环境变量进行-DHADOOP_USER_NAME参数的设置(可查看hdfs脚本命令的实现)

注2:第二个测试时,未清除前一个测试设置的参数,即此时同时指定了环境变量和启动参数,但环境变量的优先级更高。

注3:最后一个测试前,先清除了第一次创建目录时导入的环境变量,即此时环境变量与启动参数均未指定,因此采用当前系统用户作为hdfs客户端的操作用户。

2.  kerberos场景

在启用了kerberos认证的情况下,又分为两种情况获取用户信息,一种是从系统缓存的票据(ticket)中获取用户信息;一种是指定principal以及keytab文件,然后调用hadoop提供的接口完成kerberos认证,并从中得到用户信息。

从ticket中获取:

多数情况下, 我们会先通过kinit向kdc完成认证并获取票据,然后再进行相关的操作。此时程序不需要有额外的设置,会自动从系统缓存的票据中获取到principal,并从中解析出用户名,以此作为hadoop操作的用户。

例如:

[root@namenode-0 ~]# kinit hncscwc
Password for hncscwc@BIGDATA.COM:
[root@namenode-0 ~]# klist
Ticket cache: FILE:/tmp/krb5cc_0
Default principal: hncscwc@BIGDATA.COM

Valid starting Expires Service principal
04/22/2022 10:26:48 04/23/2022 10:26:48 krbtgt/BIGDATA.COM@BIGDATA.COM
        renew until 04/22/2022 10:26:48

[root@namenode-0 ~]# hdfs dfs -mkdir /user/hncscwc/test1
[root@namenode-0 ~]# hdfs dfs -ls /user/hncscwc
Found 1 items
drwxr-xr-x - hncscwc supergroup 0 2022-04-22 10:29 /user/hncscwc/test1

指定principal与keytab并调用对应接口

这也是一种常用的手段,通过指定principal,以及对应的keytab文件,随后调用hadoop提供的接口完成kerberos认证,并从中获取到hadoop操作的用户信息,然后使用该用户信息进行rpc通信。

调用流程的大概步骤如下所示:

// 使用principal, keytab登录
UserGroupInformation.loginUserFromKeytab(principal, keytab);
// 获取ugi类实例
UserGroupInformation ugi = UserGroupInformation.getCurrentUser();
// 执行具体的rpc请求
ugi.doAs(
    @Override
    public void run() throws Exceptions {
        FileSystem fs = FileSystem.get(conf);
        FSDataOutputStream out = fs.create(new Path(filePath), true);
        Date date = new Date();
        out.write(date.toString().getBytes());
        out.flush();
        out.close();
        return ;
    }
);

注:需要进行交互的操作都需要放到doAs中完成

【内部实现】


1. 重要的实现类

在具体的实现中,用户信息对应的类为UserGroupInformation。该类又通过JAAS(Java Authentication and Autorization Service)结合,实现了用户信息的获取与保存。

在该类的内部通过jaas的subject作为成员变量保存用户的信息;根据不同的认证方式(是否启用kerberos认证),调用jaas的不同接口实现获取对应的用户信息。

2. rpc通信过程中用户信息的传递

在rpc的交互过程中,用户信息会作为协议的一部分传递给服务端

protobuffer协议中用户信息的定义:

客户端中对应的用户信息构造逻辑:

同时,在服务端一侧,会先从请求中解析出用户信息,然后构造对应的UserGroupInformation类实例,并将该信息作为请求的一部分(Call实例对象的成员),向上传递给后续的handler处理。

【用户代理】


考虑一种场景,在开启kerberos认证后,每个服务启动后都会以各自的principal向kdc登录完成认证,此后就以该principal对应的票据信息向其他服务进行访问。

如果某个服务支持不同用户登录,然后根据用户请求完成不同的逻辑业务处理,例如操作hdfs。此时,这个服务可能需要为每个用户维护一个有效的票据,或者持有该用户的用户名密码信息,或者principal与keytab信息,确保通过kerberos认证的同时,可以以该用户的身份进行后续的操作。

这显然不是一种好的做法,并且还需要动态维护用户信息,例如用户的新增等。

一个实际的场景,不同的用户各自通过jdbc连接到hiveserver2,进行相关操作,而hiveserver2最终需要以不同的用户到hdfs上进行文件的操作。

为了友好地解决这个问题,代理用户(proxyUser)就应运而生。

注:在开启kerberos认证的场景下,一个进程中同时维持多个用户的principal会存在bug,官方的jira单中,有进行相关的讨论,但最终给出的方案仍旧是试用代理用户的方式。

代理用户是个什么概念?

代理用户就是以某个用户完成kerberos的认证工作后,以该用户对应的principal与其他服务进行通信,同时为其他用户代理提供hadoop的相关访问操作。

代理用户的具体配置方法是添加如下配置项:

<property>
    <name>hadoop.proxyuser.${SuperUserName}.hosts</name>
    <value>${HostLists}</value>
</property>
<property>
    <name>hadoop.proxyuser.${SuperUserName}.groups</name>
    <value>${Groups}</value>
</property>

<!-- 说明 -->
<!-- ${SuperUserName} 为具有代理功能的用户,通常也是超级用户, 这意味着并不是每个用户都能成为代理用户 -->
<!-- ${HostLists} 为代理用户能正确完成代理功能的主机地址列表 -->
<!-- ${Groups} 为代理用户能代理的用户组, 也就是能为那些用户组中的用户进行代理 -->

<!-- 示例 -->
<!-- hadoop用户为代理用户, 可以为任意用户进行代理, 但仅在hive-server.hncscwc主机地址上能够正确完成代理工作 -->
<property>
    <name>hadoop.proxyuser.hadoop.hosts</name>
    <value>hive-server2.hncscwc</value>
</property>
<property>
    <name>hadoop.proxyuser.hadoop.groups</name>
    <value>*</value>
</property>

代理用户的内部实现:

在UserGroupInformation类中,提供了创建代理用户的接口,该接口需要传入代理用户的用户名、以及真实用户(被代理用户)的用户信息。

而前面提到了用户信息作为rpc协议的一部分,从protobuffer的定义中可以看到,用户信息有两个值:一个是有效用户(也就是代理用户的用户名),另一个是真实用户(也就是被代理用户的用户名),两者一并传递给了服务端。

在服务端最终使用代理用户完成认证工作,而使用真实用户信息完成鉴权工作,这样,请求可以被正确调用的同时,能确保按照真实用户的信息进行鉴权操作。

有了代理用户后,只需要以代理用户完成kerberos认证,后续以该用户的principal与namenode或resourcemanager进行交互,同时又确保可以按真实用户的信息进行权限控制,而不至于出现权限放大或缩小的情况。

【总结】


小结一下,本文讲述了hadoop中的用户信息,包括客户端在不同认证情况下如何指定用户,用户信息如何在rpc请求中传递给服务端。最后扩展讲解了代理用户的使用场景,如何配置,以及内部的大概实现逻辑。

好了,这就是本文的全部内容,如果觉得本文对您有帮助,请点赞转发,也欢迎加我微信交流~

 

本文分享自微信公众号 - hncscwc(gh_383bc7486c1a)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

展开阅读全文
加载中

作者的其它热门文章

打赏
0
2 收藏
分享
打赏
0 评论
2 收藏
0
分享
返回顶部
顶部