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