本文通过访问HDFS服务为您介绍如何兼容MIT Kerberos认证。

前提条件

已创建集群,详情请参见创建集群

通过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节点。

      登录详情请参见使用SSH连接主节点

    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
    说明 当您需要运行YARN作业时,请提前在集群中所有节点添加对应的linux账号,详情请参见RAM认证

通过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版本。