HBase的权限控制

来源:互联网 发布:悠悠球雪鳞锋淘宝 编辑:程序博客网 时间:2024/06/03 17:02

HBase自带的权限管理工具:

HBase的权限管理包括两个部分,分别是Authentication&Authorization


Authentication:针对某host是否有权成为集群的regionserver或者client端;

Authorization:是针对client端对集群数据的读写等权限;

其中Authentication由kerberos提供解决方案,用户级别的Authorization由ACL模块控制


(一)、Authentication——


kerberos的基本原理:


kerberos实现了机器级别的安全认证,包括服务器到服务器的认证,确保不会有其他机器冒充regionserver。kerberos中包含一个中心服务器(KDC),KDC中有数据库,由管理员将集群中确定的机器手动添加到上述数据库中,在KDC上会分别产生主机与各节点的keytab,并将这些keytab分发到对应的节点上。通过这些keytab文件,节点可以从KDC上获得与目标节点通信的秘钥,进而被目标节点所认证,从而才能提供相应的服务;


HBase的kerberos安装流程简述:


1、配置kerberos server和kerberos client

kerberos server既KDC,kerberos client是我们集群节点;

这一步安装kerberos的基本组件,包括krb5-libs、krb5-server等,并初始化kerberos数据库,添加admin用户等等;


2、配置hadoop

创建keytab并修改core-site.xml、hadoop-env.sh、hdfs-site.xml,主要是添加keytab文件的位置信息,并使能kerberos控制;


3、配置zookeeper

创建keytab,修改java.env,修改zoo.cfg


4、配置HBase

创建keytab,修改hbase-env.sh/hbase-site.xml等等

hbase-site.xml中主要是添加下述配置:

<property><name>hbase.security.authentication</name><value>kerberos</value></property>

添加了如上配置,便使能了hbase的权限控制,此时只有经过了认证的服务器,才能够成功向master申报,所以如果host没有配置kerberos时,贸然添加上述配置可能会导致regionserver进程难以启动;


总结:

1、kerberos提供了机器级别的安全认证,但调研及尝试安装下来之后,觉得首先kerberos的安装流程复杂,如果是建设新集群,可以考虑使用kerberos,但当前集群已经存在上百个业务在时时跑,复杂的安装流程势必会造成业务中断,不是业务方所能接受的;


2、kerberos对应用访问集群的性能有一定影响,加了kerberos认证后,client端再想访问集群,需要先两次访问KDC,第一次访问向KDC证明我是我自己,第二次访问时生成services端和client端之间的session key用于service端对client的身份鉴别,一次用户请求的访问路径变长,必然有性能损耗;


3、使用kerberos,也添加了外部需要维护的依赖,包括KDC&数据库DB等等

(二)Authorization


a、使用方式:


使能hbase的ACL控制比较简单,只需要在集群的各个节点hbase-site.xml添加如下配置即可

<property>       <name>hbase.security.authorization</name>       <value>true</value></property><property>       <name>hbase.superuser</name>       <value>默认是hbase的安装用户</value></property><property>       <name>hbase.coprocessor.master.classes</name>       <value>org.apache.hadoop.hbase.security.access.AccessController</value></property><property>       <name>hbase.coprocessor.region.class</name>       <value>org.apache.hadoop.hbase.security.token.TokenProvider,org.apache.hadoop.hbase.security.access.AccessController</value></property>

其中,hbase.superuser是超级用户,可以不配置,不配置时默认是hbase的安装用户,超级用户用于给其它用户添加或者收回相应权限;


AccessController类是hbase权限控制的主入口类,关于hbase权限控制的机理在下文中有简述;


b、Authorization中可认证的权限都包括了哪些:

R——范围内可读;

W——范围内可写;

X——可以执行授权范围内埋设的coprocessor;

C——范围内可执行creat操作,如scope指定为namespace,则C是指ns之内可以创建表,如scope指定为table,则C是指可对table执行create snapshot操作;

A——范围内可以执行admin操作,如果你的scope是namespace,那么admin操作是指balance、assign、move、merge等,如果你的scope是table,那么admin操作是指alter操作,即修改表属性;


需要注意的是:

1、表的disable权限由’C’认证控制

2、表数据的删除权限由’W’认证控制


c、上面的“scope”都包含了哪些维度:


hbase包含了如下几种可定义的scope维度:

superuser——超级管理员,可执行针对集群的任意操作,一般为集群的安装者,superuser也可以由用户添加,即hbase.superuser配置;

global——全局scope,可操作所有tables;

namespace——可操作指定namespace内的scope,我们的namespace只有一个,就是default;

table——可操作指定的table;

ColumnFamily——可操作指定的columnFamily;

cell——具体到列元的scope指定;

e、hbase权限控制的实现原理:


几个实现要点:


AccessContoller实现了CoprocessorService接口,并继承了Observer类,这说明AccessContoller是一个observer endpoint,即hbase里的coprocessor插件。


AccessContoller作为observer覆写了postStartMaster方法,用于在master启动完成之后调createACLTable来创建acl table,acl table是hbase的system tables之一,用于持久化保存所有的权限信息。acl table和用户表一样都分region存储在regionserver上。


RegionServer启动之后,会逐一open各regionserver上的regions,AccessController同样覆写了postOpen函数,postOpen在region被open之后触发,如果打开的是属于acl table的region,AccessController会遍历该region中的所有内容,load到AccessController维护的一个map中,与此同时,这些数据同时被序列化之后写到zk上,关键代码如下:

void initialize(RegionCoprocessorEnvironment e) throws IOException {     final Region region = e.getRegion();     Configuration conf = e.getConfiguration();     Map<byte[], ListMulitmap<String, TablePermission>> tables = AccessControlLists.loadAll(region);     for (Map.Entry<byte[], ListMulitmap<String, TablePermission>> t : tables.entrySet()) {           byte[] entry = t.getKey();           ListMultimap<String, TablePermission> perms = t.getValue();           byte[] serialized = AccessControlLists.writePermissionAsBytes(perms, conf);           this.authManager.getZKPermissionWatcher().writeToZookeeper(entry,serialized);     }           initialized=true;}

acl region被加载到AccessContoller的map之后,一个AccessContoller才真正初始化完成。


AccessContoller还实现了coprocessorService接口,这是一个可序列化的service接口,coprocessorService在coprocessor被加载到host的时候实例化,具体实现在coprocessorHost的loadInstance中:

public E loadInstance(Class<?> implClass, int priority, Configuration conf)                 throws IOException {     // create the instance     Coprocessor impl;     Object o = null;     try {       o = implClass.newInstance();       impl = (Coprocessor)o;     } catch (InstantiationException e) {       throw new IOException(e);     } catch (IllegalAccessException e) {       throw new IOException(e);     }     // create the environment     E env = createEnvironment(implClass, impl, priority, loadSequence.incrementAndGet(), conf);     if (env instanceof Environment) {       ((Environment)env).startup();     }     coprocessorNames.add(implClass.getName());     return env; } 

createEnvironment中会将各个coprocessorService实例register到masterService上,而在AccessControlService反射出来的类所需要实现的接口,就是shell中hbase权限相关的四个命令:

grant、revoke、getUserPermissions、checkPermissions

其中grant用于授权操作,revoke用于收回用户权限,其余两个是查询操作,以grant接口为例,其实现代码如下所示:

public void grant(RpcController controller,                    AccessControlProtos.GrantRequest request,                    RpcCallback<AccessControlProtos.GrantResponse> done) {    final UserPermission perm = ProtobufUtil.toUserPermission(request.getUserPermission());    AccessControlProtos.GrantResponse response = null;    try {      // verify it's only running at .acl.      if (aclRegion) {        if (!initialized) {          throw new CoprocessorException("AccessController not yet initialized");        }        //用户鉴权        switch(request.getUserPermission().getPermission().getType()) {          case Global :          case Table :            requirePermission("grant", perm.getTableName(), perm.getFamily(),              perm.getQualifier(), Action.ADMIN);            break;          case Namespace :            requireGlobalPermission("grant", Action.ADMIN, perm.getNamespace());           break;        }        //执行权限添加,向acl table新写入一条记录        User.runAsLoginUser(new PrivilegedExceptionAction<Void>() {          @Override          public Void run() throws Exception {            AccessControlLists.addUserPermission(regionEnv.getConfiguration(), perm);            return null;          }        });      } else {        throw new CoprocessorException(AccessController.class, "This method "            + "can only execute at " + AccessControlLists.ACL_TABLE_NAME + " table.");      }      response = AccessControlProtos.GrantResponse.getDefaultInstance();    } catch (IOException ioe) {      ResponseConverter.setControllerException(controller, ioe);    }    //执行回调操作    done.run(response);}

在AccessController保存权限信息的map中,维护了一个ZKPermissionWatcher类型的变量,该变量继承了zookeeperListener,可见该变量可用于监听zk节点上的变化,前面说过acl table的信息会序列化到zk上,如果用户修改acl table的内容,这些修改会同步到zk到,反映为zk节点的变化,zkPermissionWatcher监听zk节点的变化,同步修改AccessController中map的内容,实现了内存、zk与acl table三者之间数据的一致。


下面讲讲zookeeperListener的初始化方式,AccessController在start的时候,会通过env获取该服务上的zookeeperWatcher,并将zkwatcher和config一起构造TableAuthManager,在TableAuthManager的构造函数中,使用上述两个参数和TableAuthManager自身构造成员变量ZKPermissionWatcher,并将之start,start函数的关键代码如下:

public void start() throws KeeperException {       try {           watcher.registerListener(this);           if (ZKUtil.watchAndCheckExists(watcher, aclZNode)) {                List<ZKUtil.NodeAndData> existing =                         ZKUtil.getchildDataAndWatchForNewChildren(watcher, aclZNode);           if (existing != null) {                 refreshNodes(existing);           }          }       } finally {           initialize.countDown();       }}
需要注意的是这里的initialize变量,它是一个CountDownLatch,用于确保ZKPermissionWatcher已经初始化完成并成功start,initialize被初始化为1,在start结束后置为0,此时阻塞在initialize await上的nodeCreated、nodeDelete、nodeDataChanged等方法能够进行下去,以监听zk节点的变化,并将zk上的变化同步更新到本地的TableAuthManager中,即集群各节点的内存之中。


总而言之,hbase acl权限的控制是通过hbase自身系统表acl table做持久化,具体发挥作用则是由AccessControler加载进内存,以便于权限的查询结果能够直接从内存返回,减少权限认证对数据访问性能的影响,而保证table和内存内容一致性则是由zookeeper来实现。


f、hbase自带权限的几个注意点(坑点


1)权限内容通过zk同步,可能会导致部分节点不能准确同步到最新的权限内容,造成不一致,hbase2.0中的procedure V2解决了上述问题,proceduer V2引入了两阶段提交的框架,只有所有节点的更新都成功之后,才确认此次更新成功,否则回滚;


2)生效不平滑,acl生效之后除superuser之外的用户默认不具有任何权限,而新用户授权操作grant只有在acl生效之后才能使用,这造成的问题是,如果在时时有用户读写数据的hbase集群上生效acl,会造成集群在一段时间对所有用户停服。


2、apache ranger的权限控制


a)apache ranger的基本原理:


Apache Ranger也是以coprocessor的形式集成到HBase中,由Ranger Admin管理访问策略,具体的权限策略存储在外部DB中,Ranger插件定期轮询Admin以更新策略到本地,并根据策略信息进行用户权限的判定,其中同样包含一个super用户,可以管理所有策略。插件的ranger web和Ranger Plugin,与Admin之间的通信是基于Http的Restful来实现。


关于Ranger插件的具体机制原理和初始化流程,本文不再详述,只列出它与HBase自带权限控制策略的比较:


1、ranger将权限策略存储于外部DB,由第三方角色Ranger Admin管理,HBase则存储于自身的系统表acl table中,由superuser(HBase的安装用户)管理;

2、新权限的更新方面,ranger是由编译到HBase上的插件Plugin,定期向admin发送restfule请求,以拉取最新的policy,而HBase的自身实现是依靠zk做集群各节点权限信息同步一致;

3、权限的执行,两者相同,都是依赖coprocessor在client端行为的前后埋hook,用户权限的查询都是从内存中获得,ranger是从Plugin中维护的内存,而hbase自带的是从AccessController中维护的内存;

4、权限管理的粒度,两者相似,都可以管理到namespace/table/column family/cell这四个粒度,具体的权限内容,同样包括了get&scan,写,create table等等;

5、关于grant、revoke等操作,ranger掩盖了hbase中的实现,hbase中的不再生效,想要操作从ranger admin入口进行操作;


总结:


对于apache ranger,一需要外部部署DB,solr等外部系统,增加了第三方系统就增加了维护的难度,比如ranger的DB挂掉,那么同样会影响到hbase,造成hbase的数据无法访问;

二、是DB容易成为该系统的单点,因为所有的策略更新都要访问该DB;

三、权限的生效周期不如hbase自带策略及时;


原创粉丝点击