Kerberos身份驗證在ChunJun中的落地實踐

語言: CN / TW / HK

Kerberos,在古希臘神話故事中,指的是一隻三頭犬守護在地獄之門外,禁止任何人類闖入地獄之中。

那麼在現實中,Kerberos指的是什麼呢?

一、Kerberos介紹

01 Kerberos是什麼

根據百度詞條釋義,Kerberos是一種計算機網絡授權協議,用來在非安全網絡中,對個人通信以安全的手段進行身份認證。Kerberos旨在通過密鑰加密技術為客户端/服務器應用程序提供身份驗證,主要用在域環境下的身份驗證。

在此之前,通常只有服務器的運維管理人員在配置Active Directory之類的東西時才會接觸到Kerberos,但隨着大數據的流行,整個Hadoop生態圈在安全方面對於Kerberos愈發依賴,同時由於Kerberos認證必須入侵式改造代碼的特點,使得越來越多的大數據開發同學開始接觸到Kerberos。

02 Kerberos 解決了什麼問題

目前用於身份密碼的驗證主要面臨兩個問題:首先是人工記憶的密碼混亂且易遺忘,一些比較簡單的密碼又容易被攻擊;其次是技術錯覺,在計算機上的輸入密碼時顯示的是一串星號,大家誤以為很安全,實際上計算機通過網絡發送密碼基本是發送“明文”密碼,大部分密碼都處於“裸奔”狀態。

Kerberos的出現很好的解決了這個問題,它減少了每個用户使用整個網絡時必須記住的密碼數量——只需記住 Kerberos 密碼,同時Kerberos結合了加密和消息完整性來確保敏感的身份驗證數據不會在網絡上透明地發送。通過提供安全的身份驗證機制,Kerberos為最終用户和管理員提供了明顯的好處。

03 Kerberos 基本概念

principal 是Kerberos 世界的用户名,用於標識身份,每個用户都會有一個 principal,如果 principal 失效或者不正確,那麼這個用户將無法訪問任何資源。principal 主要由三部分構成:primary,instance(可選) 和 realm。

file

● primary

主體,每個 principal 都會有的組成部分,代表用户名(username)或服務名(service name)。

● instance

用於服務主體以及用來創建用於管理的特殊主體。instance 用於服務主體時的一般會用於區分同一服務在不同服務器上的服務實例,因此與 primary 組成的 principal 一般用於 server 端,如:NameNode,HiverServer2,Presto Coordinator等。

instance 用來創建用於管理的特殊主體時,一般來區分同一個用户的不同身份,如區分擔任管理員角色的 a 用户與擔任研發的 a 用户。

● realm

realm 是認證管理域名,用來創建認證的邊界,只有在同屬於一個認證服務的邊界內,這個認證服務才有權利認證一個用户、主機或者服務。每個域都會有一個與之對應的 kdc 服務用於提供域內的所有服務的認證服務。

● keytab

"密碼本",包含了多個 principal 與密碼的文件,用户可以利用該文件進行身份認證。

● ticket cache

客户端與 KDC 交互完成後,包含身份認證信息的文件,短期有效,需要不斷renew。

file

04 Kerberos 的認證簡介

file

參與 Kerberos 認證過程中的角色:

  1. 訪問服務的 Client;

  2. 提供服務的 Server;

  3. DC是Domain Controller的縮寫,即域控制器;AD是Active Directory的縮寫,即活動目錄。DC中有一個特殊用户叫做krbtgt,它是一個無法登錄的賬户,是在創建域時系統自動創建的,在整個Kerberos認證中會多次用到它的Hash值去做驗證。

  4. KDC(Key Distribution Center)密鑰分發中心。在KDC中又分為兩個部分:Authentication Service(AS,身份驗證服務)和Ticket Granting Service(TGS)

  5. AD會維護一個Account Database(賬户數據庫), 它存儲了域中所有用户的密碼Hash和白名單,只有賬户密碼都在白名單中的Client才能申請到TGT。

05 Kerberos詳細認證流程

1. Client with AS

客户端(Client)向 AS(Authentication Service)發送請求獲取 TGT(ticket grant ticket)

file

2. Client with TGS

客户端(Client)向 TGS(Ticket Granting Service,)發送請求獲取ST(Service Ticke)

file

客户端(Client)向服務端(Server)發送認證請求進行認證,如果客户端(Client)要求進行雙向認證,服務端(Server)額外發送認證請求至客户端(Client)進行認證。

file

3.Kerberos 與 JAAS可插拔的認證模塊

JAAS jdk 在1.4引入的一種可插拔的認證模塊( Pluggable Authentication Module,PAM )的安全體系結構,這意味着可以通過改變模塊,支持從一種安全協議組件無縫的切換到另一個協議組件。

同時這種體系架構定義的接口無需修改代碼即可實現加入多種認證技術和授權機制,因為 JAAS API 定義了應用程序代碼與實際驗證邏輯之間的抽象,這個抽象不用重新編譯現有的應用程序代碼就可以作為登錄模塊的運行時替代。

這種實現方式是通過應用程序只調用 LoginContext 接口,而認證技術的實際提供程序則是基於 LoginModule 接口進行開發的,在運行時LoginContext 通過讀取配置文件確定使用哪些認證模塊來對應用程序進行認證。

file

二、ChunJun任務提交中的Kerberos認證

接下來我們來大家介紹下ChunJun任務提交中的 Kerberos 認證,我們可以參考ChunJun的 readme 文檔中的 yarn session 部分:

https://github.com/DTStack/chunjun/blob/master/README_CH.md

file

01 Flink 提交流程中的 Kerberos

首先,我們需要啟動一個 yarn session 環境,進入 Flink 的 bin 目錄下執行 yarn-session 腳本啟動 flink session 並使用 -t 參數上傳 ChunJun 的依賴包。

file

當我們執行 yarn-session 時,腳本內部會調用 java 命令運行 FlinkYarnSessionCli 這個類的 main 方法。在 FlinkYarnSessionCli 的 main 方法中,首先需要安裝一個全過程的安全配置,然後獲得一個安裝後的上下文,並且在上下文中運行 run 方法。

file

在 run 方法中我們構建了一個 YarnClusterDescripter 對象,這個對象中封裝了 Flink 所依賴的配置文件和 jar 包等。而後再調用YarnClusterDescripter 對象的 DeploySessionClister 方法將任務提交到 yarn 集羣。至此完成了 Flink session 到 Yarn 的一個提交。

file

我們再回顧下整體的提交流程:

file

● Flink => HDFS

Flink 需要將配置文件以及 session 所依賴的 jar 上傳至 HDFS,因此需要與 HDFS 進行通信

● Flink => Yarn

Flink 需要向 Yarn 申請資源,因此需要與 Yarn 進行通信

Flink => Zookeeper

如果 Flink 配置了基於 zookeeper 的高可用,那麼 JobManager 需要在 Zookeeper 註冊 leader 節點,客户端還需要從 Zookeeper 上的 leader 節點獲取 webMonitorUrl,因此需要與 Zookeeper 通信

02 Flink SecurityUtils作用於 Kerberos 認證

1.SecurityUtils.java

file

2.SecurityUtils#install 方法中首先通過 installModules 方法對 Flink 內部的安全模組進行了 install(其中包括Hadoop、Jaas、Zookeeper 模組)

file

3.SecurityUtils#installContext 方法對安全上下文進行初始化(獲得 HadoopSecurityContext,其中包含這 hadoop 的認證憑證 ugi)

file

03 Flink Hadoop Kerberos 認證

$Flink_HOME/conf/Flink-conf.yaml

security.Kerberos.login.use-ticket-cache: 是否從你的Kerberos ticket緩存中讀取

security.Kerberos.login.keytab: 包含用户憑證的Kerberos keytab文件的絕對路徑。

security.Kerberos.login.principal: 與keytab相關的Kerberos principal名稱。

security.Kerberos.krb5-conf.path:指定 krb5.conf 文件的本地位置。如果定義了,這個conf將被掛載到Kubernetes、Yarn和Mesos的JobManager和TaskManager容器/桶上。注意: 需要在容器內部可訪問到定義的 KDC 的地址。

security.Kerberos.login.contexts: 用逗號分隔的登錄上下文列表,以提供Kerberos憑證(例如,Client,KafkaClient用於ZooKeeper認證和Kafka認證的憑證)。

zookeeper.sasl.service-name: 默認為 "zookeeper"。如果ZooKeeper quorum配置了一個不同的服務名稱,那麼可以在這裏提供。

zookeeper.sasl.login-context-name: 默認為 "Client"。該值需要與 "security.Kerberos.login.contexts"中配置的值之一相匹配。

file

04 ChunJun 提交流程中的 Kerberos

執行 ChunJun-Yarn-session.sh 提交任務,ChunJun-Yarn-session.sh 實際上只是對任務的腳本路徑進行了檢查校驗,然後再執行 submit.sh 腳本啟動任務提交進程。

file

Launcher 的 main 方法中主要對不同的任務執行模式進行區分並交給各個模式具體的任務提交類去提交任務。

file

YarnSessionClusterClientHelper 將任務的配置以及依賴的 jar 進行組裝獲得 YarnClusterDescriptor 對象。再將任務提交到對應的 Flink session 上。

file

三、ChunJun Connector 中的Kerberos 認證

接下來為大家介紹 ChunJun Connector 中的 Kerberos 認證 。

01ChunJun 插件中的 Kerberos

以 ChunJun HDFS Connector 為例:

插件在 openInputFormat 方法中會對任務的目標數據源 HDFS 是否開啟了 Kerberos 進行判斷,如果開啟了 Kerberos,則會根據配置的認證文件進行認證並獲取認證後的 ugi,ugi 可以認為是之後插件與 HDFS 通信的用户憑證,裏面保存着用户的認證信息.

file

02 如何進行Kerberos 認證

● OpenInputFormat 方法

OpenInputFormat 方法是 Flink 對算子的每個實例進行初始化是都會執行的方法,ChunJun 的BaseRichInputFormat 也實現了該方法,我們開發插件也都會去實現該方法。

對於每個算子實例來説,Kerberos 認證只會進行一次(不包括認證過期後的刷新),因此 Kerberos 認證的代碼應該在該方法中實現.

file

● 開發 hadoop 生態中的數據源組件

一般而言,Hadoop 生態中的數據源組件如:HDFS、HBase、Hive 等都是用 ugi(UserGroupInformation) 進行 Kerberos 認證。

ChunJun 內部也提供了相關的工具類用於獲取登錄後的 ugi:com.dtstack.ChunJun.util.FileSystemUtil#getUGI

● 開發 Zookeeper、Kafka 等組件

這類組件開啟 Kerberos 認證後,用户需要在插件端配置 jaas.conf 文件,再通過各個組件提供的參數配置項配置組件所選用的 jaas.conf 的 entry,即可完成 Kerberos 配置。

03 如何排查 Kerberos 認證問題

$Flink_HOME/conf/Flink-conf.yaml

#jvm 啟動參數中增加 “-Dsun.security.krb5.debug=true”

env.java.opts:用於配置啟動所有Flink進程的JVM 參數

env.java.opts.jobmanager:用來配置啟動 JobManager 的 JVM 參數

env.java.opts.taskmanager:用來配置啟動 TaskManager 的 JVM 參數

env.java.opts.historyserver:用來配置啟動 HistoryServer 的 JVM 參數

env.java.opts.client:用來配置啟動 Flink Client 的 JVM 參數

04 Kerberos 認證常見問題

1.javax.security.sasl.SaslException: GSS initiate failed [Caused by GSSException: No valid credentials provided (Mechanism level: Failed to find any Kerberos tgt)]

此消息表明一個操作嘗試要求以Kerberos的user/host@realm身份認證的操作,但票據cache中沒有用於user/host@realm的票據。

用户環境引用的策略/票證緩存文件丟失、不可讀(權限)、損壞或無效票證續簽壽命設置為零

票證授予票證(TGT)不存在,因為服務A需要將命令作為服務B運行,但尚未正確配置為允許模擬服務B

票證更新尚未執行/未成功。這可能是由於CDH 5.3之前的HBASE或CDH5.2之前的Hive / Sentry缺陷引起的

該用户的憑據尚未在KDC中生成

執行了手動步驟,例如hadoop fs -ls,但是用户從未通過Kerberos身份驗證

Oracle JDK 6 Update 26或更早版本無法讀取由MIT Kerberos 1.8.1或更高版本創建的Kerberos憑證高速緩存。

某些版本的Oracle JDK 8可能會遇到此問題

2.javax.security.sasl.SaslException: GSS initiate failed [Caused by GSSException: No valid credentials provided (Mechanism level: Fail to create credential. (63) - No service creds)]

由JDK缺陷引起

票證消息對於UDP協議而言太大

主機未正確映射到Kerberos領域

3.Found unsupported keytype(18)

確保正確安裝了與JDK相匹配的無限強度策略文件的正確版本

確保對策略文件(位於jdk目錄中,例如/usr/java/jdk1.7.0_67-cloudera/jre/lib/security/)的許可權能夠被所有用户讀取。

確保文件已部署到集羣軟件正在使用的jdk中

有關詳細信息,使用以下的(鏈接以匹配關鍵字類型號18在該實例中)將其加密類型http://www.iana.org/assignments/Kerberos-parameters/Kerberos-parameters.xml(AES256-CTS-HMAC-此示例為sha1-96)

4.GSSException: No valid credentials provided (Mechanism level: Server not found in Kerberos database (7) - UNKNOWN_SERVER)

hostname或要訪問的URL與keytab中列出的主機之間發生主機名不匹配。造成這種情況的原因多種多樣,包括但不限於:

多網卡(NIC)服務器,以使來自主機的數據包的IP地址與通過主機解析返回的IP不匹配

負載平衡器和後續的主機名解析問題

DNS和主機名解析問題/不一致

反向DNS(必需)主機名解析問題/不一致

在krb5.conf中主機正在映射到參數[domain_realm]的錯誤域,這或者是通過其他的krb5.conf配置,或者是通過KDC配置。默認參數情況下,除非使用[domain_realm]等進行顯式配置,否則主機名(例如:“ crash.EXAMPLE.com ”)將映射到域“ EXAMPLE.com ” 。請參見MIT Kerberos文檔:[domain_realm]

如果嘗試在Cloudera Manager中執行“ Generate Credentials ”步驟(在更高版本中重命名為“ Generate Missing Credentials ”)時發生此錯誤,則可能是由於導入到Cloudera Manager數據庫中的管理員帳户詳細信息不再與主機匹配,例如Cloudera Manager服務器的主機名在上一次導入後隨後更改了。

視頻回放&PPT獲取

  • 視頻回看:

https://www.bilibili.com/video/BV1mD4y1h7ce/?spm_id_from=333.999.0.0

  • 課件獲取:

關注公眾號“ChunJun”,後台私信“課件”獲得直播課件

想了解或諮詢更多有關袋鼠雲大數據產品、行業解決方案、客户案例的朋友,瀏覽袋鼠雲官網:https://www.dtstack.com/?src=szkyzg

同時,歡迎對大數據開源項目有興趣的同學加入「袋鼠雲開源框架釘釘技術qun」,交流最新開源技術信息,qun號碼:30537511,項目地址:https://github.com/DTStack