Skip to main content

使用 Kerberos

Ranger 与 Kerberos 都是 Hadoop 下与数据安全密不可分的组件,简而言之,Ranger 提供了创建“哪些用户能够访问哪些文件”的安全规则的能力,而 Kerberos 则解决了用户认证的问题。二者可以搭配使用以获得最佳的数据安全性,也可以单独启用来满足特定的使用需要。

Kerberos 简介

Kerberos 是 Hadoop 生态广泛支持的一种用户认证协议。在未开启 Kerberos 认证时,Hadoop 的 文件系统客户端无法验证当前访问用户的真实性,可以简单通过 HADOOP_USER_NAME 环境变量设置用户访问的用户名,甚至可以是 superuser,这会带来一定的安全问题。可以参考 Hadoop in Secure Mode 启用 Kerberos,如此一来,访问文件系统的用户就必须是通过 Kerberos 协议认证的,保证了真实性。

Kerberos 旨在通过使用密钥加密技术为 Client/Server 应用程序提供强身份验证。互联网是不安全的,如果密码通过网络传输,很容易被劫取。因此可以通过 Kerberos 协议实现一个安全的单点登录服务(SSO),整个过程密码均没有通过网络传输。

用下图大概介绍一下认证流程,图中 KDC 即为 Kerberos 的核心组件 Key Distribution Center:

Kerberos-auth-workflow

Client 和 Server 均是 KDC 里的一个用户(Principal),需要提前在 KDC 里面添加。

大概流程:

  • Client 通过自己的 Principal 和 keytab(password)登录 KDC 里面的 AS,AS 会返回一张临时票据(TGT),此 TGT 会有过期信息;
  • Client 通过上一步获得的临时票据(TGT)向 KDC 的 TGS 请求需要访问的 Server Principal 的临时票据(ST);
  • Client 通过上一部获得的临时票据(ST)向 Server 发起请求。Server 端使用自己的 keytab 可以验证 Client Principal 发来的请求。

整个过程只有第一步涉及到用户密码。但其实密码并没有通过网络发送:AS 返回的 TGT 里含有加密内容,只有当 Client 顺利解密,才视为登录成功。TGS 和 Server 会根据 Client 端从 KDC 获得的 TGT 和 ST 验证 Client 的真实性,同时,Server 端并不需要和 KDC 直接通信。

JuiceFS 中的 Kerberos

相比于直接信任 Client 输入的用户名,当 JuiceFS 元数据服务打开 Kerberos 认证后,Client 在访问元数据服务前需要先通过 Kerberos 认证。JuiceFS Client 和元数据服务各自有其 Principal 对应的 keytab 文件。

流程如下:

jfs-Kerberos-workflow

  1. 客户端通过 kinit 或者 keytab 文件从 KDC 获得 TGT,然后在用此 TGT 向 KDC 申请需要访问的 JuiceFS 元数据服务 principal 对应的 ST;
  2. 客户端通过 ST 向 JuiceFS 元数据服务发起验证请求,JuiceFS 元数据服务根据自己的 principal 对应的 keytab 即可验证客户端的身份。

从上图可以看到,JuiceFS 的 Kerberos 身份认证只涉及 Client 和元数据服务之间的认证。Client 和对象存储之间不涉及 Kerberos 身份认证。

在通过 Kerberos 认证的过程中,TGT 是可以缓存在本地的,但是用来通过元数据服务认证的 ST 却无法缓存,也就是 client 每次初始化都需要向 KDC 发起请求。

在 YARN 任务中,通常会同时启动大量的进程访问 JuiceFS。如果每个 Client 都需要向 KDC 请求对应 JuiceFS 元数据服务的 ST,将会给 KDC 带来极大压力。为了解决这个问题,JuiceFS 参考 Hadoop Delegation Token 实现了 DelegationToken 验证。

DelegationToken 流程如下:

Kerberos-delegation-token

  1. Submit client 首先需要通过 Kerberos 认证和 JuiceFS 元数据服务建立连接;
  2. 建立连接后,计算框架(MR、Spark 等)会调用 FileSystem.getDelegationToken() 方法从 JuiceFS 元数据服务申请 DelegationToken;
  3. 计算框架会把 DelegationToken 一并发送到 YARN ResourceManager,ResourceManager 会负责这些 token 的生命周期管理(如 renew、cancel);
  4. 具体任务节点启动后,YARN ResourceManager 会把 DelegationToken 发送给 task client; Task client 通过 DelegationToken 进行身份认证。

DelegationToken 是临时的,ResourceManager 会维护 ApplicationId 和其对应的 DelegationToken 并定期更新。DelegationToken 生命周期管理由 org.apache.Hadoop.yarn.server.resourcemanager.security.DelegationTokenRenewer 负责。

每个 token 都会有一个最大生命周期(maxDate),默认 7 天。如果程序运行时间大于 7 天,需要设置参数 yarn.resourcemanager.proxy-user-privileges.enabled=true,这样在到期前,DelegationTokenRenewer 会通过代理用户机制重新为任务用户重新申请一个新的 DelegationToken。

开启 Kerberos 支持

JuiceFS>=4.8 的 Hadoop SDK 支持使用 Kerberos 做用户认证。

  1. 准备工作

    1. 如果没有安装 Kerberos,需要先安装 KDC

    2. 为 JuiceFS 创建 meta.keytab 文件,将 VOL_NAME 需要替换为创建的 JuiceFS 文件系统名:

      kadmin.local -q "addprinc -randkey meta/{VOL_NAME}"
      kadmin.local -q "ktadd -norandkey -k meta.keytab meta/{VOL_NAME}"
  2. 在 JuiceFS 控制台开启 Kerberos 支持

    1. 在文件系统的设置页面打开 Kerberos 支持,并上传之前步骤创建的 meta.keytab 文件

      Kerberos

    2. Superuser 和 Supergroup

      当开启 Kerberos 支持后,superuser 和 supergroup 可以通过控制台设置。当设置后,控制台的值将会覆盖客户端 juicefs.superuserjuicefs.supergroup 设置的参数。

    3. 可选:代理用户

      JuiceFS 也支持代理用户功能,请参考 HDFS Proxy User。当需要使用代理用户功能时,请添加代理用户规则。

  3. SDK 客户端配置

    修改 core-site.xml,添加如下配置

    <property>
    <name>hadoop.security.authentication</name>
    <value>kerberos</value>
    </property>
    <property>
    <name>juicefs.server-principal</name>
    <value>meta/_HOST</value>
    <description>
    如果使用 _HOST 通配符,会被动态替换为访问的 JuiceFS 文件系统的名字,
    也可以使用 meta/{VOL_NAME}, 指定具体的文件系统
    </description>
    </property>
  4. 验证使用

    • Hadoop shell

      # 通过 kinit 登录
      kinit {your-client-principal}
      # 验证 JuiceFS 正常运行
      hadoop fs -ls jfs://{VOL_NAME}/
      # 退出
      kdestroy
      # 退出以后,访问文件会报错:kerberos credential is needed
      hadoop fs -ls jfs://{VOL_NAME}/
    • Spark

      Spark 提交任务需增加以下配置:

      --conf spark.yarn.access.hadoopFileSystems

客户端默认使用 /etc/krb5.conf 配置文件访问 KDC,如果 KDC 配置默认不在此位置,可以在 Java 启动参数里面添加 -Djava.security.krb5.conf=/path/to/conf 修改。