功能
開啟了 Kerberos認證的安全模式集群,進行應用開發時需要進行安全認證。
Kerberos這一名詞來源于希臘神話“三個頭的狗——地獄之門守護者”,后來沿用作為安全認證的概念,使用Kerberos的系統在設計上采用“客戶端/服務器”結構與AES等加密技術,并且能夠進行相互認證(即客戶端和服務器端均可對對方進行身份認證)。可以用于防止竊聽、防止replay攻擊、保護數據完整性等場合,是一種應用對稱密鑰體制進行密鑰管理的系統。
結構
Kerberos的原理架構如下圖所示,各模塊的說明如下圖所示。
原理架構


模塊說明
| 模塊 | 說明 | 
|---|---|
| Application Client | 應用客戶端,通常是需要提交任務(或者作業)的應用程序。 | 
| Application Server | 應用服務端,通常是應用客戶端需要訪問的應用程序。 | 
| Kerberos | 提供安全認證的服務。 | 
| KerberosAdmin | 提供認證用戶管理的進程。 | 
| KerberosServer | 提供認證票據分發的進程。 | 
步驟原理說明:
應用客戶端(Application Client)可以是集群內某個服務,也可以是客戶二次開發的一個應用程序,應用程序可以向應用服務提交任務或者作業。
- 應用程序在提交任務或者作業前,需要向Kerberos服務申請TGT(Ticket-Granting Ticket),用于建立和Kerberos服務器的安全會話。
- Kerberos服務在收到TGT請求后,會解析其中的參數來生成對應的TGT,使用客戶端指定的用戶名的密鑰進行加密響應消息。
- 應用客戶端收到TGT響應消息后,解析獲取TGT,此時,再由應用客戶端(通常是rpc底層)向Kerberos服務獲取應用服務端的ST(Server Ticket)。
- Kerberos服務在收到ST請求后,校驗其中的TGT合法后,生成對應的應用服務的ST,再使用應用服務密鑰將響應消息進行加密處理。
- 應用客戶端收到ST響應消息后,將ST打包到發給應用服務的消息里面傳輸給對應的應用服務端(Application Server)。
- 應用服務端收到請求后,使用本端應用服務對應的密鑰解析其中的ST,并校驗成功后,本次請求合法通過。
基本概念
以下為常見的基本概念,可以幫助用戶減少學習Kerberos框架所花費的時間,有助于更好的理解Kerberos業務。以HDFS安全認證為例:
TGT
票據授權票據(Ticket-Granting Ticket),由Kerberos服務生成,提供給應用程序與Kerberos服務器建立認證安全會話,該票據的默認有效期為24小時,24小時后該票據自動過期。
TGT申請方式(以HDFS為例):
- 通過HDFS提供的接口獲取。
/** 
  * login Kerberos to get TGT, if the cluster is in security mode 
  * @throws IOException if login is failed 
  */ 
  private void login() throws IOException {  
  // not security mode, just return 
    if (! "kerberos".equalsIgnoreCase(conf.get("hadoop.security.authentication"))) { 
        return; 
    } 
   
    //security mode 
    System.setProperty("java.security.krb5.conf", PATH_TO_KRB5_CONF); 
   
    UserGroupInformation.setConfiguration(conf); 
    UserGroupInformation.loginUserFromKeytab(PRNCIPAL_NAME, PATH_TO_KEYTAB);   
  }
- 通過客戶端shell命令以kinit方式獲取。
ST
服務票據(Server Ticket),由Kerberos服務生成,提供給應用程序與應用服務建立安全會話,該票據一次性有效。
ST的生成在FusionInsight產品中,基于hadoop-rpc通信,由rpc底層自動向Kerberos服務端提交請求,由Kerberos服務端生成。
認證代碼實例講解
package com.xxx.bigdata.hdfs.examples; 
 
import java.io.IOException; 
 
import org.apache.hadoop.conf.Configuration; 
import org.apache.hadoop.fs.FileStatus; 
import org.apache.hadoop.fs.FileSystem; 
import org.apache.hadoop.fs.Path; 
import org.apache.hadoop.security.UserGroupInformation; 
 
public class KerberosTest { 
    private static String PATH_TO_HDFS_SITE_XML = KerberosTest.class.getClassLoader().getResource("hdfs-site.xml") 
            .getPath(); 
    private static String PATH_TO_CORE_SITE_XML = KerberosTest.class.getClassLoader().getResource("core-site.xml") 
            .getPath(); 
    private static String PATH_TO_KEYTAB = KerberosTest.class.getClassLoader().getResource("user.keytab").getPath(); 
    private static String PATH_TO_KRB5_CONF = KerberosTest.class.getClassLoader().getResource("krb5.conf").getPath(); 
    private static String PRNCIPAL_NAME = "develop"; 
    private FileSystem fs; 
    private Configuration conf; 
   
    /** 
     * initialize Configuration 
     */ 
    private void initConf() { 
        conf = new Configuration(); 
   
        // add configuration files 
        conf.addResource(new Path(PATH_TO_HDFS_SITE_XML)); 
        conf.addResource(new Path(PATH_TO_CORE_SITE_XML)); 
    } 
   
    /** 
     * login Kerberos to get TGT, if the cluster is in security mode 
     * @throws IOException if login is failed 
     */ 
    private void login() throws IOException {  
        // not security mode, just return 
        if (! "kerberos".equalsIgnoreCase(conf.get("hadoop.security.authentication"))) { 
            return; 
        } 
   
        //security mode 
        System.setProperty("java.security.krb5.conf", PATH_TO_KRB5_CONF); 
   
        UserGroupInformation.setConfiguration(conf); 
        UserGroupInformation.loginUserFromKeytab(PRNCIPAL_NAME, PATH_TO_KEYTAB);   
    } 
   
    /** 
     * initialize FileSystem, and get ST from Kerberos 
     * @throws IOException 
     */ 
    private void initFileSystem() throws IOException { 
        fs = FileSystem.get(conf); 
    } 
   
    /** 
     * An example to access the HDFS 
     * @throws IOException 
     */ 
    private void doSth() throws IOException { 
        Path path = new Path("/tmp"); 
        FileStatus fStatus = fs.getFileStatus(path); 
        System.out.println("Status of " + path + " is " + fStatus); 
        //other thing 
    } 
 
 
    public static void main(String[] args) throws Exception { 
        KerberosTest test = new KerberosTest(); 
        test.initConf(); 
        test.login(); 
        test.initFileSystem(); 
        test.doSth();  
    } 
}
說明
Kerberos認證時需要配置Kerberos認證所需要的文件參數,主要包含keytab路徑,Kerberos認證的用戶名稱,Kerberos認證所需要的客戶端配置krb5.conf文件。
方法login()為調用hadoop的接口執行Kerberos認證,生成TGT票據。
方法doSth()調用hadoop的接口訪問文件系統,此時底層RPC會自動攜帶TGT去Kerberos認證,生成ST票據。
