Kerberos身份驗證在ChunJun中的落地實踐
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。
● 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。
04 Kerberos 的認證簡介
參與 Kerberos 認證過程中的角色:
-
訪問服務的 Client;
-
提供服務的 Server;
-
DC是Domain Controller的縮寫,即域控制器;AD是Active Directory的縮寫,即活動目錄。DC中有一個特殊用戶叫做krbtgt,它是一個無法登錄的賬戶,是在創建域時系統自動創建的,在整個Kerberos認證中會多次用到它的Hash值去做驗證。
-
KDC(Key Distribution Center)密鑰分發中心。在KDC中又分為兩個部分:Authentication Service(AS,身份驗證服務)和Ticket Granting Service(TGS)
-
AD會維護一個Account Database(賬戶數據庫), 它存儲了域中所有用戶的密碼Hash和白名單,只有賬戶密碼都在白名單中的Client才能申請到TGT。
05 Kerberos詳細認證流程
1. Client with AS
客戶端(Client)向 AS(Authentication Service)發送請求獲取 TGT(ticket grant ticket)
2. Client with TGS
客戶端(Client)向 TGS(Ticket Granting Service,)發送請求獲取ST(Service Ticke)
客戶端(Client)向服務端(Server)發送認證請求進行認證,如果客戶端(Client)要求進行雙向認證,服務端(Server)額外發送認證請求至客戶端(Client)進行認證。
3.Kerberos 與 JAAS可插拔的認證模塊
JAAS jdk 在1.4引入的一種可插拔的認證模塊( Pluggable Authentication Module,PAM )的安全體系結構,這意味著可以通過改變模塊,支持從一種安全協議組件無縫的切換到另一個協議組件。
同時這種體系架構定義的接口無需修改代碼即可實現加入多種認證技術和授權機制,因為 JAAS API 定義了應用程序代碼與實際驗證邏輯之間的抽象,這個抽象不用重新編譯現有的應用程序代碼就可以作為登錄模塊的運行時替代。
這種實現方式是通過應用程序只調用 LoginContext 接口,而認證技術的實際提供程序則是基于 LoginModule 接口進行開發的,在運行時LoginContext 通過讀取配置文件確定使用哪些認證模塊來對應用程序進行認證。
二、ChunJun任務提交中的Kerberos認證
接下來我們來大家介紹下ChunJun任務提交中的 Kerberos 認證,我們可以參考ChunJun的 readme 文檔中的 yarn session 部分:
https://github.com/DTStack/chunjun/blob/master/README_CH.md
01 Flink 提交流程中的 Kerberos
首先,我們需要啟動一個 yarn session 環境,進入 Flink 的 bin 目錄下執行 yarn-session 腳本啟動 flink session 并使用 -t 參數上傳 ChunJun 的依賴包。
當我們執行 yarn-session 時,腳本內部會調用 java 命令運行 FlinkYarnSessionCli 這個類的 main 方法。在 FlinkYarnSessionCli 的 main 方法中,首先需要安裝一個全過程的安全配置,然后獲得一個安裝后的上下文,并且在上下文中運行 run 方法。
在 run 方法中我們構建了一個 YarnClusterDescripter 對象,這個對象中封裝了 Flink 所依賴的配置文件和 jar 包等。而后再調用YarnClusterDescripter 對象的 DeploySessionClister 方法將任務提交到 yarn 集群。至此完成了 Flink session 到 Yarn 的一個提交。
我們再回顧下整體的提交流程:
● 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
2.SecurityUtils#install 方法中首先通過 installModules 方法對 Flink 內部的安全模組進行了 install(其中包括Hadoop、Jaas、Zookeeper 模組)
3.SecurityUtils#installContext 方法對安全上下文進行初始化(獲得 HadoopSecurityContext,其中包含這 hadoop 的認證憑證 ugi)
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"中配置的值之一相匹配。
04 ChunJun 提交流程中的 Kerberos
執行 ChunJun-Yarn-session.sh 提交任務,ChunJun-Yarn-session.sh 實際上只是對任務的腳本路徑進行了檢查校驗,然后再執行 submit.sh 腳本啟動任務提交進程。
Launcher 的 main 方法中主要對不同的任務執行模式進行區分并交給各個模式具體的任務提交類去提交任務。
YarnSessionClusterClientHelper 將任務的配置以及依賴的 jar 進行組裝獲得 YarnClusterDescriptor 對象。再將任務提交到對應的 Flink session 上。
三、ChunJun Connector 中的Kerberos 認證
接下來為大家介紹 ChunJun Connector 中的 Kerberos 認證 。
01ChunJun 插件中的 Kerberos
以 ChunJun HDFS Connector 為例:
插件在 openInputFormat 方法中會對任務的目標數據源 HDFS 是否開啟了 Kerberos 進行判斷,如果開啟了 Kerberos,則會根據配置的認證文件進行認證并獲取認證后的 ugi,ugi 可以認為是之后插件與 HDFS 通信的用戶憑證,里面保存著用戶的認證信息.
02 如何進行Kerberos 認證
● OpenInputFormat 方法
OpenInputFormat 方法是 Flink 對算子的每個實例進行初始化是都會執行的方法,ChunJun 的BaseRichInputFormat 也實現了該方法,我們開發插件也都會去實現該方法。
對于每個算子實例來說,Kerberos 認證只會進行一次(不包括認證過期后的刷新),因此 Kerberos 認證的代碼應該在該方法中實現.
● 開發 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
- 課件獲?。?/li>
關注公眾號“ChunJun”,后臺私信“課件”獲得直播課件
想了解或咨詢更多有關袋鼠云大數據產品、行業解決方案、客戶案例的朋友,瀏覽袋鼠云官網:https://www.dtstack.com/?src=szkyzg
同時,歡迎對大數據開源項目有興趣的同學加入「袋鼠云開源框架釘釘技術qun」,交流最新開源技術信息,qun號碼:30537511,項目地址:https://github.com/DTStack