前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >ranger插件开发(下)

ranger插件开发(下)

作者头像
陈猿解码
发布2023-02-28 14:43:59
6260
发布2023-02-28 14:43:59
举报
文章被收录于专栏:陈猿解码

要在ranger中支持一个新的服务模块的权限校验,可以分为两部分,一部分是在ranger中添加一个服务模块,然后添加该服务的实例并配置对应的权限策略;另一部分就是在真正的服务端开发插件,从ranger中拉取权限策略,并提供接口完成真正的鉴权动作。

本文就来聊一聊相关的知识。

【在ranger中添加服务模块】


在ranger中添加服务模块可以分为3个步骤:

1. 编写服务定义配置文件

具体怎么编写这个配置文件,可以参考上篇文章,里面详细介绍了配置文件中的各个字段。

配置文件通常命名为"ranger-servicedef-xxx.json",其中xxx为服务的名字,即和配置文件中的name字段的值保持一致。

另外,该文件需存放到agents-common/src/main/resources/service-defs目录下。

2. 编写ranger中的服务实现类

还记得在服务定义配置文件中有个字段为implClass吗,它的值为类的名称。

例如:org.apache.ranger.services.rabbitmq.RangerServiceRabbitmq

每个服务模块都需要有一个对应的实现类。这个实现类通常继承自抽象类RangerBaseService,在构造函数和init方法中,一般都是调用父类的实现。

而两个需要自行实现的方法为:

代码语言:javascript
复制
// 实现对配置文件d的有效性j检查
public abstract Map<String, Object> validateConfig() throws Exception;
// 实现对资源的检索
public abstract List<String> lookupResource(ResourceLookupContext context) throws Exception;

可以根据实际需要完成具体的实现。当然,也可以返回一个空的map或list,即不进行有效性检查和不支持检索。

另外,还有一个可以重写的方法是:

代码语言:javascript
复制
public List<RangerPolicy> getDefaultRangerPolicies() throws Exception

该方法在父类实现中提供了默认的策略。即一旦在ranger的web界面中添加了该服务的一个实例,那么会自动添加默认的策略。

因此,可以在具体实现类中根据需要改写该方法的实现。

3. 加载服务模块

完成前面两步后,在ranger中添加服务的主要工作基本完成,剩下的就是启动初始化加载该服务模块(实例化具体的类对象)使其可以在界面中展示了。

初始化动作是在EmbeddedServiceDefsUtil类中完成的,具体包括:

  • 在静态变量DEFAULT_BOOTSTRAP_SERVICEDEF_LIST中添加服务名 注意:名称要和服务定义配置文件中name的值完全匹配。
  • 添加类成员,并在init方法中完成初始实例化动作。

简单示例代码如下:

代码语言:javascript
复制
public static final string RABBITMQ_IMPL_CLASS_NAME = "rabbitmq";

private RangerServiceDef rabbitmqServiceDef;

public void init(ServiceStore store) {
    ...
    rabbitmqServiceDef = getOrCreateServiceDef(store, RABBITMQ_IMPL_CLASS_NAME);
}

完成上述步骤后,重新编译ranger,然后安装部署启动ranger,在ranger的web界面,就可以看到我们添加的服务模块了。

除了上面的方法,在官网的rest接口文档中,看到还可以通过rest接口添加服务模块。

实测了一下,确实可以成功添加,在ranger的web控制台上也能看到添加的服务模块。但是有一点需要注意:由于服务定义配置文件中需要指明对应的实现类,而如果ranger内部找不到对应的实现类,虽然可以成功添加服务模块,但是在添加服务模块的具体实例时,会因为没有对应的实现类而报错!

一种可行的解决办法是:

仍旧需要完成对应类的实现,并制作相应的jar包,然后将jar包放到ranger服务对应的插件目录中,如下图所示:

此后,再通过rest接口添加服务模块,就不会报错了。

【插件开发】


完成了在ranger中添加模块后,接下来的工作就是编写插件,并嵌入到具体服务中,完成具体的鉴权动作了。

实际上,ranger已经提供了完备的框架,我们只需要简单开发两三个继承类,最终调用指定接口就可以完成整个插件开发了。

在进行开发之前,有必要先了解ranger插件框架中几个核心的类。

  • RangerBasePlugin ranger插件中最核心的类,负责从ranger拉取策略并缓存,同时对外暴露接口完成资源访问的权限校验。
  • RangerAccessResourceImpl 资源的封装类,调用鉴权接口时,需要构造这么一个类,并设置需要鉴权的资源。
  • RangerAccessRequestImpl 资源访问的封装类,内部包含了上面提到的资源封装类,同时还包括访问资源的用户、用户组、角色、访问的类型、客户端IP等信息。最终调用接口进行权限校验时,该类的实例对象需要作为参数被传入。
  • RangerDefaultAuditHandler 审计日志的处理类,所有的权限校验动作都可以作为审计日志被记录下来

有了上面的大概认识后,对于插件开发,我们只需要做这么几个动作:

1. 编写一个继承RangerBasePlugin的类

通常,只需要实现构造函数和init方法即可。

在构造函数中,会调用父类的构造函数,这里需要正确传入服务的类型,也就是服务定义配置文件中name字段的值。

另外就是,在init方法中,调用父类的init方法,这个时候在插件内部会触发启动线程,向ranger注册并定时从ranger拉取策略。

2. 编写粘合类

这是一个承上启下的类,也就是在具体服务内部先调用该类完成初始化动作,此后调用该类的接口进行权限校验。

而在这个类的内部,将上面RangerBasePlugin的继承类对象作为类成员,初始化时调用RangerBasePlugin继承类对象的init方法,完成插件的初始化动作。

而对外提供的的鉴权接口中,则对需要权限校验的资源、访问动作、访问的用户、用户组等信息封装成RangerAccessRequestImpl类对象,最后调用RangerBasePlugin继承类对象的isAccessAllowed方法,完成权限校验动作。

3. 编写一个继承RangerDefaultAuditHandler的类(可选)

一个简单的示例代码:

代码语言:javascript
复制
public class RangerRabbitmqAuthorizer {
    private static volatile RangerRabbitmqPlugin rmqPlugin = null;
    public RangerRabbitmqAuthorizer () {}
    public void init() {
        RangerRabbitmqPlugin plugin = rmqPlugin;
        if(plugin == null) {
            synchronized(RangerRabbitmqAuthorizer.class) {
                plugin = rmqPlugin;
                if(plugin==null) {
                    plugin = new RangerRabbitmqPlugin();
                    plugin.init();
                    rmqPlugin = plugin;
                }
            }
        }
    }
    
    public boolean checkPermission(String userName, String userGroups, string clientIp, String accessType, String resourceType, String resourceName) {
        Date eventTime = new Date();
        RangerAccessRequestImpl rangerRequest = new RangerAccessRequestImpl();
        rangerRequest.setUser(userName);
        rangerRequest.setUserGroups(Sets.newHashSet(userGroups));
        rangerRequest.setClientIPAddress(clientIp);
        rangerRequest.setAccessTime(eventTime);
        
        String action = accessType;
        RangerAccessResourceImpl rangerResource = new RangerAccessResourceImpl();
        rangerRequest.setResource(rangerResource);
        rangerRequest.setAccessType(accessType);
        rangerRequest.setAction(action);
        rangerRequest.setRequestData(resourceName);
        
        rangerResource.setValue(resourceType, resourceName);
        
        boolean retValue = false;
        try {
            RangerAccessResult result = rmqPlugin.isAccessAllowed(rangerRequest);
            if(result == null) {
                // Ranger plugin return null, returning false
            } else {
                retValue = result.getIsAllowed();
            }
        } catch (Throwable t) {
        } finally {
        }
        return retValue;
    }
    
    public static void main(String[] args) {
        RangerRabbitmqAuthorizer rmqAuthorizer = new RangerRabbitmqAuthorizer();
        rmqAuthorizer.init();
        
        Boolean isAllowed = rmqAuthorizer.checkPermission(
            "hncscwc",  // 资源访问的用户名
            "hncscwc",  // 资源访问的用户组
            "127.0.0.1",  // 资源访问的客户端IP
            "consume",  // 资源访问的类型(对队列j进行消费)
            "queue",  // 资源访问的类型
            "test"  // 具体访问的队列名称
    }
}

class RangerRabbitmqPlugin extends RangerBasePlugin {
    public RangerRabbitmqPlugin() {
        super("rabbitmq", "rabbitmq");
    }
    
    public void init() {
        super.init();
        RangerDefaultAuditHandler auditHandler = new RangerDefaultAuditHandler(getConfig());
        super.setResultProcessor(auditHandler);
    }
}

来小结一下:

本文主要介绍了在ranger中支持一个新服务(插件开发)权限校验的步骤和流程,最后也给出了简单示例代码。未提到的一部分是整个工程的设置、编译打包的一些细节,还包括插件端配置文件的一些内容,这一块相对比较简单,也可以直接参考源码中其他模块的实现。

好了,本文就介绍到这里,原创不易,点赞,在看,分享是最好的支持, 谢谢~

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-09-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 陈猿解码 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档