ranger插件开发(下)

本文详细介绍了如何在Apache Ranger中添加新的服务模块以支持权限校验,包括编写服务定义配置文件、实现服务类、加载服务模块以及开发服务端鉴权插件。通过这些步骤,可以在Ranger的Web界面中看到新增的服务,并实现服务的权限管理功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

要在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方法中,一般都是调用父类的实现。

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

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

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

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

public List<RangerPolicy> getDefaultRangerPolicies() throws Exception

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

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

3. 加载服务模块

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

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

  • 在静态变量DEFAULT_BOOTSTRAP_SERVICEDEF_LIST中添加服务名

    注意:名称要和服务定义配置文件中name的值完全匹配。

  • 添加类成员,并在init方法中完成初始实例化动作。

简单示例代码如下:

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的类(可选)

一个简单的示例代码:

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值