使用TransportClient客户端通过Kerberos方式连接华为ES

173 阅读4分钟

参数

ES版本:7.10.2

客户端:TransportClient

厂商:华为

提示:因为时间因素,没有解决使用TransportClient客户端原生方式连接es,以下方式依靠华为提供API,但不影响原有代码,以及Client操作

起因

由于一些因素,选择了华为的es云服务,es目前可以不会引起版权的版本为7.10.2,也是由于项目升级原因,没有更换客户端。

在大数据场景,多数使用的安全验证为Kerberos,这个验证方式在大数据方面比较常见,但是对于寻常后端开发比较少见,并且TransportClient在es7.x中也被废弃,所以,相关参考文章较少,在切换验证方式的时候遇到较多问题。

正文

快速开始

配置maven

  1. 使用前请确保您已安装JDK 1.8及以上版本和Maven 3.0及以上版本。

  2. 配置Maven配置文件。

    • 如果想要覆盖Maven配置文件,在华为开源镜像站(mirrors.huaweicloud.com/),选择“华为SDK > HuaweiCloud SDK”,下载华为开源镜像站提供的“settings.xml”文件,覆盖至“ <本地Maven安装目录> /conf/settings.xml”文件即可。

    • 如果不想覆盖Maven配置文件,可以参考以下方法手动修改“settings.xml”配置文件或者组件样例工程中的“pom.xml”文件,配置镜像仓地址。

      • 配置方法一:修改“settings.xml”配置文件。

        手动在“settings.xml”配置文件的“mirrors”节点中添加以下开源镜像仓地址:

        <mirror>
            <id>repo2</id>
            <mirrorOf>central</mirrorOf>
            <url>https://repo1.maven.org/maven2/</url>
        </mirror>
        

        在“settings.xml”配置文件的“profiles”节点中添加以下镜像仓地址:

        <profile>
            <id>huaweicloudsdk</id>
            <repositories>
                <repository>
                    <id>huaweicloudsdk</id>
                    <url>https://repo.huaweicloud.com/repository/maven/huaweicloudsdk/</url>
                    <releases><enabled>true</enabled></releases>
                    <snapshots><enabled>true</enabled></snapshots>
                </repository>
            </repositories>
        </profile>
        

        在“settings.xml”配置文件的“activeProfiles”节点中添加如下profile地址:

        <activeProfile>huaweicloudsdk</activeProfile>
        

华为样例工程获取

github.com/huaweicloud…

华为官方提供的样例,对于快速开发还需要进一步修改

核心类

LoadProperties加载transport客户端配置文件,直接将类考入项目

import com.huawei.fusioninsight.elasticsearch.transport.common.Configuration;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.common.transport.TransportAddress;
import org.springframework.boot.system.ApplicationHome;
​
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.URL;
import java.net.URLDecoder;
import java.net.UnknownHostException;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
​
/**
 * 加载transport客户端配置文件
 *
 * @since 2020-03-30
 */
public class LoadProperties {
    private static final Logger LOG = LogManager.getLogger(LoadProperties.class);
​
    private static Properties properties = new Properties();
​
    private static final String CONFIGURATION_FILE_NAME = "esParams.properties";
​
    /**
     * 配置文件默认配置路径
     */
    private static final String DEFAULT_CONFIG_PATH = "conf";
​
    private static final String JAR_EXT = ".jar";
​
    private static final String KEY_TAB_PATH = "user.keytab";
​
    private static final String KRB_5_PATH = "krb5.conf";
​
    private static final String CUSTOM_JAAS_PATH = "customJaasPath";
​
    private static String configPath;
​
    /**
     * 加载配置文件
     *
     * @return 配置对下
     * @throws IOException 异常
     */
​
    public static Configuration loadProperties()  {
        configPath=getRootPath() + "conf" + File.separator + CONFIGURATION_FILE_NAME;
        initProperties();
        Configuration configuration = new Configuration();
        configuration.setClusterName(loadClusterName());
        configuration.setTransportAddress(loadTransportAddress());
        configuration.setSecureMode(loadIsSecureMode());
        if (configuration.isSecureMode()) {
            configuration.setPrincipal(loadPrincipal());
            try {
                configuration.setKeyTabPath(loadPath());
                configuration.setKrb5Path(loadPath());
            } catch (IOException e) {
                e.printStackTrace();
            }
​
            configuration.setSslEnabled(loadSslEnabled());
            configuration.setCustomJaasPath(loadCustomJaasPath());
        }
        configuration.setSniff(loadIsSniff());
        LOG.info("configuration: {}", configuration);
​
        return configuration;
    }
​
    public static String getRootPath() {
        ApplicationHome h = new ApplicationHome(LoadProperties.class);
        File jarF = h.getSource();
        return jarF.getParentFile().toString() + File.separator ;
    }
    private static void initProperties() {
        try {
            properties.load(new FileInputStream(new File(configPath)));
        } catch (IOException e) {
            LOG.error("Failed to load properties file, config file path is {}.", configPath, e);
            throw new IllegalArgumentException();
        }
    }
​
    private static void initConfigPath(String[] args) throws IOException {
        // 配置文件路径参数位置
        int configPathArgumentIndex = 0;
        if (args == null || args.length < 1 || args[configPathArgumentIndex] == null
            || args[configPathArgumentIndex].isEmpty()) {
            configPath = getCurrentJarPath() + CONFIGURATION_FILE_NAME;
        } else {
            configPath = args[configPathArgumentIndex];
            File configFile = new File(configPath);
            if (configFile.exists() && configFile.isDirectory()) {
                configPath = configPath + File.separator + CONFIGURATION_FILE_NAME;
            }
        }
    }
​
    /**
     * 读取clusterName参数
     *
     * @return 参数值
     */
    public static String loadClusterName() {
        String clusterName = properties.getProperty("clusterName");
        if (clusterName == null || clusterName.isEmpty()) {
            LOG.error("clusterName is empty, please configure it in config file : {}.", configPath);
            throw new IllegalArgumentException();
        }
        return clusterName;
    }
​
    private static Set<TransportAddress> loadTransportAddress() {
        String serverHosts = properties.getProperty("esServerHosts");
        if (serverHosts == null || serverHosts.isEmpty()) {
            LOG.error("Please configure esServerHosts in conf/{}.", CONFIGURATION_FILE_NAME);
            LOG.error("The format of esServerHosts is ip1:port1,ip2:port2,ipn:portn");
            throw new IllegalArgumentException();
        }
        String[] hosts = serverHosts.split(",");
        Set<TransportAddress> transportAddresses = new HashSet<>(hosts.length);
        for (String host : hosts) {
            String esClientIp = "";
            int port = -1;
            final int portIdx = host.lastIndexOf(":");
            if (portIdx > 0) {
                try {
                    port = Integer.parseInt(host.substring(portIdx + 1));
                } catch (final NumberFormatException ex) {
                    throw new IllegalArgumentException("Invalid HTTP host: " + host);
                }
                esClientIp = host.substring(0, portIdx);
            }
            if (-1 == port) {
                LOG.error("The configuration  esClientIPPort is empty, please configure it in config file : {}.",
                    configPath);
                throw new IllegalArgumentException();
            }
            try {
                if (port % 2 == 0) {
                    LOG.warn("The configuration esClientIPPort may be wrong, please check it in config file : {}.",
                        configPath);
                }
            } catch (NumberFormatException e) {
                LOG.warn("The configuration esClientIPPort may be wrong, please check it in config file : {}.",
                    configPath);
                throw new IllegalArgumentException();
            }
            try {
                transportAddresses.add(new TransportAddress(InetAddress.getByName(esClientIp), port));
            } catch (NumberFormatException | UnknownHostException e) {
                LOG.error("Init esServerHosts occur error : {}.", e.getMessage());
                throw new IllegalArgumentException();
            }
        }
        return transportAddresses;
    }
​
    private static String loadPath() throws IOException {
        String loadedPath = getRootPath() + "conf" + File.separator ;
        if (loadedPath == null || loadedPath.isEmpty()) {
            loadedPath = getCurrentJarPath();
            if (!loadedPath.endsWith(File.separator)) {
                loadedPath += File.separator;
            }
            LOG.warn("Config path is empty, using the default path : {} .", loadedPath);
        }
        return loadedPath;
    }
​
    private static String loadCustomJaasPath() {
        String jaasPath = properties.getProperty(CUSTOM_JAAS_PATH);
        if (jaasPath == null || jaasPath.isEmpty()) {
            return "";
        }
​
        return jaasPath;
    }
​
    private static boolean loadIsSecureMode() {
        return !Boolean.FALSE.toString().equals(properties.getProperty("isSecureMode"));
    }
​
    private static boolean loadSslEnabled() {
        return !Boolean.FALSE.toString().equals(properties.getProperty("sslEnabled"));
    }
​
    private static boolean loadIsSniff() {
        return !Boolean.FALSE.toString().equals(properties.getProperty("isSniff"));
    }
​
    private static String loadPrincipal() {
        String principal = properties.getProperty("principal");
        if (principal == null || principal.isEmpty()) {
            LOG.error("Please configure principal config file : {} .", configPath);
            throw new IllegalArgumentException();
        }
        return principal;
    }
​
    private static String getCurrentJarPath() throws IOException {
        StringBuilder currentJarPath = new StringBuilder();
        URL url = LoadProperties.class.getProtectionDomain().getCodeSource().getLocation();
        try {
            String filePath = URLDecoder.decode(url.getPath(), "UTF-8");
            if (filePath.endsWith(JAR_EXT)) {
                // 获取jar包所在目录
                filePath = filePath.substring(0, filePath.lastIndexOf(File.separator) + 1);
                File file = new File(filePath);
                currentJarPath.append(file.getCanonicalPath());
                if (!currentJarPath.toString().endsWith(File.separator)) {
                    currentJarPath.append(File.separator);
                }
                currentJarPath.append("..").append(File.separator).append(DEFAULT_CONFIG_PATH).append(File.separator);
            } else {
                currentJarPath.append(System.getProperty("user.dir"))
                    .append(File.separator)
                    .append(DEFAULT_CONFIG_PATH)
                    .append(File.separator);
            }
        } catch (IOException ex) {
            LOG.error("Get current jar path error.", ex);
            throw ex;
        }
        return currentJarPath.toString();
    }
}

获取客户端的方法

        ClientFactory.initConfiguration(LoadProperties.loadProperties());
        TransportClient client = ClientFactory.getClient(); 

※ 配置文件存放路径为jar包同级下创建conf文件夹,其中放入esParams.properties、krb5.conf、user.keytab

esParams.properties文件

clusterName=elasticsearch_cluster
#集群中节点的IP和TRANSPORT_TCP_PORT端口,多个用逗号隔开(TRANSPORT_TCP_PORT的获取在FusionInsight Manager界面的Elasticsearch服务的全部配置中的每个EsNode下的端口选项中)
esServerHosts=0.0.0.0:9300
#principal填写用户名
principal=esuser
isSecureMode=true
sslEnabled=true
isSniff=true
#包含全路径的jaas.conf文件,不填将根据keytab自动生成
customJaasPath=

通过以上方法发就可以获取到es客户端,并且这段代码较为独立,对于项目的变动较小。

引入pom

<!-- elasticsearch package 开始 -->
        <!-- 源生 -->
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>x-pack-transport</artifactId>
            <version>7.10.2</version>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch</groupId>
            <artifactId>elasticsearch</artifactId>
            <version>7.10.2</version>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>transport</artifactId>
            <version>7.10.2</version>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch.plugin</groupId>
            <artifactId>transport-netty4-client</artifactId>
            <version>7.10.2</version>
            <scope>compile</scope>
        </dependency>
​
        <dependency>
            <groupId>com.huawei.mrs</groupId>
            <artifactId>elasticsearch-transport-client</artifactId>
            <version>8.2.0-320.r11</version>
            <exclusions>
                <exclusion>
                    <groupId>com.google.guava</groupId>
                    <artifactId>guava</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.eclipse.jetty</groupId>
                    <artifactId>jetty-http</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.eclipse.jetty</groupId>
                    <artifactId>jetty-io</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.eclipse.jetty</groupId>
                    <artifactId>jetty-server</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>com.huawei.mrs</groupId>
            <artifactId>elasticsearch-common</artifactId>
            <version>8.2.0-320.r11</version>
        </dependency>
        <dependency>
            <groupId>com.huawei.us</groupId>
            <artifactId>us-common</artifactId>
            <version>1.0.66</version>
        </dependency>
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-common</artifactId>
            <version>3.3.1-h0.cbu.mrs.320.r11</version>
        </dependency>
​
        <!-- elasticsearch package 结束 -->