ES插件代码的执行权限问题

一、问题描述

es的ik插件需要使用jdbc访问数据库,所以需要在plugin-security.policy里配置SocketPermission,但是配置好并重启es却依然出现了下列错误:

Caused by: java.security.AccessControlException: access denied ("java.net.SocketPermission" "172.16.20.213:3306" "connect,resolve")
  at java.security.AccessControlContext.checkPermission(AccessControlContext.java:472) ~[?:?]
  at java.security.AccessController.checkPermission(AccessController.java:1036) ~[?:?]
  at java.lang.SecurityManager.checkPermission(SecurityManager.java:408) ~[?:?]
  at java.lang.SecurityManager.checkConnect(SecurityManager.java:910) ~[?:?]
  at java.net.Socket.connect(Socket.java:599) ~[?:?]
  at com.mysql.jdbc.StandardSocketFactory.connect(StandardSocketFactory.java:213) ~[mysql-connector-java-5.1.34.jar:5.1.34]

看样子配置是没有起作用,多次重启后还是这个错误,在网上搜索相关解决方案,临时在es自带的jdk里修改jdk/conf/security/java.policy后才解决。

二、原因分析

可能的原因:

  • es读取的插件权限策略不适用于插件的依赖包?
    • 依赖包里有httpclient依赖包,且网络请求都正常,不可能只针对jdbc做特殊限制
    • 查看权限校验的相关代码得知,权限策略适用于本插件目录下的所有jar包,所以排除此猜测
  • mysql的依赖包不在本插件目录下,导致权限策略没加载上?
    • 仔细查找jdbc的依赖包,在本插件目录下确实不存在,最后发现放在了es的lib目录下(官方安装包里并没有此JDBC依赖),虽然启动时不会报ClassNotFoundException异常,但是配置的权限却没有赋给此jar包,最终出现在jdk里配置才有效的错觉。

ES插件的权限配置及权限校验的大致流程:

  • 首先在org.elasticsearch.bootstrap.Bootstrap的setup方法里会调用org.elasticsearch.bootstrap.Security.configure方法
  • 实例化ESPolicy替换Java的安全策略。过程中调用getPluginAndModulePermissions方法获取各插件和模块中jar包的访问策略,最终ESPolicy.plugins里存储的KV:<插件或模块目录下的每个Jar包路径, Jar包所属插件或模块目录下配置的策略>
  • 运行时会通过ESPolicy.implies方法校验目标代码是否有权限,源码如下:
// 代码位置:org.elasticsearch.bootstrap.ESPolicy
public boolean implies(ProtectionDomain domain, Permission permission) {
    CodeSource codeSource = domain.getCodeSource();
    // codesource can be null when reducing privileges via doPrivileged()
    if (codeSource == null) {
        return false;
    }

    URL location = codeSource.getLocation();
    // https://bugs.openjdk.java.net/browse/JDK-8129972
    if (location != null) {
        // run scripts with limited permissions
        if (BootstrapInfo.UNTRUSTED_CODEBASE.equals(location.getFile())) {
            return untrusted.implies(domain, permission);
        }
        // plugins已经保存了每个Jar包路径对应的Policy
        // 这里根据目标代码所属的Jar包路径,找到对应的Policy进行权限校验
        Policy plugin = plugins.get(location.getFile());
        if (plugin != null && plugin.implies(domain, permission)) {
            return true;
        }
    }

    // 省略后续代码片段...
}

三、解决及总结

最终解决方式:

  1. 把ES_HOME下lib里的JDBC移动到当前插件目录下
  2. 还原在jdk里配置的访问策略(按需在各自模块中配置权限更安全)
  3. 重启ES后,问题解决

总结:
由于ES启动后在程序里设置了自定义的Java权限策略,所以在各插件里必须配置用到的权限。JDBC的网络权限配置不生效的原因是没有按规范把JDBC的jar包放在插件目录下,导致JDBC的访问策略为空,最终在运行时报无权限的错误。所以在未知影响范围的情况下,禁止往ES的lib目录下放依赖Jar包,避免Jar包冲突和代码权限等问题。

posted @ 2021-10-27 18:03  爱定小闹钟  阅读(693)  评论(0编辑  收藏  举报