首页 > 代码库 > 《Hadoop高级编程》之为Hadoop实现构建企业级安全解决方案
《Hadoop高级编程》之为Hadoop实现构建企业级安全解决方案
本章内容提要
● 理解企业级应用的安全顾虑
● 理解Hadoop尚未为企业级应用提供的安全机制
● 考察用于构建企业级安全解决方案的方法
第10章讨论了Hadoop安全性以及Hadoop中用于提供安全控制的机制。当构建企业级安全解决方案(它可能会围绕着与Hadoop数据集交互的许多应用程序和企业级服务)时,保证Hadoop自身的安全仅仅是安全解决方案的一个方面。各种组织努力对数据采用一致的安全机制,而数据是从采用了不同安全策略的异构数据源中提取的。当这些组织从多个源获取数据,接着提取、转换并将数据加载到Hadoop时,随着结果数据集被导入到企业级应用中,安全挑战甚至变得更加复杂。例如,当从Hadoop作业中产生的数据集代表着多个数据集的组合时,应该如何对初始数据集实施访问控制策略?
更为复杂的是,许多组织发现Hadoop提供的安全级别不能满足它们的安全规章需求,而且它们必须补充Hadoop的安全模型。例如,为了满足其规章要求,一些组织需要加密静止的数据——这是Hadoop原本不提供的功能。还有,其他一些组织要求Hadoop查询为进行分析查询的数据科学家提供某个粒度级别的、基于属性的访问控制。尽管这当然包含在Hadoop安全未来的路线图中(如第10章中的讨论),但当前对这些功能的需求远远超过了Hadoop自身的支持能力。
鉴于这些挑战,必须使用一种整体的(而非以Hadoop为中心的)安全方案来开发企业级解决方案。当然,可以使用Hadoop中的原生安全机制来满足部分安全需求,但在许多组织中,你会发现Hadoop的安全机制并不能解决所有问题。必须为使用Hadoop的企业级应用策划、设计和补充其他安全机制,请查看企业级“蓝图”。
如第10章中的讨论,Hadoop在设计和开发时没有考虑安全性,而且在很长的一段时间里,Hadoop实现都几乎没有安全性。社区早期所采用的一个假设是Hadoop集群将由相互协作的、可信的机器组成,并由在可信环境中的可信用户使用。从较早的时间起,Hadoop社区采用了一种新的安全架构,使用了新的安全控制(如第10章中的讨论),但许多需要显式访问控制限制、保密规则、隐私保护和遵从法规的组织仍然不能使用Hadoop生态系统中的基础工具来满足其安全需求。由于想要使用Hadoop的功能,因此这些组织不得不将安全方案构建到其他工具中,或者设计不同方式的Hadoop使用方案。
本章是为那些想要使用Hadoop,但却必须满足安全性要求的企业级应用开发者而编写的。重要的是要理解大多数企业级应用都需要遵从组织的安全需求。这可能包含了与身份和访问管理基础设施、其他网络基础设施的相互结合,也可能意味着要应用尚未与“新来的”Hadoop集成的其他安全控制。本章给出了用于满足这些需求的方法论和可能的解决方案。
本章最开始简要地概述开发使用Hadoop的企业级应用时可能遇到的安全顾虑。接着讨论Hadoop安全尚未提供的机制,并给出了一系列用于构建使用Hadoop的企业级安全解决方案的方法,并包括一些实际示例。最后,本章简要地涵盖了可以在Hadoop发行版中使用的另外一个工具所提供的安全性——该工具是ApacheAccumulo,它是一个高度安全的数据存储和检索系统,由美国国家安全局(NSA)最初构建在Hadoop之上,用于细粒度访问控制的目的。
12.1 企业级应用的安全顾虑
当构建Hadoop解决方案时,考虑保证Hadoop自身的安全(如第10章中的讨论)并不是唯一重要的事情,理解安全策略的蓝图和以数据为中心的视角也很重要。
正如在图12-1中看到的那样,必须要理解Hadoop数据生命周期。当构建Hadoop解决方案时,会存在一个过程,即从信息源获取数据集、将数据集加载到Hadoop集群、运行查询和分析,以及使用结果集。随着数据的流动,安全架构师的目标就是确保在整个数据生命周期中实施了全部的访问策略。
不考虑涉及的工具,数据从各式各样的数据源提取出来、转换成某种常用格式并加载到Hadoop集群的HDFS上,这通常被称为提取(Extract)、转换(Transform)和加载(Load)过程(ETL过程)。数据分析师接着运行一系列MapReduce作业,并执行产生结果集的查询,而结果集通常又反过来用于企业级应用。
这里面临的挑战是多方面的。你必须能够在数据穿越整个生命周期的过程中保护它,以遵从原始的安全策略。由于数据要经过提取、加载并与集群机器上的其他数据集相组合,而且其他应用程序还会使用结果集,因此这可能会是一个挑战。
图12-1 Hadoop数据生命周期中的安全顾虑
图12-1很好地概括了本章所考察的一些顾虑。要构建涉及Hadoop的企业级安全解决方案,架构师们必须理解信息安全基础,以及如何应用它们。这里需要对用于Hadoop解决方案的大量安全目标进行一些解释,而且理解最佳实践取决于对安全顾虑和相关术语的理解。此讨论的目的不是给出一个详尽的清单或者解释每一个安全顾虑,而是提供一个对应于安全目标的简要信息安全词汇表,这些都是企业架构师需要了解的。每个目标中都有术语的定义,因而可以理解它们为什么在Hadoop上下文中很重要。
12.1.1 认证
认证意味着验证某个主体的身份。主体可能是某个系统中的用户、应用程序、任务或者其他“执行者”。如第10章的讨论,可以将Hadoop配置为使用Kerberos来认证用户、服务和Hadoop集群中的服务器。认证可以为用户和服务所声称的身份提供一定程度的保证,并且阻止用户、任务和服务被恶意系统冒充。
还应该提到的一点是,并非每个组织都有用于在Hadoop之外进行认证的企业级Kerberos部署。企业级应用可能需要将其他身份和访问管理基础设施进一步集成到自身的解决方案中。
12.1.2 授权
授权意味着确定某个主体有权限做什么。主体的身份在认证中验证之后,系统必须确定主体的授权凭据,并将它们与既定的授权策略相比较来提供对被请求资源的访问。如第10章中的讨论,Hadoop当前提供某个级别的访问控制,通过使用访问控制列表(ACL)来表达对Hadoop某些方面的访问控制策略,并使用类似UNIX的文件访问权限来表达所有者和组用户的访问权限。
除了Hadoop提供的机制之外,大多数企业组织还有用于授权的额外控制。例如,一个组织可能有以下所列举的一个或多个机制:
● 轻量级目录访问协议(LDAP)目录或活动目录(AD)实例——用于为主体保存组、角色和访问权限。
● 属性服务——将属性用作主体的授权凭据。
● 安全令牌服务(STS)——用于发放与主体授权凭据相关的令牌,以及用于发放事务中的授权决策。
● 策略服务——使用一些标准,例如可扩展访问控制标记语言(XACML)和安全断言标记语言(SAML),来表达资源的访问控制策略,并为主体提供访问控制决策。
使用Hadoop的企业级解决方案可能需要基于自己组织的企业级访问控制策略来控制对数据集的访问,这通常意味着要使用其他机制来补充Hadoop原生的授权控制。
需要记住的是,在整个数据生命周期中保持一致性的授权很重要。如果原始数据源有对数据的访问控制策略,那么对你来说很重要的一点就是为对这些数据运行查询的数据科学家们提供相同的访问控制。对所有后续导入到企业级应用的结果集进行适当的控制,这一点可能甚至是更重要的。但这的确是一个挑战。
12.1.3 保密性
保密性是一种限制敏感信息仅对已授权的参与方可见的安全目标。当在网络中传输敏感信息时,可能的需求是该信息不能在传输过程中被窃听者看到。这通过网络加密来做到。某些组织需要磁盘上的加密,或“静止数据”的加密,其中将加密应用在数据存储的位置,降低了未保护数据被偷窃的风险。
如第10章中所学,Hadoop提供用于网络加密的能力和机制。然而,它不提供用于加密静止数据的能力。本章后面将进一步学习用于达成此目标的策略。
12.1.4 完整性
完整性意味着确保数据在传输或者静止时没有被改动。这通常使用消息摘要、哈希码或者数字签名附带功能等加密机制来实现。当配置Hadoop实现网络加密时,它会在传输中应用数据完整性。
静态数据的完整性是另外一个问题,而幸运的是,由于要确保数据复制的可靠性,Hadoop中已经内置了大量数据完整性机制。Hadoop健壮、分布式架构的一个自然的副产品就是数据完整性和可靠性。由于HDFS被设计为运行在商用硬件之上,因此为了容忍故障,它会将数据的副本放置在多个节点上。基于副本的数量,以及校验和检查与冲突检测的机制,它为保存在HDFS中数据集的完整性提供了一种健壮的机制。
然而,安全架构师们有时会表达这样的担忧,即如果Hadoop集群中的某个节点被攻破的话,恶意用户可能会修改数据,导致数据分析结果的偏差。这当然是一种可能性,但通过使用一种防御纵深的安全策略来补充Hadoop的安全机制(服务器/服务认证、完整性检查等),企业级解决方案架构师们就可以降低这种风险。
12.1.5 审计
大多数公司依赖于安全审计来提供合规性问题的保证,以及发现潜在的安全漏洞。当然可以将Hadoop配置为记录所有访问——NameNode保存本地日志,为了确保日志完整性,可以配置将审计日志写入到受保护的卷。各种组织可能有与认证和授权相关的更进一步的审计需求。
注意:
尽管关于经典安全目标的大多数描述通常都关注于“保密性”、“完整性”和“可用性”,但这里的讨论关注于认证、授权、保密性、完整性和审计,因为这些是企业级应用安全的关键方面。可用性(保证对Hadoop的访问)固然重要——从Hadoop的设计方式上就可以看出已经考虑了这一点。Hadoop集群是高可靠性的,对可用性有高度的跟踪记录,而且由企业中的其他安全机制(例如入侵检测系统)来补充,以防范拒绝服务(DoS)攻击。这在本章中没有涵盖,因为此讨论是面向企业级应用开发者的。
12.2 Hadoop安全没有为企业级应用原生地提供哪些机制
现在,你已经掌握了一些上下文和安全术语,从而为学习本章余下的内容做好了准备,但理解Hadoop没有原生提供的某些方面的企业级安全是很重要的。当然,Hadoop确实提供了某种级别的认证(Kerberos)、一定程度的授权(ACL和UNIX级别的文件访问权限),以及支持网络加密和完整性的能力。然而,Hadoop却没有提供某些方面的安全性。
12.2.1 面向数据的访问控制
除了针对HDFS上用户和组的ACL和基于POSIX的文件访问权限(读和写)之外,Hadoop并不原生地跟踪其数据的访问控制策略。如本章所述,许多组织会基于可能非常复杂的策略来限制访问。可能存在某些情况,其中Hadoop实现包含一些数据集,必须对这些数据进行保护,以禁止某些可能没有权限看到MapReduce作业和查询结果的数据分析师们访问。
以下是这方面的一些很好的示例:
● 某个健康护理组织可能有这样的访问控制需求,即内科医生只可以访问与他自己的病人相关的数据,而且是在正常的工作时间内(上午9点到下午5点)。这意味着要对病人数据进行访问控制,提供访问该数据的系统必须基于用户的角色(内科医生)、一天中的时间(正常工作时间)以及是否是属于该内科医生的病人记录来限制数据。
● 政府文档可能要使用被称为强制访问控制(MAC)的策略,基于用户的公民身份和/或安全许可证来限制访问。
● 为特定公司提供建议的商业顾问应该没有权限访问为竞争对手提供的计划和建议。这通常被称为“兴趣冲突”或者“长城”策略。
● 大学可能会从其各个部门和下属组织中收集学生数据,范围包括财政、医疗记录和校园警察。大学可能需要基于部门和角色(医疗、警察、财政)来控制对数据的访问。
在所有这些例子中,都无法简单地将Hadoop原生的安全机制用于实施这些访问控制策略。这些挑战中的一部分是结构性的,基于MapReduce算法的设计方式。导入的数据可能最初与访问控制策略相关联(在使用安全策略“标记”了数据的示例中)。然而,策略和数据之间的关联性是存在裂缝的,因为数据分布在HDFS上,而且后续会随着作业运行而与其他数据集组合。这可能会产生新的、组合的数据集,其中的访问控制策略并不完全清晰。
对于需要提供此级别访问控制的组织来说,这是一个有挑战性的问题,本章后面将会考察此问题。
12.2.2 差分隐私
在近40年中,人们已经对无意识地泄露统计数据库中的信息这一课题,以及与数据挖掘相关的安全和隐私顾虑进行了研究。2006年,微软研究院的CynthiaDwork博士将该数据科学领域定义为差分隐私。
差分隐私关注于保护多个数据集和数据库中的信息,以防止泄露。随着Hadoop和其他数据分析平台已经能够使用大量计算能力处理多个大数据集,差分隐私已经成为一个非常热门的主题,涉及严重的隐私和法律问题。这一点对于类似《健康保险携带和责任法案(HIPAA)》的法令和其他一些隐私保护数字法律来说是尤其适用的。
即使通过“匿名化”去除了隐私信息,Hadoop数据集包含的(或者与之耦合的)其他看上去无害的信息,也可能会泄露个体的身份或者其他敏感信息,导致违反隐私策略。可能存在的情况是,以某种方式组合多个Hadoop作业所产生的信息是不能对数据科学家或者Hadoop用户可见的。然而,Hadoop自身并不提供差分隐私。当然,这不仅会影响内部用户的访问控制,也会对与其他组织分享统计结果和数据集的组织产生严重的影响。
由于Hadoop是一个由许多组织使用的强大分析平台,因此可以将它用于发现你可能没有想到的信息。在将数据集发布给公众或者自己的商务伙伴之前,组织应该三思而行。组织可能也有对数据的内部控制——这取决于你的环境,要知道,某些Hadoop用户可能没有被授权访问其分析查询的某些结果。这曾是NSA的顾虑之一,NSA开发并在之后发布了Accumulo,作为Apache的开源项目,提供单元格级别的安全。
“差分隐私”问题示例
关于差分隐私的最著名案例之一发生在Netflix公司。2006年,Netflix出价100万美元,为其影片推荐系统寻求10%的改进,并发布了“匿名化”的训练数据集,数据集中包含50万订阅用户的影片浏览历史,以便参加竞赛的开发者们能够使用这些数据。此数据集含有Netflix订阅用户已观看影片的收视率,并删除了所有个人身份信息。
两位研究人员,来自Austin Texas大学的Arvind Narayanan博士和Vitaly Shmatikov博士,将Netflix的数据集与互联网电影资料库(IMDB)的review数据库连接在一起,实现了一个新的“反匿名化算法”。他们发表了研究论文,阐述了可以从数学上辨别出Netflix发布的数据集中大部分用户的身份。基于用户在IMDB中仅少数几部影片的收视率,研究人员展示了他们的算法能够识别出Netflix数据集中相同的个体,并获取了Netflix订阅用户在2005年以前完整的影片浏览历史,导致了与订阅用户宗教信仰、性取向和政治倾向相关的潜在的隐私泄露。其结果是,一位Netflix订阅用户起诉了Netflix,声称其发布数据的行为违反了《视频保护隐私权法案(VPPA)》,并“暴露”了她是女同性恋。Netflix于2010年花费900万美元平息了这场诉讼。
与此同时,AOL发布了一个“匿名化”的搜索引擎日志数据集,用于研究目的,而纽约时报的一位记者交叉引用该数据集和通信录列表,能够识别出用户的身份。这暴露了AOL用户三个月内的搜索历史——其中一些是非常令人尴尬的。其结果是AOL的首席技术官(CTO)辞职、两名AOL员工被解雇以及一场针对公司的集体诉讼。
还有不胜枚举的其他例子——MIT的一位研究人员在将一个“匿名化”的州保险数据库与公开可用的州选举注册记录一起分析时,发现能够从该数据集中识别出其州长的医疗记录。
这些例子演示了手头的问题,以及一起使用数据集中的信息会如何潜在地违反隐私法律、规章,并绕过对用户的访问控制。通过使用这些相同的方法,你的内部Hadoop用户也许能够绕过安全限制,如果没有设置适当的控制的话。
12.2.3 加密静止的数据
由于针对保存在磁盘上和终端用户设备上信息的保密性存在很多威胁,因此许多有敏感信息的组织都有要求加密静止数据的策略。此种策略的多数原因与恶意软件的威胁、数据的敏感性或保密性、或者法律规章相关。例如,HIPPA具有与加密电子保护的健康信息(EPHI)中静止数据相关的指导意见,并且其他保护个人可识别信息(PII)的法律也在发挥作用。
一些组织正在推动加密HDFS上的静止数据,Hadoop并不原生地提供该功能。然而,可以将第三方库和其他产品与Hadoop一起使用来满足这些需求,而且Rhino项目(如第10章中的讨论)也正在致力于解决Hadoop中的这个问题。
12.2.4 企业级安全集成
大多数公司在企业内部都有各式各样的安全基础设施,包括用于认证的公钥基础设施(PKI)组件、活动目录实例、安全令牌服务、属性服务和用于认证用户的策略服务器,提供授权凭据,并做出和实施访问控制决策。Hadoop的原生安全机制并不总能让你与各个组织的安全基础设施“适配”或集成。当安全需求指定要将企业级应用与组织的安全基础设施集成时,安全架构师的工作就是设计一个解决方案,能够在使用Hadoop的同时,使用其他工具与安全基础设施相集成。
12.3 保证使用Hadoop的企业级应用安全的方法
近来,大量的项目、Hadoop插件和专门的Hadoop发行版已经承诺了要增强Hadoop的安全性。Hortonworks的Knox Gateway、Intel的安全增强型Hadoop发行版和诸如Rhino等开源项目已经发布,并实现了帮助企业级应用开发者满足安全需求的承诺。无论如何,重要的是要记住每个企业级应用都是不同的,而且每个部署中的安全需求也将是不同的。
在讨论细节之前,重要的是要理解一些一般的基础知识和指南,用于为使用Hadoop的企业级应用提供安全保证。当大量的项目都只关注于特定的安全机制,而不是遵从某些适用于任何项目的、常识性的指导方针时,它们在运行过程中都会出现问题。
基于客户的任务和需求,每个项目的企业安全策略都可能不同,但却都遵从这些常识规则:
● 确定安全需求——理解安全需求很关键。对于认证、访问控制、审计、加密、完整性和隐私的需求将由组织自身来决定。需要问的一些问题可能会围绕着Hadoop MapReduce作业结果数据集的安全性,以及Hadoop运行时自身的安全性(为进行查询和运行作业的应用程序/用户提供访问控制)。与适当的决策制定者会晤来理解哪些是需要的,以便可以做相应的准备。
● 从一开始就设计安全性——这些类型项目最大的问题之一就是到最后才尝试改进安全性,这样的实践导致了短暂且脆弱的架构,通常会注定项目的失败。如果项目中有本章所讨论的安全需求,但却认为可以只关注数据分析而后续再尝试考虑保证解决方案安全性的话,那么会有极大的失败风险。应该关注于开发可以与有关当局进行讨论的初始总体安全架构,以获得概念上的认可。
● 不要使用不需要的安全性——如果没有要达到本章所讨论的某些目标的安全需求,那么就不要做任何事!不要实现那些不需要的东西来增加复杂性和性能开销。
● 使用“防御纵深”方案——永远不要假设使用个别安全方案或机制就能够阻止或预防攻击或违反安全策略。防御纵深策略包含多层防御。
● 牢记蓝图——了解数据的生命周期(如前面图12-1中所示)。理解提供安全性可能意味着访问控制,以及在整个数据生命周期(从原始数据源中的数据,到加载到Hadoop集群中的数据,再到结果数据集)中保持和实施策略。
接下来的几小节会深入到满足某些安全需求的具体细节中,并补充Hadoop原生提供的安全机制。讨论关注于三个主要方案,在与Hadoop原生机制结合的同时,它们提供了企业级安全的构成组件。在接下来的这些小节中,讨论将聚焦于Apache Accumulo。
12.3.1 使用Accumulo进行访问控制保护
Apache Accumulo是一个稀疏的、分布式的、有序的以及多维度的键/值存储,提供单元格级别的细粒度访问控制属性。它于2008年由NSA开发,基于Google BigTable的设计,于2011年发布到Apache开源社区,并且现在是顶级Apache项目。它是构建在Hadoop和Zookeeper之上的、高度可扩展的NoSQL数据库。开发它的部分原因是为了解决大数据安全问题。
Accumulo扩展了BigTable的数据模型,但添加了一个元素,以提供单元格级别的、强制的基于属性的访问控制(ABAC)。可以使用可见性控制来标记所有导入到Accumulo中的数据,当数据分析师查询数据时,基于访问控制策略中的可见性控制,他们将仅能看到你期望他们看到的内容。Accumulo的API为你提供的能力包括编写认证用户的客户端,以及与企业级属性服务相集成,并拉取用户的授权凭证以提供某个级别的访问控制。Accumulo还提供将用户和授权信息保存在其自身中的能力。
如图12-2中所示,Accumulo是一个键/值存储,它的键是一个5元组。Accumulo中的键由行ID、列族、列限定符、列可见性和时间戳构成。此5个元素的键与一个值相关联。
图12-2 Accumulo数据模型
该5元组键提供原子性、本地性、唯一性、访问控制和版本化。重要的是要注意键中的时间戳维度包含了基于不同的时间和日期,提供相同数据多个版本的能力。大体来说,Accumulo的数据模型多数借用了BigTable数据模型,但添加了可见性元素来提供面向数据的安全——它将仅返回那些运行查询的用户/应用程序的凭据满足可见性标签的单元格。
Accumulo和HBase中数据级安全性的差异
HBase和Accumulo是类似的——它们都是在Hadoop之上运行BigTable实现的Apache项目。HBase和Accumulo中的安全性提供类似的数据级安全,但方式不同。如第10章中的讨论,HBase可以对数据提供以逐个表或逐个列为基础的访问控制。当前,它还不支持Accumulo可以做到的单元格安全性,但Rhino项目的Intel发行版正在实施这方面的工作,使得HBase不久后可能会支持基于单元格的安全。
HBase可以与Hadoop的安全模型轻易地集成(使用Kerberos),而且此方案与Hadoop生态系统的其余部分一致。而另一方面,Accumulo是一个较新的顶层Apache项目,包含一个内部访问控制数据库,而且它实现安全性的方式与Hadoop生态系统中其他工具不同。
HBase和Accumulo都很流行。基于其单元格级别的访问控制安全特性,Accumulo在高安全环境中是最流行的,并承诺提供与强制访问控制(MAC)和差异性安全相关的解决方案。
大多数较熟悉关系型数据库的开发者通常习惯于看到类似于表12-1的表,它是一个二维的模型。
表12-1 关系数据模型中的示例数据
名 字 | 大 学 | 出生所在州 | 签 名 短 语 |
Billy | UCLA | West Virginia | “Brutal” |
Jeff | UVA | New Jersey | “C’Mon Man” |
在Accumulo的结构中,相同的数据看上去会类似于表12-2,其中使用了较细的粒度来保存数据,包括可见性和能够跟踪数据随时间变化的时间戳。
表12-2 Accumulo数据模型中的数据
行ID | 族 | 限 定 符 | 可 见 性 | 时 间 戳 | 值 |
Billy | School | University | Public | 20130503 | UCLA |
Billy | BirthRecord | State of Birth | Admin | 20120503 | West Virginia |
Billy | Greeting | Signature Phrase | Public | 20120503 | “Brutal” |
Jeff | School | University | Public | 20120503 | UVA |
Jeff | BirthRecord | State of Birth | Admin | 20120503 | New Jersey |
Jeff | Greeting | Signature Phrase | Public | 20120503 | “C’Mon Man” |
注意在表12-2中,可见性被标记了安全标签。可以使用与/或布尔逻辑将这些标签添加到记录中。例如,可以给出类似于表12-3的授权策略,其中可以创建授权凭据并与用户关联,将访问限定为表中的每个单元格。
表12-3 安全策略示例及其安全标签语法
访问某条记录的策略示例 | 安全标签语法 |
必须是共和党人而且是美国公民 | Republican & USCitizen |
必须是警察,或者必须是美国公民且在武装部队中 | Police Officer | (USCitizen & ArmedForces) |
必须是项目管理者而且必须在FGM或White Oak组织中 | ProjectManager & (FGM | White Oak) |
超过17岁或者父母同意 | Over17 | parentalConsent |
在Accumulo的安全模型中,用户向可信的客户端(作为开发人员,可以编写这样的客户端)进行认证,而客户端要负责认证用户并向Accumulo传递适当的授权凭据。你的可选方案为与自己的认证和授权系统相集成,或者使用Accumulo的内部认证/授权组件——可以在其中保存用户和他们的授权凭据。本小节为每种方案都提供了一个示例。
一个简单的示例
让我们考虑一个大学数据库的示例,其中某大学从各个部门和下属组织收集了关于其学生的数据。在此示例中,有来自校园医疗中心、财政中心、大学管理处、体育设施和校园警察的数据。你收集了各种各样的信息,而且整个组织可以查询这些信息。你的需求是保护某些信息,例如如下所述:
● 学生医疗检查记录应该只对医护人员和大学管理处可见。
● 田径学院学生体育相关的记录应该只对他们的教练可见,有时也可对医护人员可见。
● 购买记录、评分以及诸如社会安全号码等敏感信息应该只对大学管理处可见。
● 学生在校园警察处的记录应该只对校园警察或者大学管理处可见。
对于本例,让我们将一些样例数据加载到Accumulo数据库中,如表12-4所示。在这个简单的例子中,有一位名叫Kirk Rest的学生,你有关于他的各种信息,这些信息均是从大学中的大量数据源收集而来的。
表12-4 大学数据示例中的键/值
行ID | 族 | 限 定 符 | 可 见 性 | 时 间 戳 | 值 |
Kirk Rest | SSN | 999999999 | ADMIN | 20050612 |
|
Kirk Rest | Phone | 804-555-0005 | ADMIN | 20050612 |
|
(续表)
行ID | 族 | 限 定 符 | 可 见 性 | 时 间 戳 | 值 |
Kirk Rest | Address | 111 Carson Ave, Richmond VA | ADMIN | 20050612 |
|
Kirk Rest | Weight | 170 | MEDICAL | COACH | 20110711 |
|
Kirk Rest | Running Test | 10K | COACH | 20110812 | 56 |
Kirk Rest | Running Test | 10K | COACH | 20110517 | 58 |
Kirk Rest | Running Test | 5K | COACH | 20110716 | 24 |
Kirk Rest | Running Test | 5K | COACH | 20110612 | 27 |
Kirk Rest | Payment | Semester Payment | ADMIN | 20111223 | 1000 |
Kirk Rest | Medical Test Report | Cholesterol | MEDICAL | 20111222 | 200 |
Kirk Rest | Medical Test Report | Biopsy | MEDICAL | 20111012 | Negative |
Kirk Rest | Grade | Organic Chem | ADMIN | 20111201 | A |
Kirk Rest | Grade | Calculus 1 | ADMIN | 20111201 | B |
Kirk Rest | Grade | Radical Presbyterianism | ADMIN | 20100612 | D |
Kirk Rest | Police Charge | Curfew Violation | ADMIN | POLICE | 20071103 | Pending Hearing |
Kirk Rest | Police Charge | DUI Arrest | ADMIN | POLICE | 20091104 | Guilty |
假定将此信息加载到已经安装在测试Hadoop实例上的Accumulo存储中。为此,应该使用Accumulo shell,它是一个简单的客户端,可以用于创建和修改表,以及创建用户并为这些用户分配授权凭据。由于本章关注的是安全,而非Accumulo的更多细节,因此这里不讨论加载数据的详情。
注意:
由于不同版本的Accumulo需要与不同版本的Hadoop和Zookeeper一起工作,因此这有时是对安装的一个挑战!上手Accumulo的一种简单方法是使用已经配置好的虚拟机(VM)。Sqrrl公司的网站上提供一个独立的亚马逊机器实例(AMI),用于Apache Accumulo的快速入门,并且该公司还提供一个在Oracle VirtualBox上预先配置好的VM。更多详情请参见位于http://www.sqrrl.com/的网站,以及位于http://blog.sqrrl.com/post/40578606670/ quick-accumulo-install/的VM。
Accumulo针对快速获取键对应的值做了优化。为此,开发的Accumulo客户端(在这种情况下,客户端就是Accumulo shell)要创建一个对值进行迭代的扫描器。正如在代码清单12-1中所看到的那样,scan命令允许你在创建的新表——universitydata——中对值进行迭代(以root身份运行,而root对表中的所有内容均有访问权限)。
代码清单12-1:查看数据
<span style="font-family:Microsoft YaHei;font-size:14px;">root@accumulo universitydata> scan Kirk Rest Address:111Carson Ave, Richmond VA [ADMIN]Kirk RestGrade:Calculus 1 [ADMIN] BKirk RestGrade:Organic Chem [ADMIN] AKirk RestGrade:Radical Presbyterianism [ADMIN] DKirk Rest MedicalTest Report:Cholesterol [MEDICAL] 200Kirk Rest NedicalTest Report:Biopsy [MEDICAL] NegativeKirk RestPayment:Semester Payment [ADMIN] 1000Kirk RestPhone:8045550005 [ADMIN]Kirk Rest PoliceCharge:Curfew Violation [ADMIN|POLICE] Pending HearingKirk Rest PoliceCharge:DUI Arrest [ADMIN|POLICE] GuiltyKirk Rest RunningTest:10K [COACH] 56Kirk Rest RunningTest:5K [COACH] 27Kirk RestSSN:99999999 [ADMIN]Kirk Rest Weight:170 [MEDICAL|COACH]</span>
为演示单元格可见性的示例,需要创建下列用户:
● 医生(drhouse),为其分配MEDICAL角色
● 管理员(denyseAccountant),为其分配ADMIN角色
● 教练(coachTark),为其分配COACH角色
● 警察局长(chiefDoug),为其分配POLICE角色
如代码清单12-2所示,使用shell来为所有这些能够读取表的用户分配访问权限(授予他们每个人Table.READ权限),并使用setauths命令为他们分配用于可见性的适当角色。
代码清单12-2:分配访问权限和用户视图
<span style="font-family:Microsoft YaHei;font-size:14px;">root@accumulo universitydata> grantTable.READ -t universitydata -u drhouseroot@accumulouniversitydata> setauths -s MEDICAL -user drhouse root@accumulouniversitydata> grant Table.READ -t universitydata -udenyseAccountantroot@accumulouniversitydata> setauths -s ADMIN -user denyseAccountant root@accumulo universitydata> grant Table.READ -t universitydata -ucoachTarkroot@accumulouniversitydata> setauths -s COACH -user coachTark root@accumulo universitydata> grant Table.READ -t universitydata -uchiefDougroot@accumulo universitydata>setauths -s POLICE -user chiefDoug</span>
最后,为展示Accumulo现在将保护对表的访问,以每个用户的身份登录并使用Accumulo shell。对universitydata表进行扫描(或迭代)。代码清单12-3展示了如何以用户coachTark、drHouse、denyseAccountant和chiefDoug的身份登录,并对表进行迭代,而且表基于每个用户的权限提供了访问控制。
代码清单12-3:演示用户的角色和可见性
<span style="font-family:Microsoft YaHei;font-size:14px;">root@accumulo universitydata> user coachTarkEnter password foruser coachTark: ********* coachTark@accumulouniversitydata> scanKirk Rest RunningTest:10K [COACH] 56Kirk Rest RunningTest:5K [COACH] 27Kirk Rest Weight:170[MEDICAL|COACH] root@accumulouniversitydata> user drhouse Enter password foruser drhouse: *******drhouse@accumulouniversitydata> scan Kirk Rest MedicalTest Report:Cholesterol [MEDICAL] 200Kirk Rest NedicalTest Report:Biopsy [MEDICAL] NegativeKirk Rest Weight:170[MEDICAL|COACH] drhouse@accumulouniversitydata> user denyseAccountant Enter password foruser denyseAccountant: ******denyseAccountant@accumulouniversitydata> scan Kirk Rest Address:111Carson [ADMIN]Kirk RestGrade:Calculus 1 [ADMIN] BKirk Rest Grade:OrganicChem [ADMIN] AKirk RestGrade:Radical Presbyterianism [ADMIN] DKirk RestPayment:Semester Payment [ADMIN] 1000Kirk RestPhone:8045550005 [ADMIN]Kirk Rest PoliceCharge:Curfew Violation [ADMIN|POLICE] Pending HearingKirk Rest PoliceCharge:DUI Arrest [ADMIN|POLICE] GuiltyKirk RestSSN:999999999 [ADMIN] denyseAccountant@accumulouniversitydata> user chiefDougEnter password foruser chiefDoug: *********chiefDoug@accumulouniversitydata> scan Kirk Rest PoliceCharge:Curfew Violation [ADMIN|POLICE] Pending HearingKirk Rest Police Charge:DUI Arrest[ADMIN|POLICE] Guilty</span>
正如从代码清单12-3中看到的那样,Accumulo能够基于每个用户的授权控制来限制访问,你已经通过使用Accumuloshell演示了这一点。现在,让我们用Java构建一个Accumulo客户端,该客户端将为本例演示相同级别的访问控制,并与企业中的身份和访问管理基础设施相集成。
当涉及与企业基础设施集成时,Accumulo有一个灵活的模型。如前面提到的,Accumulo客户端的职责是认证用户和获取用户的授权凭据,并将其展示给Accumulo以供处理之用。只要使用企业属性存储中的相同属性或角色标记了Accumulo表中的数据可见性,它就可以优雅地工作。如果没有标记的话,那么很可能需要对从客户端属性存储中获取的属性进行一些处理,以确保它们是完全相同的角色。
为了演示这一点,让我们浏览一个如何编写简单客户端的示例,该客户端通过自选的认证机制来认证用户,并从自选的属性服务或LDAP目录拉取授权凭据。
代码清单12-4展示了一个编写连接到Accumulo的Java类的示例。为了连接,必须使用Connector类建立一个Accumulo连接。为此,必须首先通过初始化ZookeeperInstance类,连接到跟踪Accumulo的Zookeeper实例,而ZookeeperInstance类将会返回一个连接器。
代码清单12-4:Accumulo客户端代码示例
<span style="font-family:Microsoft YaHei;font-size:14px;">import java.util.Collection;importjava.util.Collections;importjava.util.Map.Entry; import org.apache.accumulo.core.client.Connector;importorg.apache.accumulo.core.client.ZooKeeperInstance; importorg.apache.accumulo.core.client.Scanner;importorg.apache.accumulo.core.data.Key;importorg.apache.accumulo.core.data.Range;importorg.apache.accumulo.core.data.Value;importorg.apache.accumulo.core.security.Authorizations; public classQueryExample{public static void main(String[] args)throws Exception{//Simple Example of the name of youraccumulo instance & zookeeperZooKeeperInstanceinst = new ZooKeeperInstance("accumulo", "localhost"); //Obviously this is just an exampleConnector connector =inst.getConnector("root", "secret"); //Scan in the username and password forthis simple example java.util.Scanner in = newjava.util.Scanner(System.in);System.out.println("Username:");String username = in.nextLine();System.out.println("Password:");String password = in.nextLine(); Authorizations auths = null; try{//An example of how you can interactwith other systems (LDAP,etc) CustomAuthenticator authenticator = newCustomAuthenticator();authenticator.authenticate(username,password); //Retrieve credentials from externalsystemauths =authenticator.getAuthorizationInfo(username);}catch (ExceptionauthenticationException){System.out.println("AuthenticationFailure.");System.exit(-1);} // Search our university data example& print out everything Scanner scanner =connector.createScanner("universitydata", auths);for (Entry<Key,Value> entry :scanner) {System.out.println( entry.getKey().toString());}}}</span>
一旦建立了连接,就要认证用户。在这种情况下,对于这样一个简单的示例,从命令行抓取用户信息,并将其传递给一个叫做CustomAuthenticator的外部类,编写此类仅是为了展示可以使用Accumulo之外的另一种认证和授权机制。在该类中,将从命令行中扫描到的用户名和密码传入该类的authenticate()方法。如果用户认证成功,那么接着从外部存储拉取用户的授权凭据,并返回Accumulo期望的org.apache.accumulo.core.security. Authorizations类中的值。最后,如之前示例中所示,创建一个扫描器对相同表中的值进行迭代,并简单地打印结果。
代码清单12-5展示了命令行中的结果。在此示例中,设置了一个外部的LDAP目录,其中包含一个叫做joeUser的用户,其角色为ADMIN。
代码清单12-5:Accumulo客户端的结果
<span style="font-family:Microsoft YaHei;font-size:14px;">Script started on Fri 03 May 2013 12:45:09 AM EDT$ java QueryExample13/05/03 00:45:16INFO zookeeper.ZooKeeper:Clientenvironment:zookeeper.version=3.4.3--1,built on 03/20/2012 16:15 GMT13/05/03 00:45:16INFO zookeeper.ZooKeeper:Client environment:host.name=ubuntu13/05/03 00:45:16INFO zookeeper.ZooKeeper:Clientenvironment:java.version=1.6.0_2713/05/03 00:45:16INFO zookeeper.ZooKeeper:Client environment:java.vendor=SunMicrosystems Inc.13/05/03 00:45:16INFO zookeeper.ZooKeeper:Clientenvironment:java.home=/usr/lib/jvm/java-6-openjdk-amd64/jre13/05/03 00:45:16INFO zookeeper.ZooKeeper:Client environment:java.class.path=.13/05/03 00:45:16 INFO zookeeper.ZooKeeper:Clientenvironment:java.library.path=/usr/lib/jvm/java-6-openjdkamd64/jre/lib/amd64/server:/usr/lib/jvm/java-6-openjdkamd64/jre/lib/amd64:/usr/lib/jvm/java-6-openjdkamd64/jre/../lib/amd64:/usr/java/packages/lib/amd64:/usr/lib/x86_64-linuxgnu/jni:/lib/x86_64-linux-gnu:/usr/lib/x86_64-linuxgnu:/usr/lib/jni:/lib:/usr/lib13/05/03 00:45:16 INFO zookeeper.ZooKeeper:Client environment:java.io.tmpdir=/tmp13/05/03 00:45:16 INFO zookeeper.ZooKeeper:Client environment:java.compiler=<NA>13/05/03 00:45:16 INFO zookeeper.ZooKeeper:Client environment:os.name=Linux13/05/03 00:45:16 INFO zookeeper.ZooKeeper:Client environment:os.arch=amd6413/05/03 00:45:16 INFO zookeeper.ZooKeeper:Client environment:os.version=3.2.0-29-generic13/05/03 00:45:16 INFO zookeeper.ZooKeeper:Client environment:user.name=accumulo13/05/03 00:45:16 INFO zookeeper.ZooKeeper:Client environment:user.home=/usr/lib/accumulo13/05/03 00:45:16 INFO zookeeper.ZooKeeper:Client environment:user.dir=/usr/lib/accumulo/classes13/05/03 00:45:16 INFO zookeeper.ZooKeeper:Initiating client connection,connectString=localhost sessionTimeout=30000watcher=org.apache.accumulo.core.zookeeper.ZooSession$AccumuloWatcher@6791d8c113/05/03 00:45:16 INFO zookeeper.ClientCnxn:Opening socket connection to server /127.0.0.1:218113/05/03 00:45:16 INFOclient.ZooKeeperSaslClient:Client will not SASL-authenticate because the defaultJAASconfiguration section ‘Client‘ could not be found. If youare notusing SASL, you may ignore this. On the other hand,if you expected SASL to work, please fix your JAASconfiguration.13/05/03 00:45:16 INFO zookeeper.ClientCnxn:Socket connection established tolocalhost/127.0.0.1:2181,initiating session13/05/03 00:45:16 INFO zookeeper.ClientCnxn:Session establishment complete on serverlocalhost/127.0.0.1:2181,sessionid = 0x13e6757677611f1, negotiated timeout = 30000Username:joeAdminPassword:******Kirk Rest Address:111 Carson [ADMIN] 20050612falseKirk Rest Grade:Calculus 1 [ADMIN] 20111201falseKirk Rest Grade:Organic Chem [ADMIN] 20111201falseKirk Rest Grade:Radical Presbyterianism[ADMIN] 20100612 falseKirk Rest Payment:Semester Payment [ADMIN]20111223 falseKirk Rest Phone:804 [ADMIN] 20050612 falseKirk Rest Police Charge:Curfew Violation[ADMIN|POLICE] 20071103 falseKirk Rest Police Charge:DUI Arrest[ADMIN|POLICE] 20091104 falseKirk Rest SSN:99 [ADMIN] 20050612 false</span>
在此示例中进行认证的用户——joeAdmin,与之前示例中的用户不同,该用户并没有保存在Accumulo中。如这里所示,可以编写一个Java客户端来认证用户,从企业存储拉取授权凭据,并查询Accumulo。
还有更多关于Apache Accumulo的内容,比此小节中所涵盖的要多得多。然而,重要的是要意识到对于为了数据安全而使用Accumulo的组织来说,Accumulo仅是企业安全解决方案的一个方面。企业级安全需要防御纵深,并且必须覆盖整个数据生命周期的安全——而不是仅当数据在Hadoop中保存时。
12.3.2 加密静止数据
Hadoop中静止数据的加密是许多不同项目(一些开源项目和一些商业项目)都在为之努力的一个主题。Hadoop并不原生支持此功能。当前,大量公司正在使用不同的Hadoop发行版来保护敏感数据,这些发行版不仅保护敏感信息,而且遵从法律(例如HIPAA)和其他安全法规。许多组织想要使用静止数据的加密来防止恶意用户尝试获取对DataNode的未授权访问。
当前的一些解决方案包括Gazzang zNcrypt,它为Cloudera CDH发行版提供数据安全性。Intel的Hadoop发行版于2013年初发布,已经在使用Intel公司的Xeon处理器时对加密静止数据进行了优化。看上去每天都有新的解决方案出现——但到目前为止,所有这些方案都受专利保护,或者要求使用某个特定的Hadoop发行版。如第10章中提到的,Rhino项目(由Intel贡献给Apache)包含了一些改进,包括分布式密钥管理和实现静止数据加密的能力。Hadoop开发者社区目前正在针对将其加入到未来的某个Hadoop发行版而进行审查。
无论将何种机制用于实现加密Hadoop中的静止数据,非常重要的一点是也要理解此功能的意外效果。如果需要一个加密静止数据的解决方案,那么要记住加密将会对性能产生影响。如果认为MapReduce作业可能比现在所期望的更慢,那么要想象一下加密静止数据将会对性能产生什么影响。Intel的Hadoop发行版在使用特定Intel处理器的机器上对加密和解密进行了优化。正是由于Intel的发行版在开发时考虑了自己的硬件加速器,因而对企业架构师来说,还有很重要的一点是要评估加密应用程序的静止数据所带来的成本——如果确实需要此功能,那么请为性能做相应的准备。
目前来说,除非迫切需要加密静止数据,否则在此时,可能会有一些原因让你选择避免这样做。首先,由于分布式数据和密钥管理的挑战,这是一个非常复杂的功能领域。第二,Rhino项目在该领域带来的提升可能即将到来,而在此之前,你可能还是会被锁定到某个特定的发行版或提供商。最后,如前文所提到的,会存在与加密静止数据相关的性能损失。如果数据如此敏感,以致于正在探讨加密静止数据可能性的话,那么下一小节可能是一个潜在的解决方案。
12.3.3 网络隔离和分隔方案
如前面提到的,有保密和敏感数据的组织传统上将隔离Hadoop集群网络作为一种满足安全需求的方案。这些组织通常基于用户的授权级别控制对各个集群的访问,将物理安全作为一种保护机制。其他一些组织则使用一种限制较少的方案,即分隔网络,但允许可信的服务器和工作站在网络之间进行一些传输。
此种方案仍然是非常可行的选项,这有许多原因:
● 安全集成的复杂性——如果安全策略非常严格而且数据非常敏感,以至于必须将大量非原生的安全控制集成到Hadoop集群中,那么请考虑使用网络隔离——将它与其他网络分隔开来,并限制仅有授权的用户能够访问。如果这样做,那么只需要考虑Hadoop结果数据集的可见性,而不需要考虑Hadoop运行时安全。这将最小化整体风险,而且最有可能降低成本。
● 性能——人们常说,“安全是性能的敌人”。在某个解决方案中实施的安全机制越多,它通常就会变得越慢。对于保证Hadoop安全来说,情况就是这样的,尤其是如果正在考虑使用第三方工具来加密和解密HDFS上的静止数据的话。许多人将会选择网络隔离方案来简单地避免性能损失。
● 数据的敏感程度不同——组织中的某些数据可能只能对某些人群可见。如果是这种情况,那么Hadoop作业的结果集也将是敏感的。尽管Hadoop中的某些工具(例如HBase和Accumulo)可以提供某种列级别(HBase)和单元格级别(Accumulo)的访问过滤方式,但Hadoop中的其他工具则不提供该级别的安全性。如果正在运行构建结果集的JavaMapReduce应用程序,而且正在使用各种各样的不同工具,那么明智之举就是考虑基于用户的可见性来分隔集群。
● 不断演进的Hadoop安全范畴——大量的Hadoop新产品、发布版本和发行版正在提供新的安全特性。如第10章中提到的,Hadoop安全性增强可能即将在未来一年中到来。这些即将到来的变化将会影响使用Hadoop的企业级应用程序,而在了解这些变化产生的影响之前,很多组织正在选择网络隔离模型。
● 集成之前的数据安全审核——由于网络隔离方案不支持其他网络中的企业级应用程序对数据的实时访问,因此它允许在企业级应用程序使用数据材料之前,对其进行审核和过滤,以最小化潜在的保密性风险和隐私泄露(这当然是一柄“双刃剑”,因为网络隔离通常是实时Hadoop的一个阻碍,而且需要一个发布供企业级应用程序使用的数据集的处理过程)。
网络隔离能够以很多方式实现企业级应用程序安全。图12-3展示了一种做到这一点的方法。某个组织创建了“数据分析”网络,使用物理的“气隙”将其从组织的企业网络中分离,以阻止在两个网络之间传输任何数据。具有适当访问控制权限的数据科学家在数据分析网络中的Hadoop集群上执行查询和MapReduce操作,而且对该网络的访问由物理安全和/或对用于执行查询的客户端机器的认证来控制。
图12-3 使用导入/导出工作流的“气隙”网络隔离
为了支持使用这些数据集结果的企业级应用程序,必须开发和应用一个重要的工作流处理过程:
(1) 首先,必须从企业网络适当的数据库和应用程序中抽取待分析的所有数据,将其写入媒介,并带入到隔离的网络中。
(2) 一旦准备好了分析所用的数据而且已经将其加载到了集群中,那么就可以运行HadoopMapReduce作业,直到生成待审查的结果。
(3) 对于结果来说,必须使用由外部企业级应用程序控制的授权策略来标记结果,或者对结果进行过滤,以便删除敏感的、保密的或者受隐私保护的数据。
(4) 一旦过滤或使用访问控制策略标记了此数据集,就可以将该数据集写入到媒介并导入到企业级应用程序。
对于许多组织来说,这是一个繁琐的过程,因为涉及两个网络的物理隔离,而且需要一个工作流——从原始网络中导出数据,将其导入到数据分析网络,并进行分析、过滤,然后准备结果数据集并加载到企业级应用中。然而,当数据尤其敏感时,许多组织还是采取这个方案。
鉴于引入的复杂性,一些组织开始转向一个类似的模型,即一种将流量限定为从企业网络中的可信主机到数据分析网络的方案,如图12-4所示。在这种情况下,ETL过程可以通过网络完成,省去了前面所述处理过程的第(1)步。
图12-4 使用单向传输的网络隔离
将Apache Accumulo主要用于对数据进行访问控制的一些组织,会对可以发布到企业网络中的结果数据集执行数据过滤——例如,创建“企业网络用户”,他们的凭据与网络中的最低授权等级相同。基于此用户对待发布数据进行的过滤通常使得结果集更易于在内部发布,而不必担心不经意的信息泄露。
可以以其他无数种方式使用网络隔离——这些只是其中的一部分。其他一些方案包括基于所使用数据的类型隔离Hadoop集群,而某些限制较少的方案包括允许与企业网络中的机器互联,使用ACL来限制只有可信主机能够访问。
企业级安全解决方案的每个部分都将取决于组织自身的安全需求——没有任何两个组织是完全相同的。无论如何,本章提供的示例和指南应该能够在构建企业级安全解决方案时帮到你。
12.4 小结
本章给出了企业级的安全视图,关注于数据生命周期中的安全策略和以数据为中心的视角。重要的是安全架构师们要理解这个蓝图,同时能够解决Hadoop和补充安全工具所能提供的不同方面的企业级安全。
本章以开发使用Hadoop的企业级应用中对安全顾虑的简要概述作为开始。你学习了Hadoop自身无法解决的一些安全挑战——包括面向数据的安全、差分隐私和静止数据的加密。查看了大量用于构建使用Hadoop的企业级安全解决方案的方法,并浏览了一些指南和示例。学习了如何将ApacheAccumulo用于单元格级别的安全,并深入考察了静止数据的加密以及当前可用的一些方案。还学习了一些关于网络隔离的方案,许多对暴露敏感数据有顾虑的组织都在使用这种方案。
对于Hadoop来说,安全当然是一个不断演进的话题,而且是Hadoop在未来几年中将持续增长的领域。第13章关注于Hadoop在一些其他方面即将到来的改进,并讨论当今新兴的、且会在未来继续增长的趋势。
《Hadoop高级编程——构建与实现大数据解决方案》试读电子书免费提供,有需要的留下邮箱,一有空即发送给大家。 别忘啦顶哦!