前提条件

  • 本地下载安装好Elasticsearch、Kibana、Logstash,并可以正常启动

  • 本文所使用的ELK的版本为8.2.0

  • Elasticsearch 8.2.0 版本,安装好之后会默认生成对应的http_ca.cert、transport.p12、http.12文件

生成CA证书

为什么这里是生成ca.crt而不是官方文档中的ca.p12文件呢?(此问题已更新,请参照Java代码那一节最新说明)

./bin/elasticsearch-certutil ca --days 3650 --pem --out ./tls/ca/ca.zip
unzip tls/ca/ca.zip

在ca目录下生成了ca.crt和ca.key文件

根据CA证书生成用于各个节点通信加密的证书

instances.yml文件

instances:
- name: elasticsearch
  dns:
  - localhost     # local connections
  ip:
  - 127.0.0.1     # local connections

执行命令

./bin/elasticsearch-certutil cert --ca-cert tls/ca/ca/ca.crt --ca-key tls/ca/ca/ca.key --in tls/instances.yml --days 3650 --out tls/certificate.zip

解压文件

unzip certificate.zip

解压成功之后会有一个elasticsearch.p12文件

相关官方文档

为其他组件Kibana、Logstash生成证书

./bin/elasticsearch-certutil http

根据提示输入第一步生成的ca.crt和ca.key,可以选择设置密码或者不设置密码

最终会生成一个elasticsearch-ssl-http.zip压缩文件

unzip elasticsearch-ssl-http.zip

解压之后为两个文件夹,分别有

elasticsearch-ca.pem和http.p12文件

elasticsearch和kibana,里面分别有一个README.txt告诉怎么用

相关官方文档

配置elasticsearch.yml

注意 上述所有生成过程的密码都是空

将上述生成的所有文件放到一个目录下,通常是$ES_INSTALL_HOME/config/certs,以下为elasticsearch.yml文件

# http mode下生成的文件
xpack.security.http.ssl.enabled: true
xpack.security.http.ssl.keystore.path: http.p12

# cert mode下生成的文件
xpack.security.transport.ssl.enabled: true
xpack.security.transport.ssl.verification_mode: certificate
xpack.security.transport.ssl.keystore.path: elasticsearch.p12
xpack.security.transport.ssl.truststore.path: elasticsearch.p12

执行下列命令,具体命令的文档

# 密码问第三步生成http.p12时设置的密码
./bin/elasticsearch-keystore add xpack.security.http.ssl.truststore.secure_password

./bin/elasticsearch-keystore add xpack.security.http.ssl.keystore.secure_password

# 密码为第二步生成elasticsearch.p12文件时的设置的密码
./bin/elasticsearch-keystore add xpack.security.transport.ssl.keystore.secure_password

./bin/elasticsearch-keystore add xpack.security.transport.ssl.truststore.secure_password

每个命令都会让你输入密码,如果没有密码直接回车即可

注意 这里也可以将上述配置写到elasticsearch.yml文件里。但是由于elasticsearch刚安装的时候已经设置了password而不是secure_password。所以会启动不起来。
在这里插入图片描述

用命令行的方式应该会把password给覆盖掉

所有配置配置完毕之后,启动elasticsearch,观察是否正常启动

配置kibana.yml

将第三步生成的elasticsearch-ca.pem拷贝到$KIBANA_INSTALL_HOME/config文件夹下

# 将http 改为 https
elasticsearch.hosts: [ "https://localhost:9200" ]

elasticsearch.ssl.certificateAuthorities: [ "config/elasticsearch-ca.pem" ]

启动Kibana,观察是否正常启动

配置logstash.conf

将第三步生成的elasticsearch-ca.pem拷贝到$Logstash_INSTALL_HOME/config文件夹下

在具体的logstash配置文件中的output部分增加最后两行配置

output {
	elasticsearch {
		hosts => "localhost:9200"
		user => "elastic"
		password => "password"
		# 添加ssl配置
		ssl => true
		cacert => "config/elasticsearch-ca.pem"
	}
}

启动logstash,观察是否正常启动

Elasticsearch Java Client使用HTTPS连接ES

截止到这部分,ELK能正常启动不全部配置了TLS。现在在Java代码里使用HTTPS连接ES.

相关官方文档

为什么使用ca.crt而不是官方推荐的ca.p12?

因为JDK8对于.p12文件的解析存在问题。据我Google,如果要使用.p12文件进行连接,JDK版本至少是11才可以,不过我没试过,所以在JDK8的环境里,我推荐使用ca.crt文件

2022年9月22日更新
Oracle JDK8版本只有大于8u301的才没问题,具体bug连接见Oracle Bug 8267837

但是由于Oracle JDK 8u202以上版本是收费的.可以使用Adoptium Temurin OpenJDK来代替,Adoptium OpenJDK对应的JDK8截止今天为止,最后一个版本是8u345-b01

同时ES中TLSV1.3也需要JDK版本高于8u261,所以个人建议,如果不是特别麻烦(考虑到线上所有项目需要升级JDK并完整测试),可将JDK升级到8u345

如果本机切换到高级版本则可以使用.p12文件进行连接,官方.p12文件连接示例,文档中的keyStorePass为密码

示例代码如下

@Configuration
public class ElasticSearchConfiguration {
    
    @Bean
    @SneakyThrows
    public ElasticsearchClient elasticsearchClient() {
        CredentialsProvider credentialsProvider =
            new BasicCredentialsProvider();
        credentialsProvider.setCredentials(AuthScope.ANY,
            new UsernamePasswordCredentials("elastic", "password"));
//        第一步生成的证书所在的位置
        Path caCertificatePath = Paths.get("/elastic_install_home/config/ca.crt");
        CertificateFactory factory =
            CertificateFactory.getInstance("X.509");
        Certificate trustedCa;
        try (InputStream is = Files.newInputStream(caCertificatePath)) {
            trustedCa = factory.generateCertificate(is);
        }
        KeyStore trustStore = KeyStore.getInstance("pkcs12");
        trustStore.load(null, null);
        trustStore.setCertificateEntry("ca", trustedCa);
        SSLContextBuilder sslContextBuilder = SSLContexts.custom()
            .loadTrustMaterial(trustStore, null);
        SSLContext sslContext = sslContextBuilder.build();
        RestClientBuilder builder = RestClient.builder(
            new HttpHost("localhost", 9200, "https"))
            .setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder
                // 设置ssl
                .setSSLContext(sslContext)
                .setDefaultCredentialsProvider(credentialsProvider));
        RestClient restClient = builder.build();
        ElasticsearchTransport elasticsearchTransport = new RestClientTransport(restClient, new JacksonJsonpMapper());
        return new ElasticsearchClient(elasticsearchTransport);
    }
}

写一个Test Case验证下即可。

上述代码中,只有一个节点,如果是多个节点的话,不需要我们在自己的代码里做负载均衡,Elasticsearch Java Client负责

The client sends each request to one of the configured nodes in round-robin fashion

到此为止,为Elasticsearch启动TLS并使用Java代码连接就完毕了。

另一种终极解决方案

如果你不想上面这么麻烦,想直接用HTTP,但是又是生产环境。一个比较省时又省力的方式是利用各种代理或者负载均衡。

将暴露出的域名最终映射到后端的http上面.虽然实际上还是http,不过在表面上看来是HTTPS了

2022年9月22日更新
此解决方案只适合单节点的Elasticsearch,集群环境下此方案失效,必须为各节点配置证书,下文引自官方文档

To secure your cluster, you must ensure that internode communications are encrypted and verified, which is achieved with mutual TLS.

流程总结

以下流程可在官方文档这里找到

生成证书使用的elasticesearch-certutil命令

  1. 生成ca证书,此证书可以是PEM文件或PCKS#12格式的;PEM文件会生成两个文件ca.crt和ca.key;而PCKS#12会生成一个文件ca.p12
  2. 基于第一步的证书,为集群各个节点之间通信生成证书,使用cert mode
  3. 基于第一步的证书,为Kibana、Logstash、Java Client与Elasticsearch之间通信生成证书,使用http mode

本文只提供了基于PEM文件的示例,读者可根据上述流程总结与文末给出的文档,生成PCKS#12的证书,再配置即可。

个人建议使用PCKS#12格式的证书文件,同时使用Adopt OpenJDK各版本(8、11、17)最新的版本

直接使用Elasticsearch官方脚本

如果只是本地学习使用,想要快速在本地大家一个三节点的集群。 可以直接使用官方提供的docker-compose.yml文件。只需要改动几个配置,即可快速启动一个集群,非常方便。

在官方文档里,提供了具有三个节点的集群的docker-compose.yml文件,本地可直接使用官方脚本。
官方文档地址
注意:官方文档中,docker-compose.yml中只有es01的9200端口暴露了出来

示例代码仓库

GitHub仓库地址

官方文档

强烈建议把下面的官方文档通读一边,尤其是第一次配置的同学,里面的步骤基本很详细了。而且也更详细介绍了各个配置的作用、目的。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐