HBase 之访问控制

转自:http://www.spnguru.com/2011/07/678/

 

 

构建和运维HBase集群是一个非常有挑战性的工作。HBase凭借其在海量数据的良好的扩展性和高效的读写能力,受到越来越多公司的重视。

在公司里,HBase越来越受欢迎。希望通过HBase读写数据的产品越来越多,在兴奋之余,头疼的问题也来了。毕竟,作为线上的产品,我们不希望过多人随意的访问,会照成很多潜在的风险,比如误删,误操作。但是,如果所有事情都有管理员处理,沟通的代价就会很高,而且管理员不得不处理一些Application相关的工作,导致管理低效。访问控制,就成为了一个很重要的需求。

此外,现在部署在云计算公有云的HBase集群也在日益增多,如果没有访问控制,存储其中的数据可以随意删改,对企业而言,也是无法接受的。那么HBase 的访问控制就成为了一个迫切紧急的任务。

Apache Hadoop 在0.20版本之后开始添加Kerberos认证技术。然而,直到0.21版本,这项工作仍未结束。因此,在0.22版本之前,这项特性的有效性和稳定性均不成熟。此外,Yahoo! Distribution of Hadoop 的0.20.S版本和Cloudera的第一个稳定的CDH3发布中也会加入这项安全支持。

HBase的访问控制是也是基于Kerberos的,现在,在我们的产品环境中,已经集成了Hadoop和HBase的访问控制功能。在后面的文章里,我将详细阐述HBase访问控制的具体功能和实现机制。供大家参考。

Secure HBase的特征。

1. 和Yahoo!Distribution of Hadoop 一样,基于Kerberos。在我们的环境中,我们同时部署了Secure Hadoop和Secure HBase, 关于Secure Hadoop,可以参考(Hadoop-4487)

2. 实现Coprocessor Framework, 允许HBase 管理员在Regionserver中载入定制的代码,关于Coprocessor,请参考(HBase-2001)

3. 实现了一个AccessController的Coprocessor,在代码中加入了Access Control。请参考(HBase-3025)

4. 支持基于表和column family的访问控制,不支持row级别。

认证机制

认证机制利用了Java的JAAS。 当HBase接受到透过RPC过来的请求时,将调用JAAS的doAs函数执行这个命令。具体的代码变动,可以看下面的代码比较。

 

  1. diff --git a/src/main/java/org/apache/hadoop/hbase/ipc/HBaseServer.java b/src/main/java/org/apache/hadoop/hbase/ipc/HBaseServer.java  
  2.   
  3. index 40473e3..2dec6b5 100644  
  4.   
  5. --- a/src/main/java/org/apache/hadoop/hbase/ipc/HBaseServer.java  
  6.   
  7. +++ b/src/main/java/org/apache/hadoop/hbase/ipc/HBaseServer.java  
  8.   
  9. @@ -58,6 +58,7 @@  
  10.   
  11. import java.util.concurrent.ConcurrentHashMap;  
  12.   
  13. import java.util.concurrent.ExecutorService;  
  14.   
  15. import java.util.concurrent.Executors;  
  16.   
  17. import java.util.concurrent.LinkedBlockingQueue;  
  18.   
  19. +import java.security.PrivilegedExceptionAction;  
  20.   
  21. import org.apache.commons.logging.Log;  
  22.   
  23. import org.apache.commons.logging.LogFactory;  
  24.   
  25. @@ -1060,7 +1061,7 @@ public abstract class HBaseServer implements RpcServer {  
  26.   
  27. ByteArrayOutputStream buf = new ByteArrayOutputStream(buffersize);  
  28.   
  29. while (running) {  
  30.   
  31. try {  
  32.   
  33. -          Call call = myCallQueue.take(); // pop the queue; maybe blocked here  
  34.   
  35. +          final Call call = myCallQueue.take(); // pop the queue; maybe blocked here  
  36.   
  37. if (LOG.isDebugEnabled())  
  38.   
  39. LOG.debug(getName() + ": has #" + call.id + " from " +  
  40.   
  41. @@ -1073,7 +1074,32 @@ public abstract class HBaseServer implements RpcServer {  
  42.   
  43. CurCall.set(call);  
  44.   
  45. // TODO: simple auth -- store user in context  
  46.   
  47. try {  
  48.   
  49. -            value = call(call.connection.protocol, call.param, call.timestamp);             // make the call  
  50.   
  51. +            Object obj = (Writable)call.connection.ticket.doAs(new PrivilegedExceptionAction<Object>() {  
  52.   
  53. +                public Object run() throws IOException, InterruptedException {  
  54.   
  55. +                  return call(call.connection.protocol, call.param,  
  56.   
  57. +                              call.timestamp);  
  58.   
  59. +                }  
  60.   
  61. +              });  
  62.   
  63. +  
  64.   
  65. +            if (obj instanceof Writable) {  
  66.   
  67. +              value = (Writable)obj;  
  68.   
  69. +            }  
  70.   
  71. +            else {  
  72.   
  73. +              // doAs() return value could not be converted to Writable:  
  74.   
  75. +              // probably should throw an exception here in that case.  
  76.   
  77. +            }  
  78.   
  79. catch (Throwable e) {  
  80.   
  81. LOG.debug(getName()+", call "+call+": error: " + e, e);  
  82.   
  83. errorClass = e.getClass().getName();  

 

权限和授权

HBase的权限定义比较简单。比如我们不会区分是insert还是update,而统一是Put。

HBase的权限可以分为基于行和基于schema。基于行包括对表的读写。基于schema的包括了增加一列或者增加一个family,删除表之类的操作。前者是在Regionserver中运行,但是后者是在master中执行。在master中运行的不会在Coprocessor Framework中运行,但是我们上面的代码将运行在master和Regionserver中,所以不论用户是执行基于行的操作还是基于schema的操作,都可以实现访问控制。

表的所属权

所属权定义在表的TableDescriptor,对应于 .META. 中的regioninfo:owner这一栏。表的所有者有权利读写表和删除表。任何人有权利读 –ROOT— 和 .META.  , 但只有HBase 管理员修改表的所属权属性。比如,如果有一个客户端希望能读表的信息,但是你担心他会误删表的数据,就可以建立一个对某个表只读权限的用户。

Coprocessor

Coprocessor已经融合到了HBase 0.90 的版本中。如果enable了Coprocessor,RegionServer会从配置文件hbase-site.xml 中读取Coprocessor的配置。下面是Access Control coprocessor的配置片段。

<property>

<name>hbase.coprocessor.default.classes</name>

<value>org.apache.hadoop.hbase.security.rbac.AccessController</value>

</property>

Coprocessor的接口定义了一组pre- 和post- 的函数,每个对应于客户端的一个request。

比如,客户端的函数Get(),在Coprocessor中就会定义preGet()和postGet(), preX()和postX()会抛出CoprocessorException。可以定义任意数量的Coprocessor。其实这个和动态代理类似。如图,定义了三个preGet()和三个postGet(),如果遇到异常,异常将直接抛给用户终止后面的进行。

利用pre-X方法,我们可以实现访问控制。比如,如果一个客户端发送Put(T,Row)到一个Regionserver,Regionserver会首先调用用于认证的Coprocessor函数prePut检测该用户是否对该表有写权限。如果有,则写入,否则,抛出AccessDeniedException异常。

上图是preX和permission的对应关系。

吃外,我们用preX做permission 检测的同时,也使用了两个postX方法——postOpen()和postPut() 来存储Permission信息。

如何存储Permissions

表Table1的Permission会存储在三个地方。

1. Table1的第一个region在 .META.表所在的行

2. Zookeeper中/hbase/acl/table1节点

3. 所有管理table1的RegionServer在内存中的权限镜像。

.META.

我们在.META.上面加了一个colum family,acl:。对于任意一个表T, Permission信息存储在该表在.META.的第一行,存储在acl:U列中(U表示username),值可以是R,W,RW。这是Permission信息存储的原始位置,Zookeeper和regionServer的信息都是从这里拷贝的。当Secure HBase第一次启动的时候,.META. regions 首先被load到RegionServer,之后拷贝到Zookeeper和Regionserver的镜像。当权限被管理员改变,也是先修改.META. 然后到Regionserver 的mirrors。

Zookeeper

Zookeeper在.META和Regionserver镜像中起到一个桥梁的作用。在Zookeeper中,Permission 信息会存放在/hbase/acl/T, 所有含有表T  region的Regionserver都会设置watch来监视Permission信息的改变。

Regionserver的内存镜像

每一个Regionserver都会为他服务的regions维护一个内存权限镜像。镜像的内容来自于拷贝相应Zookeeper节点的Permission信息得到。Zookeeper和Regionserver的镜像之间的一致性是靠Zookeeper Watches保证的。

Zookeeper起的作用

当一个Regionserver打开一个.META. region时,AccessController:postOpen() 扫描出表在.META.中所有的第一行,建立Zookeeper 节点/hbase/acl/T,acl:columns的每行都被拷贝到Zookeeper的节点上。形成一个user=>Permission的映射表。

维护一致性: 从.META.到Zookeeper

当管理员修改了Permission信息时,实际上是对.META.的第一行出发了put操作。这会触发Coprocessor的PostPut 方法。在PostPut里,我们将修改的权限保存到对应的/hbase/acl/T节点中。

维护一致性: 从Zookeeper到Regionserver 权限镜像

下图表示两个Regionserver,每一个都有一个ZKPermissionWatcher,实现了nodeCreated()和nodeChanged()方法。对于每一个watcher 方法,改变对应的Zookeeper节点都会触发Permission镜像的刷新。

注意,Regionserver仅仅使用本地的权限镜像,而不是使用Zookeeper或者.META.来认证客户端的请求。这是处于性能的考虑。但是,如何确保每次都执行正确的认证信息?这要求Regionserver的镜像和.META.中的Permission完全一致。因为表T它的第一个region对应的.META.的那个region被打开之后才能被打开,这就保证了regionserver总是先于任何客户端之前导入Permission信息。

总结

1. META中的acl: 这个family用于存储Permission信息。Zookeeper能够自动快速地将权限的改动更新到本地的权限缓存中。

2. 一个用户的操作既不需要查询META也不需要查询Zookeeper。最新的信息能从本地缓存中获得。

3.  修改权限不需要disable表,对表权限的更新将立即并自动地通过Zookeeper从META表更新到regionserver

实例分析

现在,我们来看一个权限处理的例子

S代表处理的Regionserver, 而U代表用户。

在第三步,doAs()将HBase的系统用户转化为一个普通的U用户,类似unix的sudo su,

第五步,如果认证失败,就会返回AccessDeniedException。

reference:
http://hbaseblog.com/2010/10/11/secure-hbase-access-controls/

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值