前面講到了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