前面讲到了AES对称加密的两个不一样方案,一是Hive表存储秘钥,一是用KMS来存储秘钥。在这两个大的分类下,又各自有两种不一样的方案,每种方案的尝试都是由于踩到了坑,因此才不得不换一种姿式。缓存
前文博客见 也说Hadoop敏感信息加密方式的尝试(上)安全
#KMS秘钥存储方案 关于KMS的讲解和配置,可见博文 KMS秘钥管理服务(Hadoop)。这里只讲其在加密方案中的应用。函数
##方案一:直接从KMS获取秘钥 这里利用KMS存储字段加密秘钥,在每一个Hive或Spark任务提交到集群的时候,集群都会进行提交者的Kerberos身份认证,咱们就在Hive/Spark UDF里利用当前Kerberos身份来获取秘钥。oop
看起来好像很瓜熟蒂落,事实证实 测试环境 下,在Spark UDF里确实能够顺利利用提交帐户获取到该帐户所能获取到的秘钥,进行字段加解密。可是咱们发如今Hive里,这种方案行不通,观察KMS
的审计日志发现,全部在beeswax
或beeline
里使用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认证!.net
因为在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自己简单了不少,不用考虑权限认证的问题。因此这是种最简单的方式,经验证也是最行之有效的方式!
就这样,林林总总选择又放弃了前面的五种方案(其实尝试的时候还不止,有些是细节上的变更,这里就没有记录),最后选了一种当初以为最矬的方案~~ 真是不到最后不甘心啊!
#问题记录
若是前两个问题能有效的解决掉,我想一套正式不猥琐的加密方案就能够面世了。加油!加油!
小主们转载请注明出处:http://www.javashuo.com/article/p-dyogxpxc-hq.html