11.3.2 HDFS

客户端与HDFS之间的通信连接由两部分组成,它们均采用了Kerberos与令牌相结合的方法进行身份认证。

(1)客户端向NameNode发起的RPC连接

由于NameNode存储了系统中所有文件的元数据信息,因此,如果客户端(如Task)需要读写一个文件,首先需要向NameNode发起RPC连接以获取文件所属的数据块列表。为了对客户端进行安全认证,Hadoop采用了Kerberos与授权令牌相结合的认证方法。

(2)客户端向DataNode发起的Block传输连接

为了防止客户端随意从DataNode上读写数据,NameNode收到客户端发送的文件读写请求后,除了为之返回文件对应的Block列表外,还会为每个Block分配一个数据块访问令牌。这样,当客户端从DataNode读写Block时,首先需要出示待读写Block对应的访问令牌,只有通过DataNode验证后,才可以读写该Block。

下面重点介绍授权令牌和数据块访问令牌的身份认证过程。

(1)授权令牌(Delegation Token)

当客户端初始访问NameNode时,需出示Kerberos票据获取NameNode认证。客户端通过认证后将收到一个授权令牌,之后便可以凭借该授权令牌访问NameNode。授权令牌可看作客户端与NameNode之间的共享密钥,当在不安全的链路上进行传输时应该保护好,任何人获取了该密钥都能够伪装成NameNode。另外,需要注意的是,只有通过Kerberos认证才可以获取授权令牌。

考虑到令牌的安全性,每个授权令牌均被赋予一定的有效期。当用户从NameNode上获取到一个授权令牌后,应告诉它谁是令牌的重新申请者。令牌的重新申请者应以自己的身份从NameNode端取得认证进而为用户更新令牌。更新令牌实际上就是延长令牌的NameNode上的有效期。在Hadoop中,所有令牌的重新申请者是JobTracker,它负责更新令牌直到作业运行完成。

认证过程

当一个客户端使用授权令牌向NameNode获取认证时,经过的步骤如下:

步骤1 客户端将TokenID发送给NameNode。其中TokenID定义如下:


TokenID={ownerID, renewerID, issueDate, maxDate, sequenceNumber}


步骤2 NameNodes使用TokenID和masterKey(NameNode和客户端共享masterKey),重新计算TokenAuthenticator和Token。其中TokenAuthenticator的计算方法如下:


TokenAuthenticator=HMAC-SHA1(masterKey, TokenID)


步骤3 NameNode检查新的Token是否合法。一个Token是合法的,当且仅当Token在内存中存在,且当前时间仍在有效期内。其中Token计算方法如下:


DelegationToken={TokenID, TokenAuthenticator}


步骤4 如果Token是合法的,客户端和NameNode分别将TokenAuthenticator作为密钥、DIGEST-MD5作为认证协议进行双方认证。

重新申请令牌

考虑到令牌的安全性,Hadoop为每个授权令牌赋予一定的有效期,当令牌到期后,需指定一个令牌重新申请者。在Hadoop中,JobTracker是授权令牌的重新申请者。当JobTracker为客户端重新申请令牌时,它将旧令牌发送给NameNode, NameNode将检查TokenID中的信息,判断该令牌是否满足以下几个条件:

❑JobTracker为该令牌的重新申请者;

❑TokenAuthenticator正确;

❑当前时间currentTime小于最长有效期maxDate。

如果验证成功,则NameNode会延长该令牌的有效期。设延长时间为renewPeriod,则新的有效期为max{currentTime+renewPeriod, maxDate}。如果该Token不在内存中,说明NameNode可能因刚刚启动丢失了之前内存中所有的Token,则NameNode会将该Token重新添加到内存中。

NameNode会定期更新masterKey并保存到磁盘上,而Token则仅保存在内存中。

(2)数据块访问令牌(Data Block Access Token)

在原始Hadoop中,DataNode上没有任何针对Data Block的访问权限控制,这使得任何用户只要能够提供一个合法的Block ID便可以直接从DataNode上读取Data Block,用户也可以向DataNode上写入任意的Data Block。这主要是HDFS缺乏相关的安全机制造成的。当用户需要读取某个文件时,首先将请求发送给NameNode, NameNode检查该用户是否有该文件访问权限,如果有,则将该文件对应的Block元信息发送给用户,这样,用户再依次从对应的TaskTracker上读取所有Block便获取整个文件内容。由于DataNode上没有任何文件或者文件访问权限相关的概念,因此它不会对客户端的Block访问请求进行任何验证。

为了提供安全的数据读写机制,HDFS增加了基于块访问令牌的安全认证机制。块访问令牌由NameNode生成,并在DataNode端进行合法性验证。一个典型的应用场景如下:一个客户端向NameNode发送文件读请求,NameNode验证该用户具有文件读权限后,将文件对应的所有数据块的ID、位置以及数据块访问令牌发送给客户端;当客户端需要读取某个数据块时,将数据块ID和数据块访问令牌发送给对应的DataNode。由于NameNode已经通过心跳将密钥发送给各个DataNode,因此DataNode可以对数据块进行安全验证,而只有通过安全验证的访问请求才可以获取数据块。

客户端可以缓存来自NameNode的数据块访问令牌,且仅当令牌失效或令牌不存在时才从NameNode端重新获取。