也说Hadoop敏感信息加密方案的尝试(下)

前面讲到了AES对称加密的两个不同方案,一是Hive表存储秘钥,一是用KMS来存储秘钥。在这两个大的分类下,又各自有两种不同的方案,每种方案的尝试都是因为踩到了坑,所以才不得不换一种姿势。

前文博客见 也说Hadoop敏感信息加密方式的尝试(上)

#KMS秘钥存储方案 关于KMS的讲解和配置,可见博文 KMS秘钥管理服务(Hadoop)。这里只讲其在加密方案中的应用。

##方案一:直接从KMS获取秘钥 这里利用KMS存储字段加密秘钥,在每个Hive或Spark任务提交到集群的时候,集群都会进行提交者的Kerberos身份认证,我们就在Hive/Spark UDF里利用当前Kerberos身份来获取秘钥。

看起来好像很顺理成章,事实证明 测试环境 下,在Spark UDF里确实可以顺利利用提交账户获取到该账户所能获取到的秘钥,进行字段加解密。但是我们发现在Hive里,这种方案行不通,观察KMS的审计日志发现,所有在beeswaxbeeline里使用UDF提交的查询,向KMS请求秘钥的用户身份都是hive。也就是说Hive里的代理用户身份设置并没有生效,用户向Hive提交的任务,Hive最后还是以hive的身份鉴权和执行!

这里的情况让我有点惊愕,因为我们提交的所有hive任务,其实都是经过了鉴权的,不可能是以hive身份来鉴权。所以意识到是我们在哪弄错了,因为集群上了Sentry,它提供了不止基于UNIX文件系统的鉴权,所以集群上的HiveServer2是与Sentry结合的。所有经过HiveServer2的任务都要先经过Sentry的鉴权,鉴权通过Hive才会往下执行。

而在安装Sentry的时候,是明确要求Hive关闭impersonation的,也即hive.server2.enable.doAs = false,这个功能就是Hive的代理用户功能,关掉它之后,所有提交给Hive的任务都将以hive的身份执行!所以成也Sentry败也Sentry,我们在Hive UDF里拿到的当前认证用户就是hive,拿不到实际提交用户的Kerberos认证!

由于在Hive UDF里拿不到提交用户的Kerberos认证,所以这一方案就被KO了

##方案二:通过MapredContext获取提交用户名 这是对上一个方案的延伸,由于在Hive UDF里拿不到当前提交用户的Kerberos认证,所以只能绕一下。在GenericUDF里有个函数 public void configure(MapredContext context) ,通过传入的context,我们可以用context.getConf()来拿到Map函数的Configuration,然后通过hive.sentry.subject.name配置,拿到提交的真正账户名。

在GenericUDF里,如果configure函数执行的话,它在initialize函数之前执行。通过从configure函数里拿到真正提交账户,我们在initialize函数里向KMS取秘钥就可以利用真正提交账户构造Kerberos认证。

但是configure函数的执行是有条件的,只有Hive的底层引擎是MapReduce时,这个函数才有可能执行,否则它不会执行。所以底层引擎不是它的时候,这种方式是行不通的。

这种方案里我们将授权人员的keytab文件进行AES加密,放入jar包里,将keytab秘钥存于KMS,在Hive UDF里先以hive身份请求keytab文件秘钥,然后解密当前提交账户的keytab。之后利用从configure函数里拿到的提交用户的身份去访问KMS,获取该用户权限范围内的字段秘钥。

方案在这里看起来似乎也是很OK的,在测试环境里,很OK的通过了。然后到线上后,发现出了BUG!无论是Spark还是Hive,都只有部分 能进行加解密成功,从日志上看只加解密了一部分数据就开始报错,报Kerberos认证失败

失败了,那就开始查日志吧,从日志上发现,所有Spark认证失败的都是位于其他节点机上的,而位于提交任务的节点机上的executor则没有失败。在Hive上也一样,位于当前提交任务的节点机上的task是成功的,其他节点机上的是失败的。为什么其他节点机上的任务就会认证失败呢?

其实是因为其他节点机上并没有提交用户的tgt缓存(kinit得到的),无论Spark还是Hive,在启动任务的时候,都会拿到HDFSDelegationToken, YarnDelegationToken等经过Kerberos认证后的token,所有的task上都会带上这些token,而不会带上提交节点机上的Kerberos UGI信息。task之后通过token来做权限验证,在token失效时间之内,用token来做验证就不需要再请求KDC来做认证,直接由token就可以认证当前用户是否有权限执行相关操作!而在用户提交的节点机上,cache里有当前用户的tgt,在上面跑的task通过UGI认证时,可以直接拿到tgt来认证,自然可以认证通过。而其他节点机上并没有提交用户的tgt,认证通过不了,任务自然失败。

上面的问题之所以在测试环境未曾出现,是因为测试环境只有唯一一台节点机上没有测试账户的tgt,而测试的时候,所有的任务刚好都没有分到那台机器上,或者分配到上面没执行成功,任务重试时分配在其他机器上成功了,从而没被我注意到。

方案走到这一步,又走到绝路了。除非在Hive和Spark提交任务时,像HDFSDelegationToken一样,先获取到当前用户或hive用户KMS认证后的DelegationToken,然后以插件的形式注册到任务提交代码里,从而分发到执行节点task上去,由执行节点通过token来做KMS认证。但是这一步不说能不能做成,就单做起来就很麻烦,还可能需要改源码,需要花太大精力,不然官方早就有了完善的加密方案!

或者很猥琐的在集群各节点机上布置需要加解密服务的用户的tgt,让节点上的任务在执行时可以拿到认证信息。但是这样做不是正路子也不方便。

所以方案到这就被掐死了,包括凡是想利用Kerberos认证的方案,到这都走不通!

#Hive表秘钥存储方案 Hive表存储秘钥理解起来就比较简单,但是实践起来也可以分两种方案。一种对外透明,一种需要用户传key,相对猥琐一点。但是实践证明,猥琐的反而好使!

##方案一:在Hive UDF里获取Hive秘钥表的加密key 这种方案属于对外透明型的,用户只需传入加密字段类型和加密字段,就可以完成数据加密,不需要去管秘钥的存储。

但在测试环境验证从Hive UDF取Hive表数据的时候,发现JDBC取Hive表数据在拿到Connection,开始执行SQL语句的时候卡住了,多次尝试一直卡在那,而后台HiveServer2的日志也在get Session后不动。这个问题查了好几次,没查到到底为什么,猜测是在Hive UDF里实际是以hive用户去取Hive表的数据,可能会出现问题,但是并没有查到到底为什么!考虑到在线上环境里,问题还是回到了Kerberos认证的问题,其他节点机上拿不到认证信息,连接HS2都会连不上!所以之后就没有再探索这个问题。

这一方案跟Kerberos认证相关,而且由于Hive UDF里取Hive表数据也存在问题,所以也被KO了

##方案二:UDF提供传入Key的参数,UDF只做加密,由用户传入key 这种方案是当时AES加密里最不看好的一种方案,因为由用户传入key有很大安全隐患,而且API显得特别矬。

但是由于Key存于HIve表,我们可以控制权限。在UDF里我们只做加密,而不做其他额外的操作,UDF本身简单了很多,不用考虑权限认证的问题。所以这是种最简单的方式,经验证也是最行之有效的方式!

就这样,林林总总选择又放弃了前面的五种方案(其实尝试的时候还不止,有些是细节上的变动,这里就没有记录),最后选了一种当初觉得最矬的方案~~ 真是不到最后不甘心啊!

#问题记录

  • 在Hive的Imperonation关闭之后,怎么才能在Hive UDF里拿到真实提交用户的Kerberos认证? 不只是获取提交用户的用户名,而希望拿到UGI。
  • 如何才能在MR的task里分发KMS认证后的DelegationToken?以怎样的形式注册到Hive和Spark的启动程序里,像HDFS和Yarn一样?
  • 在集群上了Sentry的环境下,Hive UDF里获取Hive表无法拿到数据的原因?语句不执行的原因?

如果前两个问题能有效的解决掉,我想一套正式不猥琐的加密方案就可以面世了。加油!加油!

小主们转载请注明出处:https://my.oschina.net/u/2539801/blog/808061

转载于:https://my.oschina.net/kavn/blog/808061

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值