• Spark与hdfs delegation token过期的排查思路总结


    背景

    hadoop delegation token的问题相对比较混乱和复杂,简单说下这东西的出现背景,最早的hadoop的因没有的完善的安全机制(安全机制主要包括:认证 + 鉴权,hadoop这里主要是身份认证机制没有),所以导致操作风险比较大,你可以理解只要获取了一台装有hadoop client的机器,就可以任意操作HDFS系统了,深究原因是因为hadoop身份认证机制太薄弱,所以只要黑了一台机器就可以发起各种危险操作了,所以各方大佬们云集讨论了一个可靠的安全方案,最终在SSL协议和Kerberos协议中,选择了Kerberos,主要有两个原因:

    1,性能。因为SSL数据传输中包含非对称加密算法,相对耗时比较大,而Kerberos则完全采用对称加密

    2,易于维护管理。Kerberos里面如果撤销一个客户端的访问权,直接在KDC(key distribution center)秘钥分发中心删除掉这个用户即可,而SSL里面,则需要生成一个证书吊销列表然后分发到所有的服务器中,对比而言Kerberos的集中式管理更方便维护

    Kerberos介绍

    Kerberos一些术语:

    • KDC:密钥分发巾心,负责管理发放票据,记录授权。
    • Realm: Kerberos管理领域的标识。
    • principalKerberos 下的用户可以称为 Principal,当每添加一个用户或服务的时候都需要向kdc添加一条principal, principal的形式为:主名称/实例名@领域名
    • 主名称:主名称可以是用户名或服务名,表示是用于提供各种网络服务(如hdfs、yam,、hive) 的主体。
    • 实例名:实例名简单理解为主机名。
    • keytab文件:存储了用户的加密密码。常用这种方式认证。

    使用Kerberos协议后,一次客户端访问服务端的认证流程如下:

    Kerberos的架构和工作原理

    • AS_REQ 是在初始化一个用户(kinit)的时候发出的用户认证请求,这个请求是发给KDC中的Authentication Server (AS);
    • AS_REP 是 AS回复给client的信息,其中包括TGT (用TGS secret key加密过的) and the session key (用发请求的用户的secret key加密过的);
    • TGS_REQ 是client为了一个service ticket向Ticket Granting Server (TGS)的信息. 其中包括上一条信息中获得的TGT (用TGS secret key加密过的) ,一个客户端产生的一个authenticator(用session key加密过的).
    • TGS_REP 是TGS回复给TGS_REQ的信息. 其中包括service ticket(用appservice的secret key加密过),和 一个TGS产生的service sessinon key(之前AS产生的一条session key给加密过的)
    • AP_REQ 是一条客户端发给appserver的访问服务的请求,其中包括service ticket和一个authenticator(使用TGS产生的service session key 加密过的)
    • AP_REP 是appserver回复给client的一条信息,证明这个appserver确实是客户端希望访问的server。不过这条信息也不一定总是要回复的。比如当客户端和appserver需要相互认证的时候,客户端向appserver发出请求,这个时候就不需要回复信息。

    Delegation Token介绍

    Delegation Token(委托令牌,缩写DT),前面我们知道了Kerberos的工作原理,那么Hadoop的 Delegation Token又是怎么来的?

    虽然理论上可以单独使用 Kerberos 进行身份验证,但在 Hadoop 等分布式系统中使用时,它有一些弊端。想象一下,对于每个 MapReduce 作业,如果所有YARN的NodeManager节点或者Spark的Executor节点,都必须使用委托的 TGT(Ticket Granting Ticket)通过 Kerberos 进行身份验证,那么 Kerberos 密钥分发中心 (KDC) 将很快成为瓶颈。一次大的Job作业可能有数千个节点到节点的通信,这样就会导致放大对KDC中心的请求服务。事实上,它会无意中在非常大的集群中对 KDC 执行分布式拒绝服务攻击。

    因此,Hadoop Delegation Token委托令牌作为一种轻量级身份验证方法被引入,以补充 Kerberos 身份验证。 Kerberos 是一个三方协议;相反,Delegation Token 身份验证是一种两方身份验证协议。

    DT的工作原理如下:

    1,客户端最初使用kinit或者keytab文件,完成与 Kerberos 的身份验证,并拿到TGT,然后通过TGT到TGS获取到HDFS服务的票证之后,再拿着Ticket从Name Node服务中获取委托令牌

    2,客户端使用DT委派令牌与YARN进行通信和提交任务进行后续身份验证,整个过程不再使用 Kerberos

    更详细的图示如下:

    YARN Long Running应用的问题

    看起来一切很美好,但这里面有个最大的问题是KDC颁发的票据是有最大生命周期的默认是7天,然后在7天内,每隔24颁发的票据就会失效,如果票据过期了,可以通过程序renew token来续约,这个时间一般是在过期前就会完成,准确来说是24*0.75=18个小时。

    那么当票据的最大时间到了之后,会发生什么情况呢?很简单服务直接挂掉,因为token过期失效了,也就是我们经常遇到的两种异常情况:

    1,Token is expired

    2,Token can’t be found in cache

    其实都是一个意思,只不过根据失效的时间长短抛出来的有所不同

    默认的7天,对于普通离线Job基本绰绰有余了,但对于实时应用,如flink,spark流等的程序,可能就会失败,所以这里的问题又改怎么解决呢。

    Hadoop YARN的官方文档给出了四种主流策略:

    一,使用本地文件系统存储keytab文件

    为应用程序在每个节点上的使用提供了一个keytab文件,将其安装在每个集群节点的本地文件系统中。

    在配置选项中提供此路径,一般是环境变量注入。应用程序通过 UserGroupInformation.loginUserFromKeytab() 加载凭据。密钥表必须位于安全目录路径中,只有服务(和其他受信任的帐户)可以读取它。这实际上是所有静态 Hadoop 应用程序获取其安全凭证的方式

    二,使用HDFS文件系统存储keytab文件

    将keytab文件密钥表被上传到 HDFS。启动 AM 时,keytab 被列为本地化到 AM 容器的资源。

    Application Master 配置了 keytab 的相对路径,并使用 UserGroupInformation.loginUserFromKeytab() 登录。

    当 AM 启动容器时,它会将指向 keytab 的 HDFS 路径列为要本地化的资源。它将 HDFS 委托令牌添加到容器启动上下文中,以便可以本地化 keytab 和其他应用程序文件。

    启动的容器必须自己通过 UserGroupInformation.loginUserFromKeytab() 登录。 UGI 处理登录,并安排一个后台线程定期重新登录用户。

    令牌创建在 Hadoop IPC 和 REST API 中自动处理,容器在整个持续时间内通过 kerberos 保持登录状态。

    这避免了为整个集群中的特定服务安装 keytab 的管理任务。它确实要求客户端有权访问密钥表,并且当它上传到分布式文件系统时,必须通过适当的路径权限/ACL 来保护它。

    由于所有容器都可以访问密钥表,因此必须信任在容器中执行的所有代码。恶意代码(或逃避某种形式的沙箱的代码)可以读取密钥表,因此可以访问集群,直到密钥过期或被撤销。

    三,使用HDFS存储keytab,通过AM生成token和续约token,并通过RPC分发给所有的Executor节点

    1,client把keytab上传到HDFS

    2,当启动AM的时候,会把这个keytab文件下载到AM运行的container里面

    3,Application Master 配置了 keytab 的相对路径,并使用 UserGroupInformation.loginUserFromKeytab() 登录。 UGI 代码路径仍将通过 $HADOOP_TOKEN_FILE_LOCATION 自动加载文件引用,这是获取 AMRM 令牌的方式

    4,当 AM 启动一个容器时,它会获取该容器所需的所有委托令牌,并将它们添加到容器的容器启动上下文中,典型的就是AM提交YARN任务时,会把token添加到上下文中,发送给RM,当RM启动NM时,又会把token下发到各个NM中

    5,启动的容器必须从 $HADOOP_TOKEN_FILE_LOCATION 加载委托令牌,并使用它们(包括续订),直到它们无法再续订

    6,AM和Executor 必须实现一个 IPC 接口,该接口允许接受请求一组新的委托令牌;

    7,在委托令牌到期之前,client也就是driver进程会重新new新的token,然后通过 IPC 通道发送给AM和Execuor,从而确保他们能够长时间运行

    这就是 Apache Spark 1.5+ 以后使用的策略,在容器和 AM 之间使用基于自定义的RPC网络的协议(最早是akka,目前已经重写)进行令牌更新

    四,使用本地文件系统存储keytab,在机器上定时kinit认证

    这种方式比较简单,与应用程序解耦,需要一个crontab定时任务,在token续约到期之前,自动执行kinit即可,唯一需要注意的就是,如果集群扩容什么的,新加的机器要确保也执行了,否则任务运行在这上面就会失败

    上面几种策略,我们可以根据实际情况选择合适的一种来操作,从而避免让我们的实时应用只能跑7天

    hadoop配置中和token相关的配置参数:

    dfs.namenode.delegation.token.max-lifetime = 604800000 ms (7天)
    dfs.namenode.delegation.key.update-interval = 86400000 ms  (1天)
    dfs.namenode.delegation.token.renew-interval = 86400000 ms (1天)

    在测试验证时,可以修改短点来验证,比如10,,3,3

    Spark的Token过期问题

    从前面的介绍中,我们现在应该大致了解了整个委托token的相关知识,但在实际使用过程中,仍然会遇到各种问题,因为像大数据系统涉及组件多,出一个问题说实话不太容易定位或者容易把排查方向搞偏,这里总结一下排查这种问题的经验,我总结为4个层面:

    1,kerberbos层面

    这个层面一般不容易遇到问题,但是如果要支持多个开启了Kerberos认证的hadoop集群之间互相访问数据,大概率会遇到访问失败问题,因为这种情况是需要打通两边kerberos的,当然好消息是kerberos是支持的,只需要我们配置正确即可

    2,hadoop层面

    Hadoop层面是最容易出现问题的,因为现在hadoop有很多个版本,建议新集群大家直接用hadoop 2.8+以上的版本,基本不会在遇到token问题,但在这个版本之前比如2.7和2.6都有各种各样的bug存在,需要我们打patch才能解决,详情可参考HDFS 9276的ISSUE

    3,spark层面

    spark层面其实还好,不容易出现这种问题,因为Spark使用的人多,社区也比较活跃,所以spark在1.5版本的时候都设计了可以解决实时应用长时间跑在yarn上的问题。当然也不要心存侥幸,有两个地方也会出问题:

    spark编译的时候依赖了低于hadoop 2.8的版本,那么长时间运行的应用大概率也会遇到token过期的问题,所以编译时候要注意,另外就算依赖高于hadoop 2.8的版本,spark自身的代码也会存在bug从而引发token问题,我们就遇到了:

    第一个是renew schdule的时长是一个long的最大值,这样会导致driver永远不会更新token,解决方法:把hadoop-hdfs-2.8.5的jar拷贝到spark的jars目录就行了,因为缺失一个SPI的描述文件导致的。

    第二个是spark3.0.1版本独有的bug,driver生成的token无法传给AM,从而导致在token超过7天之后,AM新生成的Executor都会失败。解决方法:参考SPARK-32905

    这里推荐两个稳定版本:spark 2.4.3 和 spark 3.0.2,有条件直接上最新的更好。

    4,应用层面

    这个主要指的是,如果你的应用是通过shade的fat jar提交运行的,那么很有可能你的shade jar里面包含了一些hadoop或者spark版本不一致的代码,从而可能会引发类冲突或者加载顺序的问题,导致命中某个bug,所以这里建议大家服务端提供了依赖,fat jar就不要再打进去了,减少这种问题发生的几率。

    总结

    本篇介绍的内容,都是我们在生产环境遇到的一些问题,当然我们现在主要用的是spark,所以介绍的spark的内容会多一点,如果你正在使用的是flink,也不要紧,解决问题的思路都是是相通的,也可以按照文中的思路在遇到token过期问题时来进行排查,大数据组件因为复杂和繁多,当组合到一起时经常会遇到一些问题,这个时候我们也不要着急,多用谷歌搜索+善用组件的官网ISSUE文档,如果实在还没迹可循,那只能看源码细细捋了,可以造一个测试环境,方便排查,这样可以验证我们的各种想法,也会大大提升我们排查问题的效率。

    参考文章:

    Kerberos认证原理与环境部署 - 大数据老司机 - 博客园

    Hadoop Delegation Tokens Explained - Cloudera Blog

    https://issues.apache.org/jira/secure/attachment/12428537/security-design.pdf

    https://www.slideshare.net/oom65/hadoop-security-architecture

    [HADOOP-4487] Security features for Hadoop - ASF JIRA

    [HDFS-9276] Failed to Update HDFS Delegation Token for long running application in HA mode - ASF JIRA

    [SPARK-32905] ApplicationMaster fails to receive UpdateDelegationTokens message - ASF JIRA

    Apache Hadoop 3.3.4 – YARN Application Security

    https://github.com/apache/spark/blob/master/core/src/main/scala/org/apache/spark/deploy/security/README.md

  • 相关阅读:
    Java Integer.toOctalString()具有什么功能呢?
    JAVA 浏览器下载excel,自定义样式:合并单元格,设置多种背景填充颜色,冻结窗格
    为什么我推荐你使用 systemd timer 替代 cronjob?
    前端(十六)——Web应用的安全性研究
    一览8个 NFT 分析平台
    OpenCV 笔记(3):基本图形的绘制
    Android学习笔记 14. GridLayout 网格布局
    【初中生讲机器学习】12. 似然函数和极大似然估计:原理、应用与代码实现
    springboot整合rabbitmq入门(三)
    DevOps-4:Jenkins配置.Net项目模板Job
  • 原文地址:https://blog.csdn.net/u010454030/article/details/127780331