Hadoop安全机制探究

一、可能的安全问题

1、如果Hadoop服务不对用户或者服务进行认证,那么可能发生什么安全问题?

HDFS文件权限检查被规避
攻击者可以伪装服务,对集群进行攻击

2、因为只需要BlockId即可读取节点的数据,而DataNode不强制对任何访问请求做访问控制。那么,任何人都可以随意的访问和读写HDFS数据,这样就存在安全隐患。

二、Apache Hadoop安全团队使用的安全机制

基于Kerberos的安全机制,而不是SSL

原因:
1、Kerberos 使用对称秘钥操作,比使用公钥操作的SSL快几个量级,可以获得更好的性能。
2、通过使用集中化管理的Kerberos KDC(key distribution center)使得用户管理更简单。例如对一个用户进行销户,只需在KDC中删除该用户即可。而SSL需要生成一个吊销证书,并将其广播到所有服务器上去。

三、RPC连接时的认证体现

在Hadoop中客户端需要通过RPC来连接服务。对于已认证的集群,连接RPC需要使用SASL(Sample Authentication And Security Layer)。并且SASL需要协商子协议,Hadoop支持Kerberos(通过GSSAPI)和DIGEST-MD5认证协议。

除了NameNode服务之外,绝大多数Hadoop服务只支持Kerberos认证。

Kerberos机制:用户获取服务的Ticket并使用SASL/GSSAPI进行认证。
DIGEST-MD5机制:客户端和服务端共享一个秘钥,来相互认证(意味着往返)。这比Kerberos代价要小一些,因为不需要第三部分(例如KDC)的参与。

每当应用创建RPC连接的时候,要么使用token(如果token是可用的),要么使用Kerberos ticket进行认证。在通过RPC连接服务的过程中,客户端会加载ticket缓存中的Kerberos tickets用于Kerberos认证。MapReduce这样的服务也会创建token缓存,供task加载,用于连接TaskTracker获取数据、状态等。

四、Hadoop具体安全机制的体现

1、HDFS安全机制

客户端和HDFS服务之间的通信体现在两个方面,一个是客户端和NameNode之间建立连接。另一个是客户端和DataNode之间的块传输。

建立连接可以通过Kerberos也可以通过delegation token。后者在client和NameNode之间共享秘钥,这可以使得后续的已认证过的访问无需使用Kerberos Key Servers,但是为了获得一个delegation token,client和NameNode之间必须使用一个已认证的Kerberos连接。

另一方面,块传输是通过block access token来认证的,block access token由NameNode产生,并且每个块都有对应的block access token。

1)、delegation token和Kerberos ticket比较

如果要使用Kerberos认证,必须要从KDC获得delegated TGT (ticket granting ticket),这也就是上边提到的第三方的参与。也就是说,你们需要到我这个KDC服务器来取“入场券”。或者是delegated service ticket,这个在使用上和delegation token有点相似,它也不需要在线连接KDC。但是Java GSS-API不支持service ticket delegation。这里可以看出一点,如果有大量的任务(MapReduce任务)的话,连接KDC获取ticket就可能成为一个瓶颈。这点上delegation token就能获得一些性能优势。

一个问题在于,如果使用Kerberos认证,ticket必须被委托,如果更新凭证,必须在凭证过期之前进行,这对时间的把握有严格的限制,另外在更新凭证期间,新的TGT或者service ticket又会产生。而delegation token不一样,delegation token的更新只需更新其有效期,而token本身无需重新生成。并且,可以在已过当前有效期之后更新delegation token也没有关系(但是需要在最大生命期内),因为只有指定的更新者才能更新delegation token,所以这不会造成安全隐患。

再者,Kerberos凭证可用于访问除了HDFS之外的其他服务,相比于用于访问HDFS专用的delegation token,在凭证泄漏时的损害肯定更小。

最后,就兼容性来讲,delegation token能与其他非Kerberos的认证机制如SSL组合使用。

2)、Hadoop访问block的安全保证

在Client访问block时,先询问NameNode块的位置,NameNode会根据访问权限,生成对应的block access token一同返回给客户端,客户端携带该信息访问DataNode上的block,DataNode对该token进行鉴别。

Delegation Token

获取时间:用户在使用Kerberos向NameNode进行初始认证之后。注:只有使用Kerberos认证才能获得新的Delegation Token。
Token实质:用户和NameNode之间的共享秘钥。
Token更新:更新NameNode上token的有效期。一开始在向NameNode获取到token的时候,需要告诉NameNode这个token的更新者,比如说是JobTracker。同一Job的所有task均使用该token。

下边看看Delegation Token的设计实现

设计实现:

以下为Delegation Token的格式

TokenID = {ownerID, renewerID, issueDate, maxDate, sequenceNumber}
TokenAuthenticator = HMAC-SHA1(masterKey, TokenID)
Delegation Token = {TokenID, TokenAuthenticator}

masterKey由NameNode随机生成。NameNode将存活Token保存在内存中,并为每个token维护一个过期时间,如果该token过期,就会从内存中删除,并且过期后客户端用该token进行的访问请求均会被拒绝。sequenceNumber是一个全局的计数器,每生成一个delegation token,该值就会自增,以此确保token的唯一性。

重点看使用Delegation Token的认证过程:

客户端发送TokenID给NameNode,NameNode使用masterKey和TokenID计算TokenAuthenticator和Token。然后判断token是否有效(token在内存中并且未过期)。如果有效,二者使用各自的TokenAuthenticator为私钥并使用DIGEST-MD5作为协议进行相互认证。

Token更新过程:

更新的目的是使token保持有效。token在生成时,会指定其更新者,也就是TokenID中的renewerID。

更新时,更新者要先向NameNode进行认证,NameNode判断该renewer是否为该token的更新者,再判断TokenAuthenticator是否正确,然后看是否过期。检查都OK,那么NameNode更新该token的有效期。如果该token不在内存中,则表示NameNode重启了,丢失了所有的token,NameNode会将该token放入内存。

当然,通过更新token操作也可以使得一个过期的或者是被取消的token复活。上一段提到NameNode重启后内存中的token信息丢失的情况。也就是说NameNode不会分辨token是过期了还是被取消了或是丢失了。当renewer发送更新token的请求到NameNode后,新的token信息会被设置到内存中。

需要注意的是,每个token的renewer是确定的,所以即使是攻击者盗取了token,也无法更新或者复活该token。另外一点是,NameNode需要将masterKey定期更新并持久化到磁盘,而不用持久化token(这在上边的认证过程中可以体现,认证过程需要重计算)。

3)、然后看Block Access Token的设计实现

出于什么目的呢?DataNode没有文件的概念,更不用说文件权限了。所以DataNode不会对block的读写请求做任何防御性的判断。Block Access Token的出现就是为了在对DataNode的块访问时也进行认证以保证安全。

设计实现-对称秘钥方案

NameNode和DataNode都保存一个共享秘钥。NameNode在生成token之后,利用私钥计算一个键哈希(称作消息认证代码 MAC),然后这个值被当做token authenticator,会作为token的一部分。Client连接DataNode进行块操作时,会将Block Access Token一起发到DataNode,DataNode收到token之后,利用自身的秘钥也计算出一个authenticator,如果和token中的authenticator一致,那么认证通过。

token中包含ownerID,该token也只有其所有者才可以使用,其所有者会认证为该token的所有者,这在NameNode生成token时便已确定。

Block Access Token的一些特性

轻量级并且存活时间短,无需更新和撤销,过期重新生成即可,也不用持久化。HDFS客户端会缓存从NameNode获取的block access token,当访问未缓存的block或者token过期时,才从NameNode重新获取token。

格式

TokenID = {expirationDate, keyID, ownerID, blockID, accessModes}
TokenAuthenticator = HMAC-SHA1(key, TokenID)
Block Access Token = {TokenID, TokenAuthenticator}

其中keyID为对应生成token的秘钥的ID,accessModes为READ、WRITE、COPY、REPLACE。

有一点是,生成token的key是NameNode随机选择的,在DataNode向NameNode注册的时候发送给DataNode。

4)、以下为秘钥滚动机制:

在NameNode启动的时候,会随机选择一个秘钥,然后每隔一定时间,会重新随机选择一个秘钥取代老的秘钥。但是老的秘钥并不丢弃,一直保持到用该秘钥创建的Token失效。未失效的秘钥都会被缓存在内存中,但是只有新秘钥是用来生成token用,其他老秘钥均用于token认证校验使用。

DataNode启动时均会向NameNode注册,并且从NameNode获取全部未过期的秘钥集合。正因为这样,DataNode上的所有秘钥均不需持久化到磁盘。

每个新秘钥生成时,NameNode会将过期秘钥从set集合中移除并将新秘钥添加进该集合。每个心跳时,NameNode会将新的秘钥发送给DataNode。

DataNode收到新的秘钥后,首先将过期的秘钥从缓存中移除,并将新接收到的秘钥添加进去,如果出现重复,那么新秘钥覆盖旧秘钥。

最后,当NameNode重启时,缓存的秘钥都会丢失,会随机选择一个秘钥使用。但是因为DataNode上未过期的秘钥仍然可用,所以客户端无需从NameNode重新获取token。只有NameNode和DataNode都重启,才需要从NameNode重新获取token。

当NameNode要求DataNode把block复制到其他DataNode,或者Balancer要求DataNode把block复制到其它DataNode时,这两种情况下分别由DataNode和Balancer生成token。

2、MapReduce安全机制

Client和JobTracker之间通过RPC建立连接并使用Kerberos进行认证。task以启动Job的用户身份和权限运行。又因为MapReduce把挂起的和在执行的任务的信息存储在HDFS上,所以也部分依赖HDFS的安全机制。并且MapReduce只有Service Level Authorization这一个认证模型。

1)、Job 提交

首先看任务提交时会产生哪些信息

  • Job的配置信息
  • 分片信息
  • 元数据信息

这些信息会由client写入到用户的home目录下,并仅有该用户可读、写、执行。

当然client会将该目录以及证书通过RPC传递给JobTracker。因为Job可能需要访问不同的服务,所以其证书通过一个键值对Map的方式存储。安全证书存储在HDFS上JobTracker的系统目录下,只有MapReduce任务可读。

在MapReduce执行期间,JobTracker会定期更新delegation tokens以防过期,Job结束后让令牌失效。

另一方面,JobTracker要访问任务的配置信息,所以JobTracker需要使用用户的HDFS的委派令牌delegation token。JobTracker读取部分需要的配置信息并放入其内存。

2)、Job中的Task

首先是Task会以提交该Job的用户的身份运行,由于只有root权限能够改变用户ID。使用用户ID来运行任务,能确保一个用户的Job不能发系统信号给TaskTracker或者给其它用户的task。这也能保证本地文件的权限足够将信息保密。

3)、Job token

token的产生由任务提交时JobTracker生成,然后将token作为job的一部分存储在JobTracker在HDFS上的系统目录下并通过RPC分发给TaskTracker。TaskTracker将token写入job的本地磁盘,并只有该job用户可用。使用该token,Task能够通过DIGEST-MD5协议并使用RPC与TaskTracker通信以获取任务状态等。

4)、Shuffle中的安全机制

我们知道,在Hadoop中Map的输出由TaskTracker管理,Reduce通过HTTP向TaskTracker请求拉取数据。

具体来讲reduce 任务会以Job的token作为秘钥,并使用请求的URL和当前时间戳来计算HMAC-SHA1。这个HMAC-SHA1值会随着请求一起发给TaskTracker。这样一来,TaskTracker通过检验HMAC-SHA1及URL和时间戳,就能安全准确地为请求匹配特定的Map输出。

另外,怎么防止木马替代了TaskTracker?
TaskTracker的response header中包含请求时生成的并通过Job token保护的HMAC-SHA1。

为什么使用HMAC-SHA1而不用DIGEST-MD5呢?
因为DIGEST-MD5存在client和server端的往返,reduce过程会有大量的fetch连接请求,这样的往返显然需要付出代价。

五、服务代理(高层服务)安全机制

有时候可能需要服务代理,用于代理用户访问Hadoop服务的请求。对于像MapReduce和HDFS这样的需要通过Kerberos认证进行访问的服务。如果想要通过高层代理,就必须要有一个Kerberos服务主体。

具体是怎么做呢?

MapReduce和HDFS服务会配置一个列表,用于存放Kerberos服务主体,每个服务主体都代表一个super-user(超级用户)。在这个配置列表中的服务主体代表其它用户访问该服务的操作是被信任的。然后每个服务主体会给配置一个组,组中包含服务主体可信并且可代表的一组IP。

在向服务认证的时候,代理对其自身进行身份认证,但是访问服务的时候就像其它用户在访问一样。

不在配置中的服务主体及IP的代理访问请求,均会被拒绝。

六、说明

本文仅仅对安全机制稍做了解,并未做深入研究,部分结论来源于较旧文献进行的提炼总结,目的只是想对安全机制有些基础性的认识,如有错误,欢迎指正。

发布了95 篇原创文章 · 获赞 5 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_43878293/article/details/103694645