Apache Ranger:统一授权管理框架
by 伊布
前一篇文章介绍了hive的授权模型和spark支持hive的现状,可以看到目前授权管理各自为政:HDFS,hive,yarn,storm等都有自己的授权模型,需要到具体产品下进行修改,比较分散,不利于统一管理,需要有一个集中控制的工具(更准确的应该叫做框架)
目前已有的统一授权管理的开源框架为Ranger和Sentry。前者由hortonworks主推,从目前的情况来看其功能更为全面(例如可以支持hive的列级授权,支持审计Audit);后者由Cloudera开发,可能更有后劲。另外Cloudera在酝酿一个安全平台。
其他还有knox安全网关这种剑走偏锋的工具,简要说明可以参见五种安全工具对比。 这里简要介绍下Ranger的功能,以及其大致机制。
1、功能
我用的是Hortonworks的sandbox,略过了ranger的安装部署过程(具体部署可以参考这篇文章,后面有时间还是再做一次部署)。
先介绍几个概念:
- user: Ranger自己管理的用户,分为internal和external,前者为Ranger自己的用户,例如admin;后者为linux或者LDAP的用户,在操作系统/LDAP里新增用户后会同步到Ranger。
- group: Ranger自己管理的用户组,也有内外之分,与user类似,设置与LDAP同步后会将LDAP的组同步过来,该组为外部组;如果是Ranger自己的用户新增的组,则为internal组。
- Service: 即授权管理服务,每个组件可以设置多个Service。
- Policy: 每个Service中可以有多条Policy,组件不同,Policy授权模型不同
支持组件
已经支持的有HDFS/HBASE/HIVE/YARN/KNOX/STORM/SOLR/KAFKA。有的资料上说Ranger后面会支持spark,比较好奇最终会怎么实现。
用户/组管理
Ranger的用户/组的设计跟linux基本一致。Ranger可以把操作系统新增的用户同步到Ranger内。Ranger支持Role,但没有看到完善的RBAC的功能,只有Admin/User两个角色。用户可以属于多个组,但是一旦新建后就不能修改还是挺不好用的。
授权
以Hive为例。
1、编辑Service的属性
也可以删掉新建。默认沙箱里只给ambari-qa授权,不过我这里之前给hive做过授权,所以填了hive。需要保证Hive Service可用。
2、编辑Policy
Ranger支持的权限比较细,授权对象可以是DB、表、列、UDF,权限类型包括select/update/create/drop/alter/index等等。 可以选择对某一用户授权,也可以对某一用户组授权。我这里给hive授予了一个表的所有权限。
3、验证
在beeline中使用hive连上hive服务,验证其权限,略。
注意,不经过Ranger,用户A直接连接到hive上向用户B授权,也是可以的;插件会将该配置向上同步给Ranger,因此最终也可以生效。
Hive跟HDFS不一样。HDFS可以设置二级认证,先Ranger如果失败再走一次HDFS,Hive应该只走Ranger。
下面是最终的Policy,第三条即为向上同步的grant(grant select on xademo.table1 to user xxx;)。
审计
Ranger提供4个方面的审计:
- Access:记录各个服务的接入信息
- Admin:记录Ranger的管理信息,例如新建了service,新建了用户等
- Login Sessions:记录用户登录Ranger的信息,例如用户如果包里破解ranger web UI的登录密码会留下记录
- Plugins:记录各个Plugin的同步信息
Ranger不提供认证的功能,需要搭配Kerbose。
2、机制
分为如下几部分:
- ranger-admin:提供web server以及Ranger管理
- ranger-usersync:与linux或LDAT同步用户。注意这个过程有个时间差,最快1分钟。
- ranger-xxx-plugin为针对各组件的插件。
组件plugin
Ranger会将各个组件的plugin编译成jar包,并将jar包配置文件拷贝到对应的组件。以hdfs为例,插件enable的时候,会将rangerplugin.jar拷贝的hadoop的lib中,将ranger*.xml拷贝到./etc/hadoop/中,并修改hdfs-site.xml,增加授权provider:
<property>
<name>dfs.namenode.inode.attributes.provider.class</name>
<value>org.apache.ranger.authorization.hadoop.RangerHdfsAuthorizer</value>
</property>
RangerHdfsAuthorizer即为权限检查的类,作为一个钩子,可以截取权限请求以做鉴权。不同的组件,使用对应组件的鉴权模型。
官方的自定义plugin的编码指南在这里,其中最关键的是定义鉴权模型,例如hive的这个:
{
"id":3,
"name": "hive",
"implClass": "org.apache.ranger.services.hive.RangerServiceHive",
"label": "Hive Server2",
"description": "Hive Server2",
"guid": "3e1afb5a-184a-4e82-9d9c-87a5cacc243c",
"resources":
[
{
"itemId": 1,
"name": "database",
"type": "string",
...
"matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher",
"matcherOptions": { "wildCard":true, "ignoreCase":true },
...
},
{
"itemId": 2,
"name": "table",
"type": "string",
"level": 20,
"parent": "database",
...
},
{
"itemId": 3,
"name": "udf",
"type": "string",
"level": 20,
"parent": "database",
...
},
{
"itemId": 4,
"name": "column",
"type": "string",
"level": 30,
"parent": "table",
...
}
],
"accessTypes":
[
{
"itemId": 1,
"name": "select",
"label": "select"
},
{
"itemId": 2,
"name": "update",
"label": "update"
},
{
"itemId": 3,
"name": "create",
"label": "Create"
},
...
{
"itemId": 8,
"name": "all",
"label": "All",
"impliedGrants":
[
"select",
"update",
"create",
"drop",
"alter",
"index",
"lock"
]
}
],
"configs":
[
{
"itemId": 1,
"name": "username",
"type": "string",
...
},
{
"itemId": 2,
"name": "password",
"type": "password",
...
},
{
"itemId": 3,
"name": "jdbc.driverClassName",
...
"defaultValue": "org.apache.hive.jdbc.HiveDriver"
},
{
"itemId": 4,
"name": "jdbc.url",
"type": "string",
...
}
}
各个组件的定义方式基本是按照资源、访问类型、配置等几个方面来定义的,hive的相对复杂,像hdfs就比较简单,只有1个资源(路径),3种访问类型(rwx)。从0.5开始Ranger支持stack-model,只要按照这个套路来定义自定义插件鉴权,就可以做到不需要修改Ranger自己的代码。官方以YARN为例做了编码说明,还是比较清晰的,就不费事翻译了,对照源码走读下还比较容易懂。 我的障碍是不管yarn还是hdfs看到鉴权最后都只有这个:
public class RangerYarnAuthorizer extends YarnAuthorizationProvider {
..
@Override
public boolean checkPermission(AccessType accessType, PrivilegedEntity entity, UserGroupInformation ugi) {
RangerYarnPlugin plugin = yarnPlugin;
RangerAccessResult result = null;
if(plugin != null) {
..
result = plugin.isAccessAllowed(request, auditHandler);
}
而plugin是基于RangerBasePlugin的,isAccessAllowed也是父类的方法,怎么做到不同的组件用同一个方法的呢?其实,对于Ranger来说它看到的只有资源和访问请求,最多资源有层级关系,访问请求有交并,完全可以忽略实际的组件抽象出来一个统一的鉴权方式的。核心实现应该比较有趣,有机会应该仔细拜读一下。
当然了,最关键的是组件要有一套自定义鉴权的机制,目前spark sql的鉴权也许只能从hdfs和yarn来做数据隔离和资源隔离了(求打脸)。
参考资料: Ranger官方
Subscribe via RSS