本文记录YARN、Spark、Hive各服务配置使用kerberos的过程。
我的环境:
目的是将YARN接入到kerberos集群里,使得:
配置:修改yarn-site.xml,指定rm和nm的Principal和keytab,将该文件同步到所有节点。
<property>
<name>yarn.resourcemanager.principalname>
<value>rm/_HOST@ZELDA.COMvalue>
property>
<property>
<name>yarn.resourcemanager.keytabname>
<value>/etc/security/rm.service.keytabvalue>
property>
<property>
<name>yarn.nodemanager.principalname>
<value>nm/_HOST@ZELDA.COMvalue>
property>
<property>
<name>yarn.nodemanager.keytabname>
<value>/etc/security/nm.service.keytabvalue>
property>
Hortonworks还会要求配置container-excutor为LinuxContainer,可以有更好的物理隔离(底层为lxc)。但由于它需要启动container-executor,而这个要求配置文件container-executor.cfg必须为root权限,并且其上层所有目录权限都是root,所以只能把配置文件放到/etc/下,但是!container-executor代码里写死了配置文件的路径为../etc/,所以只能重新编译一个container-excutor。
所以我就先没配,挖个坑。
更详细的资料
目的是spark-submit提交作业的时候,能够接入到kerberos中,从而向YARN提交作业、访问HDFS等等。
针对spark-submit的任务,有两种办法通过kerberos认证:
--keytab /etc/security/dtdream.zelda1.keytab --principaldtdream/zelda1@ZELDA.COM
,注意紧跟着命令,不要放到最后(会被当做spark JOB的参数)总之还是以keytab的方式来的,只是从当前Principal缓存里读取,还是自己从keytab里读取。
1、新增一个Principal:
addprinc -randkey dtdream/zelda1@ZELDA.COM
xst -k dtdream.spark.keytab dtdream/zelda1@ZELDA.COM
2、将生成的dtdream.spark.keytab文件拷贝到/etc/security/下
3、kinit后submit作业
kinit -kt /etc/security/dtdream.spark.keytab dtdream/zelda1
klist #检查Principal缓存
./bin/spark-submit --master yarn --class org.apache.spark.examples.SparkLR --name SparkLR lib/spark-examples-1.6.1-hadoop2.6.0.jar
或者跳过kinit直接指定keytab路径:
./bin/spark-submit --keytab /etc/security/dtdream.zelda1.keytab --principal dtdream/zelda1@ZELDA.COM --master yarn --class org.apache.spark.examples.SparkLR --name SparkLR lib/spark-examples-1.6.1-hadoop2.6.0.jar
spark sql的thriftserver是作为一个spark作业,通过spark-submit提交给yarn的,启动之前需要设置kinit或者指定keytab由spark-submit自己loginfromkeytab。
spark-submit还可以指定–proxy-user参数,可以模拟其他用户来提交job。
hive支持三种:Kerberos、LDAP、CUSTOM(自定义插件)。如果使用 Kerberos 身份验证,Thrift 客户端和 HiveServer2 以及 HiveServer2 和安全 HDFS 之间都支持身份验证。如果使用 LDAP 身份验证,仅在 Thrift 客户端和 HiveServer2 之间支持身份验证(CUSTOM类似)。
下面采用kerberos认证的配置。
<property>
<name>hive.server2.enable.doAsname>
<value>falsevalue>
property>
<property>
<name>hive.server2.authenticationname>
<value>KERBEROSvalue>
property>
<property>
<name>hive.server2.authentication.kerberos.principalname>
<value>dtdream/_HOST@ZELDA.COMvalue>
property>
<property>
<name>hive.server2.authentication.kerberos.keytabname>
<value>/etc/security/dtdream.zelda1.keytabvalue>
property>
注意需要先kinit保证已经有Principal缓存。Kerberos客户端支持两种,一是使用Principal+Password,二是使用Principal+keytab,前者适合交互式应用,例如hadoop fs -ls这种,后者适合服务,例如yarn的rm、nm等。两种初始化方法的命令如下:
$ kinit zlatan/zelda1@ZELDA.COM
Password for zlatan/zelda1@ZELDA.COM:
--
$ kinit -k -t /../xx.keytab {username}/{instance}@{REALM}.COM
kinit后,启动hiveserver2,使用beeline登录:
beeline> !connect jdbc:hive2://zelda1:10000/default;principal=dtdream/zelda1@ZELDA.COM;
Connecting to jdbc:hive2://zelda1:10000/default;principal=dtdream/zelda1@ZELDA.COM;
Enter username for jdbc:hive2://zelda1:10000/default;principal=dtdream/zelda1@ZELDA.COM;:
Enter password for jdbc:hive2://zelda1:10000/default;principal=dtdream/zelda1@ZELDA.COM;:
Connected to: Apache Hive (version 2.0.0)
Driver: Hive JDBC (version 2.0.0)
16/06/13 10:46:50 [main]: WARN jdbc.HiveConnection: Request to set autoCommit to false; Hive does not support autoCommit=false.
Transaction isolation: TRANSACTION_REPEATABLE_READ
注意这里还是会提示输入用户名、密码,是个bug,别理它,直接回车就好了,我们用的其实是klist的Principal缓存来表示我是谁。 beeline会将Principal传给hive2 JDBC,由JDBC Driver去做Kerberos认证,这个过程略微复杂,等我弄懂了再写篇文章。
目的是让不同的用户,使用不同的身份来登录beeline。
1、使用管理员账户kinit到Kerberos
我们用dtdream/zelda1@ZELDA.COM。thriftserver实际是个spark Job,通过spark-submit提交到YARN上去,需要这个账户用来访问YARN和HDFS;如果使用一些普通账户,由于HDFS权限不足,可能启动不了,因为需要往HDFS写一些东西。
2、配置spark配置文件里的hive-site.xml
thriftserver在YARN上跑起来了以后,也需要接入到Kerberos,hive-site里指定的就是这个Principal,这里我也是用的Principal。
配置跟前面hive的一样,注意doAs务必是true,否则又会包shim包找不到的错误;又由于doAs是true,所以下面需要安全伪装(我猜的)。
<property>
<name>hive.server2.enable.doAsname>
<value>truevalue>
property>
<property>
<name>hive.server2.authenticationname>
<value>KERBEROSvalue>
property>
<property>
<name>hive.server2.authentication.kerberos.principalname>
<value>dtdream/_HOST@ZELDA.COMvalue>
property>
<property>
<name>hive.server2.authentication.kerberos.keytabname>
<value>/etc/security/dtdream.zelda1.keytabvalue>
property>
3、配置hadoop安全伪装
跟hive不一样,spark sql thriftserver需要使用安全伪装。
修改hadoop的core-site.xml,配合doAs,[email protected]�人,例如zlatan/zelda1@ZELDA.COM登录到beeline上以后,thriftserver会使用zlatan的权限去访问HDFS,而不是启动thriftserver的这个Principal(即dtdream/zelda@ZELDA.COM)。
<property>
<name>hadoop.proxyuser.dtdream.hostsname>
<value>*value>
property>
<property>
<name>hadoop.proxyuser.dtdream.groupsname>
<value>*value>
property>
4、启动spark sql thriftserver
./start-thriftserver.sh --master yarn --driver-java-options '-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=13838' --executor-memory 6g --driver-memory 6g --conf spark.yarn.executor.memoryOverhead=4096 --driver-class-path /home/dtdream/spark/spark-1.6.1-bin-hadoop2.6/lib/mysql-connector-java-5.1.35-bin.jar
我在里面指定了remote debug,可以用IDEA远程连接到机器上调试。
5、登录跟hive一样,需要先kinit一个用户(密码or keytab),然后JDBC connect上去。
beeline > !connect jdbc:hive2://zelda1:20000/default;principal=dtdream/zelda1@ZELDA.COM;
Connecting to jdbc:hive2://zelda1:20000/default;principal=dtdream/zelda1@ZELDA.COM;
Enter username for jdbc:hive2://zelda1:20000/default;principal=dtdream/zelda1@ZELDA.COM;:
Enter password for jdbc:hive2://zelda1:20000/default;principal=dtdream/zelda1@ZELDA.COM;:
16/06/13 14:45:30 INFO Utils: Supplied authorities: zelda1:20000
16/06/13 14:45:30 INFO Utils: Resolved authority: zelda1:20000
16/06/13 14:45:30 INFO HiveConnection: Will try to open client transport with JDBC Uri: jdbc:hive2://zelda1:20000/default;principal=dtdream/zelda1@ZELDA.COM;
Connected to: Spark SQL (version 1.6.1)
Driver: Spark Project Core (version 1.6.1)
Transaction isolation: TRANSACTION_REPEATABLE_READ
6: jdbc:hive2://zelda1:20000/default> show databases;
beeline登录时遇到的几个问题:
1、Unsupported mechanism
beeline> !connect jdbc:hive2://zelda1:20000/default
16/06/12 14:24:32 INFO HiveConnection: Transport Used for JDBC connection: null
Error: Could not open client transport with JDBC Uri: jdbc:hive2://zelda1:20000/default: Peer indicated failure: Unsupported mechanism type PLAIN (state=08S01,code=0)
需要指定principal。不指定的话显然就是PLAIN方式啊笨蛋。
2、不准伪装!
beeline> !connect jdbc:hive2://zelda1:20000/default;principal=dtdream/zelda1@ZELDA.COM
Connecting to jdbc:hive2://zelda1:20000/default;principal=dtdream/zelda1@ZELDA.COM
Enter username for jdbc:hive2://zelda1:20000/default;principal=dtdream/zelda1@ZELDA.COM:
Enter password for jdbc:hive2://zelda1:20000/default;principal=dtdream/zelda1@ZELDA.COM:
16/06/12 14:40:42 INFO Utils: Supplied authorities: zelda1:20000
16/06/12 14:40:42 INFO Utils: Resolved authority: zelda1:20000
16/06/12 14:40:43 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
16/06/12 14:40:43 INFO HiveConnection: Will try to open client transport with JDBC Uri: jdbc:hive2://zelda1:20000/default;principal=dtdream/zelda1@ZELDA.COM
Error: Failed to open new session: java.lang.RuntimeException: java.lang.RuntimeException: org.apache.hadoop.ipc.RemoteException(org.apache.hadoop.security.authorize.AuthorizationException): User: dtdream/zelda1@ZELDA.COM is not allowed to impersonate dtdream (state=,code=0)
需要配置安全伪装。
前面的方案要求先kinit,每个client(linux用户级别)当前只能有一个用户,其他用户再kinit会顶替掉当前的Principal,不适合多租户和编程场景:
In the current approach of using Kerberos you need to have a valid Kerberos ticket in the ticket cache before connecting. This entails a static login (using kinit, key tab or ticketcache) and the restriction of one Kerberos user per client. These restrictions limit the usage in middleware systems and other multi-user scenarios, and in scenarios where the client wants to login programmatically to Kerberos KDC.
不过hive提供了secure proxy users功能,
我们这里先关注JDBC,它的方法比较简单,增加hive.server2.proxy.user=bob参数即可。
beeline> !connect jdbc:hive2://zelda1:20000/default;principal=dtdream/zelda1@ZELDA.COM;hive.server2.proxy.user=bob
0: jdbc:hive2://zelda1:20000/default> insert into x1 select t.* from (select 105, 37) t;
Error: java.lang.RuntimeException: Cannot create staging directory 'hdfs://zelda1/user/hive/warehouse/dtdream.db/x1/.hive-staging_hive_2016-06-14_11-15-29_063_112329594714965380-1': Permission denied: user=bob, access=WRITE, inode="/user/hive/warehouse/dtdream.db/x1/.hive-staging_hive_2016-06-14_11-15-29_063_112329594714965380-1":dtdream:supergroup:drwxrwxr-x
基于存储的认证、授权模型基本是可用的了,若辅助以Ranger这样的权限控制,会比较灵活、统一。不过这里还有个问题,Kerberos的用户怎么跟Ranger打通(啊!)。目前Ranger只支持跟UNIX和LDAP/AD用户同步。
使用Kerberos,的确可以解决服务互相认证、用户认证的功能。
场景1:用户提交spark App。需要该用户有kerberos的权限,以及对应的yarn、hdfs的读写权限等。
场景2:jdbc登录。以beeline为例,不同的用户通过kinit使用自己的Principal+密码通过Kerberos的AS认证拿到TGT,就可以登录到spark sql thriftserver上去查看库、表;不过由于sts还不支持sqlbased authorization,所以还只能做到底层hdfs的权限隔离,比较可惜;相对来说hive的完整度高一些,支持SQLstandard authorization。
对于Zeppeline或者数梦的dataStudio这样的产品来说,web服务可以使用管理员账户启动;普通用户先通过Studio的认证,在JDBC访问Spark thrift server的时候,studio可以使用Principal+proxyUser的方式,以当前会话的用户的身份,来访问最终资源如HDFS,以达到认证+数据隔离的目的。
仔细阅读:
HiveServer2 Clients
通过WEB修改用户的kerberos密码
传送门:
Kerberos从入门到放弃(一):HDFS使用kerberos
Kerberos从入门到放弃(二):YARN、Spark、Hive使用kerberos
Kerberos从入门到放弃(三):kerberos+LDAP各司其职