本文通過訪問HDFS服務為您介紹如何使用HAS Kerberos認證。

前提條件

已創建EMR-3.40及之前版本,EMR-4.10.1及之前版本的Hadoop集群,詳情請參見創建集群

通過hadoop命令訪問HDFS

以test用戶訪問HDFS服務為例介紹。

  1. 在Gateway節點配置krb5.conf文件。
    scp root@emr-header-1:/etc/krb5.conf /etc/
  2. 配置hadoop.security.authentication.use.has的值為false
    1. 登錄集群的emr-header-1節點。
      說明 HA集群也需要登錄emr-header-1節點。

      登錄詳情請參見登錄集群

    2. 執行以下命令,編輯core-site.xml文件。
      vim /etc/ecm/hadoop-conf/core-site.xml
    3. 查看hadoop.security.authentication.use.has的值。
      • 如果值為true,修改hadoop.security.authentication.use.has的值為false
      • 如果值為false,直接執行步驟3
  3. 添加Principal。
    1. 執行如下命令,進入Kerberos的admin工具。
      • EMR-3.30.0及后續版本和EMR-4.5.1及后續版本:
        sh /usr/lib/has-current/bin/admin-local.sh /etc/ecm/has-conf -k /etc/ecm/has-conf/admin.keytab
      • EMR-3.30.0之前版本和EMR-4.5.1之前版本:
        sh /usr/lib/has-current/bin/hadmin-local.sh /etc/ecm/has-conf -k /etc/ecm/has-conf/admin.keytab
    2. 執行如下命令,添加test的Principal。

      本示例密碼設置為123456。

      addprinc -pw 123456 test
    3. 執行如下命令,導出keytab文件。
      ktadd -k /root/test.keytab test
  4. 獲取Ticket。
    在待執行HDFS命令的客戶端機器上執行命令,本文以Gateway節點為例介紹。
    1. 添加Linux賬號test。
      useradd test
    2. 安裝MIT Kerberos客戶端工具。

      您可以使用MITKerberos工具進行相關操作(例如,kinit和klist),詳情請參見MIT Kerberos

      yum install krb5-libs krb5-workstation -y
    3. 切到test賬號執行kinit。
      su test
      • 如果沒有keytab文件,則執行kinit,回車后輸入test的密碼123456。
      • 如果有keytab文件,則執行如下命令。
        #使用指定Keytab文件中的指定Principal進行認證。
        kinit -kt test.keytab test 
        #查看ticket的生命周期。
        klist
        執行klist,回車后輸入test的密碼123456。返回類似如下信息:
        Valid starting       Expires              Service principal
        03/30/2021 10:48:47  03/31/2021 10:48:47  krbtgt/EMR.209749.COM@EMR.209749.COM
                renew until 03/31/2021 10:48:47
    4. 可選:如果需要設置ticket的生命周期,您可以執行如下操作:
      1. 設置ticket的生命周期。
        kinit -l 5d
      2. 執行klist命令,查看ticket的生命周期。
        Valid starting       Expires              Service principal
        03/30/2021 10:50:51  04/04/2021 10:50:51  krbtgt/EMR.209749.COM@EMR.209749.COM
                renew until 04/01/2021 10:50:51
  5. 在Gateway節點上執行以下命令,導入環境變量。
    export HADOOP_CONF_DIR=/etc/has/hadoop-conf
  6. 執行HDFS命令。
    hadoop fs -ls /
    返回如下類似信息。
    Found 6 items
    drwxr-xr-x   - hadoop    hadoop          0 2021-03-29 11:16 /apps
    drwxrwxrwx   - flowagent hadoop          0 2021-03-29 11:18 /emr-flow
    drwxr-x---   - has       hadoop          0 2021-03-29 11:16 /emr-sparksql-udf
    drwxrwxrwt   - hadoop    hadoop          0 2021-03-29 11:17 /spark-history
    drwxr-x---   - hadoop    hadoop          0 2021-03-29 11:16 /tmp
    drwxrwxrwt   - hadoop    hadoop          0 2021-03-29 11:17 /user

通過Java代碼訪問HDFS

  • 使用本地ticket cache
    說明 需要提前執行kinit獲取ticket,且ticket過期后程序會訪問異常。
    public static void main(String[] args) throws IOException {
       Configuration conf = new Configuration();
       //加載hdfs的配置,需要從EMR集群上復制hdfs的配置。
       conf.addResource(new Path("/etc/ecm/hadoop-conf/hdfs-site.xml"));
       conf.addResource(new Path("/etc/ecm/hadoop-conf/core-site.xml"));
       //需要在Linux賬號下,提前通過kinit獲取ticket。
       UserGroupInformation.setConfiguration(conf);
       UserGroupInformation.loginUserFromSubject(null);
       FileSystem fs = FileSystem.get(conf);
       FileStatus[] fsStatus = fs.listStatus(new Path("/"));
       for(int i = 0; i < fsStatus.length; i++){
           System.out.println(fsStatus[i].getPath().toString());
       }
    }
  • 使用keytab文件(推薦)
    說明 keytab長期有效,跟本地ticket無關。
    public static void main(String[] args) throws IOException {
      String keytab = args[0];
      String principal = args[1];
      Configuration conf = new Configuration();
      //加載hdfs的配置,需要從EMR集群上復制hdfs的配置。
      conf.addResource(new Path("/etc/ecm/hadoop-conf/hdfs-site.xml"));
      conf.addResource(new Path("/etc/ecm/hadoop-conf/core-site.xml"));
      //直接使用keytab文件,該文件從EMR集群emr-header-1上執行相關命令獲取。
      UserGroupInformation.setConfiguration(conf);
      UserGroupInformation.loginUserFromKeytab(principal, keytab);
      FileSystem fs = FileSystem.get(conf);
      FileStatus[] fsStatus = fs.listStatus(new Path("/"));
      for(int i = 0; i < fsStatus.length; i++){
          System.out.println(fsStatus[i].getPath().toString());
      }
      }
    pom依賴如下所示。
    <dependencies>
      <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-common</artifactId>
        <version>x.x.x</version>
      </dependency>
      <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-hdfs</artifactId>
        <version>x.x.x</version>
       </dependency>
    </dependencies>
    說明 x.x.x為您集群的hadoop版本。