• 一文秒懂!腾讯云ES HTTPS 集群访问通信最佳实践


    c80d899d75c53b2c414925255a4ee6ad.gif

    作者:吴容,腾讯云Elasticsearch高级开发工程师

    Elasticsearch提供了多种数据访问安全的方式,如用户名密码校验、api_key等。但是依然无法保障数据传输过程中的安全性问题。而HTTPS协议,则是一种以安全为目的的HTTP通道,在HTTP的基础上通过传输加密和身份认证等机制来保障数据传输过程中的安全性。

    本文将基于腾讯云ES集群环境,演示Beats、Logstash、Kibana和Java Client等客户端访问连接开启了HTTPS协议的ES集群。

    一、HTTPS集群环境准备

    1、创建HTTPS协议集群

    首先我们在腾讯云ES控制台创建出一个HTTPS集群,在购买页这里勾选上HTTPS协议。目前该特性目前是通过白名单支持,可提工单申请开放。

    b64da6d7f82538dfc4ae9f6948ccead8.png

    图1. 腾讯云ES购买页选择创建HTTPS协议的ES集群

    其中,ES集群是通过在elasticsearch.yml配置文件中设置如下参数来开启HTTPS协议的:

    1. xpack.security.http.ssl.enabled: true
    2. xpack.security.http.ssl.keystore.path: certs/ces-certificates.p12
    3. xpack.security.http.ssl.truststore.path: certs/ces-certificates.p12

    2、获取pem证书文件

    集群创建成功后,提工单让腾讯云ES研发提供访问HTTPS集群所需要的鉴权证书文件。此时腾讯云ES侧会提供如下两个证书文件:

    文件名称用途
    client-certificates.pem用于Beats Logstash、Java Client连接ES集群
    server-certificates.pem用于KIbana连接ES集群


    下面将详细介绍Beats、Logstash、Kibana和Java等客户端连接HTTPS集群的配置方式。

    二、Beats输出到HTTPS集群

    1、CVM Metriceat输出到ES

    我们首先在腾讯云CVM控制台创建一个和ES集群同VPC下的CVM,创建好后,将得到的pem鉴权文件上传到该CVM上,这里的存放路径为:/usr/local/service/https-certs。随后到腾讯云ES控制台的Beats管理页,创建一个Metricbeat:

    3fe21b54103b8116d0fd85ea4b8d0812.png

    图2. 创建Metricbeat

    其中,最核心的步骤是在metricbeat.yml配置文件中进行如下配置。

    1. output.elasticsearch:
    2. hosts: ["https://ES-VIP:9200"]
    3. username: "elastic"
    4. password: "changeme"
    5. ssl.certificate_authorities: ["/usr/local/service/https-certs/client-certificates.pem"]
    6. ssl.verification_mode: certificate

    配置信息说明:

    配置项说明
    hostsES集群的VIP,如https://10.0.X.29:9200,以https开头
    username/passwordES集群的用户名密码
    ssl.certificate_authorities连接HTTPS集群所需的pem鉴权证书文件路径
    ssl.verification_mode服务器证书认证模式,有四种模式,分别是full,strict,certificate和none。我们这里以certificate模式进行认证,即只认证CA证书,不认证主机名信息。详情可参考官方文档。

    配置完成后,即可在ES集群中看到自动创建了一个metricbeat-7.14.20-*开头的索引,到此CVM中Metricbeat连接HTTPS的ES集群配置完成。

    c0da0f3ba517d69e9d6b1fe6da209971.png

    图3. ES集群中自动创建了metricbeat相关的索引

    2、TKE Filebeat日志采集器输出到ES

    TKE Filebeat日志采集器输出到HTTPS的ES集群流程和CVM的metricBeat输出一样,首先我们将pem文件上传到创建TKE集群时自动创建的Worker所在的CVM节点上,如/var/log/https-certs目录下。

    d95ae6be9d2109678168186eee57e66c.png

    图4. 创建TKE集群

    client-certificates.pem文件存放位置:

    c72e7abd8fbd15907b4a8b167dbcc5ef.png

    图5. 拷贝pem文件到Worker节点

    随后我们在腾讯云ES控制新建Fliebeat采集器,这里选择TKE日志采集:

    bfd497f4c3007b8aa7ac5d35aab03f3c.png

    图6. 创建Filebeat TKE日志采集器

    下面进行Filebeat采集器的基本信息配置,如版本号选择,采集器输出ES集群选择,如图7、8所示:

    4da4759613478bc1902ef3300286b7c5.png

    图7. 配置Filbeat采集器的输出端集群

    b25a7856fcc217b4d1b977a842de336d.png

    图8. 配置Filebeat采集TKE容器日志集群

    创建好Filebeat TKE容器日志采集器后,随后我们在TKE集群的详情页,找到配置管理中的ConfigMap,然后找到对应beats的config文件:

    d0e721fa15c573ac77d81f9ef58ec924.png

    图9. TKE配置管理页

    点击“编辑yaml”后对output.elasticsearch配置项进行修改,如下图10所示:

    6c58bd2da5ec69e21811294531c64dde.png

    图10. 编辑output.elasticsearch配置信息

    具体配置信息如下:

    1. output.elasticsearch:
    2. hosts: ['https://ES-VIP:9200']
    3. username: "elastic"
    4. ssl.certificate_authorities: ["/var/log/https-certs/client-certificates.pem"]
    5. ssl.verification_mode: "certificate"
    6. password: "changeme"
    7. indices:
    8. - index: "filebeat-tke-%{+yyyy.MM.dd}"
    9. when.equals:
    10. tke_collector_target_name: "logs_to_https_es"

    然后在TKE集群中的工作负载中,找到DaemonSet,然后再到对应beats的DaemonSet,点击进去,对它的pod进行销毁重建。

    d4d0608c64f341e3c2c655bd20b61303.png

    图11. TKE DaemonSet管理页

    进入到Pod管理页,选择对应的Pod销毁重建。

    68f9ec4743ab5584e6c3e8bbd83d1b60.png

    图12. 选择对应Pod销毁重建

    销毁重建后,Pod的运行状态变成Running,如图13所示。 

    注:如果多次对pod进行销毁重建,仍是红色Running,有可能是beats的yml配置出现问题,可以在日志里面查看具体问题,或者重新检查一下yml配置是否错误。

    1c12f9504e113a2ae1265fdee17b2886.png

    图13. 销毁重建后的Pod正常运行

    随后我们到ES集群中,可以看到自动创建了以filebeat-tke-*开头的索引。表明TKE日志顺利输出到HTTPS集群中了。

    0393a1650cff3b94e4a03c8507f47923.png

    图14. ES集群中自动创建TKE日志采集器相关索引

    三、Logstash输出到HTTPS集群

    腾讯云Logstash是一款全托管的产品,因此我们首先需要在腾讯云Logstash控制台将pem文件以扩展文件方式进行上传,如下图15所示。 

    5539b0be665426debe7dcce5c31442a3.png

    图15. 腾讯云Logstash控制台上传pem文件

    随后我们新建一个管道,在管道的Config配置编辑框里配置上ES的连接信息和证书路径。

    e06a095fb537133dd6bbfa65469d333c.png

    图16. 配置Logstash的管道Config

    管道详细配置文本信息如下:

    1. output {
    2. elasticsearch {
    3. hosts => ["https://ES-VIP:9200"]
    4. user => "elastic"
    5. password => "changeme"
    6. ssl => true
    7. cacert => "/usr/local/service/logstash/extended-files/client-certificates.pem"
    8. ssl_certificate_verification => false
    9. }
    10. }

    其中cacert即可我们上一步上传的扩展文件pem的路径,固定路径为:/usr/local/service/logstash/extended-files/client-certificates.pem。点击保存并部署管道后,就会在管道列表里可以看到我们刚刚新建出来的管道信息了,此时状态为运行中。

    cdff21f21a93f4c6875e113cd7b83211.png

    图17. Logstash管道列表页

    这时候我们再到HTTPS集群中就可以看到有数据从input的集群中写入进来了。

    四、Kibana连接HTTPS集群

    腾讯云ES集群默认自带Kibana访问能力,因此一般情况下,客户是不需要对Kibana进行任何配置的。这里介绍自建Kibana连接HTTPS集群的配置方式。和Beats、Logstash等使用的客户端鉴权证书不一样,Kibana使用的是server-certificates.pem,腾讯云ES侧生成证书命令如下:

    openssl pkcs12 -in ces-certificates.p12 -password pass:xxxxxx -nokeys -cacerts -out server-certificates.pem

    由于前面我们已经拿到了pem证书文件。因此,我们将server-certificates.pem文件拷贝到Kibana所在节点的如下路径:/usr/local/service/https-certs。然后修改kibana.yml配置文件如下:

    1. elasticsearch.hosts: ["https://ES-VIP:9200"]
    2. elasticsearch.username: "elastic"
    3. elasticsearch.password: "changeme"
    4. elasticsearch.ssl.verificationMode: certificate
    5. elasticsearch.ssl.certificateAuthorities: ["/usr/local/service/https-certs/server-certificates.pem"]
    6. xpack.encryptedSavedObjects.encryptionKey: "dfed624ca4014135f61804440536xxxx"
    7. xpack.fleet.registryUrl: "https://epr.elastic.co"

    ‍配置项说明:elasticsearch.ssl.certificateAuthorities:pem文件的存放路径。elasticsearch.ssl.verificationMode:证书鉴权模式,certificate 采用只鉴权CA证书,不鉴权主机名称的模式。xpack.fleet.registryUrl:(非必选配置)Fleet集成模块需要访问的公网仓库,这里需要Kibana节点具备公网访问能力。xpack.encryptedSavedObjects.encryptionKey:value可以通过bin/kibana-encryption-keys generate 命令获得。 

    24270f8e740bb01c8c2b9b34a786f047.png

    图18. 生成Kibana安全密钥

    重新启动Kibana后即可正常访问HTTPS的ES集群了。

    五、Java Client连接HTTPS集群

    本文档演示在Spring项目中访问HTTPS集群的配置方式,首先需要添加如下maven依赖:

    1. <dependency>
    2. <groupId>org.elasticsearch.clientgroupId>
    3. <artifactId>elasticsearch-rest-clientartifactId>
    4. <version>7.10.1version>
    5. dependency>
    6. <dependency>
    7. <groupId>org.elasticsearch.clientgroupId>
    8. <artifactId>elasticsearch-rest-high-level-clientartifactId>
    9. <version>7.10.1version>
    10. dependency>
    11. <dependency>
    12. <groupId>org.elasticsearchgroupId>
    13. <artifactId>elasticsearchartifactId>
    14. <version>7.10.1version>
    15. dependency>

    ‍随后我们在ElasticsearchConfig自定义类中实现对Elasticsearch连接的配置。

    1. @Configuration
    2. public class ElasticsearchConfig {
    3. @Value("${es.username}")
    4. private String userName;
    5. @Value("${es.password}")
    6. private String password;
    7. @Value("${es.scheme}")
    8. private String scheme;
    9. @Value("${es.domain}")
    10. private String domain;
    11. @Value("${es.https.cert}")
    12. private String certFile;
    13. @Value("${es.port}")
    14. private int port;
    15. private RestHighLevelClient client;
    16. @Bean
    17. public RestHighLevelClient EsConnectInit() throws CertificateException, IOException, KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
    18. final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
    19. credentialsProvider.setCredentials(AuthScope.ANY,new UsernamePasswordCredentials(userName,password));
    20. RestClientBuilder builder;
    21. if (scheme.equals("https")) {
    22. Path caCertificatePath = Paths.get(certFile);
    23. System.out.println(certFile);
    24. CertificateFactory factory = CertificateFactory.getInstance("X.509");
    25. Certificate trustedCa;
    26. try(InputStream is = Files.newInputStream(caCertificatePath)) {
    27. trustedCa = factory.generateCertificate(is);
    28. }
    29. KeyStore trustStore = KeyStore.getInstance("pkcs12");
    30. trustStore.load(null,null);
    31. trustStore.setCertificateEntry("ca",trustedCa);
    32. SSLContextBuilder sslContextBuilder = SSLContexts.custom().loadTrustMaterial(trustStore, new TrustStrategy() {
    33. @Override
    34. public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
    35. return true;
    36. }
    37. });
    38. final SSLContext sslContext = sslContextBuilder.build();
    39. final HostnameVerifier hostnameVerifier = new HostnameVerifier() {
    40. public boolean verify(String hostname, SSLSession session) {
    41. return true;
    42. }
    43. };
    44. builder = RestClient.builder(new HttpHost(domain, port, scheme)).setRequestConfigCallback(new RestClientBuilder.RequestConfigCallback() {
    45. @Override
    46. public RequestConfig.Builder customizeRequestConfig(RequestConfig.Builder requestConfigBuilder) {
    47. requestConfigBuilder.setConnectTimeout(-1);
    48. requestConfigBuilder.setSocketTimeout(-1);
    49. requestConfigBuilder.setConnectionRequestTimeout(-1);
    50. return requestConfigBuilder;
    51. }
    52. }).setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
    53. @Override
    54. public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) {
    55. httpClientBuilder.disableAuthCaching();
    56. httpClientBuilder.setSSLHostnameVerifier(hostnameVerifier);
    57. return httpClientBuilder.setSSLContext(sslContext)
    58. .setDefaultCredentialsProvider(credentialsProvider);
    59. }
    60. });
    61. } else {
    62. builder = RestClient.builder(new HttpHost(domain, port, scheme))
    63. .setRequestConfigCallback(new RestClientBuilder.RequestConfigCallback() {
    64. @Override
    65. public RequestConfig.Builder customizeRequestConfig(RequestConfig.Builder requestConfigBuilder) {
    66. requestConfigBuilder.setConnectTimeout(-1);
    67. requestConfigBuilder.setSocketTimeout(-1);
    68. requestConfigBuilder.setConnectionRequestTimeout(-1);
    69. return requestConfigBuilder;
    70. }
    71. }).setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
    72. @Override
    73. public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) { httpClientBuilder.disableAuthCaching();
    74. return httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
    75. }
    76. });
    77. }
    78. client = new RestHighLevelClient(builder);
    79. return client;
    80. }
    81. }

    ‍其中Elasticsearch的配置信息如下:

    1. es.scheme=https
    2. es.port=9200
    3. es.domain=9.10.1.X #es vip
    4. es.username=elastic
    5. es.password=changeme
    6. es.https.cert=/usr/local/services/certs/client-certificates.pem

    ‍通过如上配置后,即可在Spring项目中成功连接上开启了HTTPS协议的ES集群了。

    扫码加入 Elasticsearch 技术社区👇

    ff81086ec100e80d11e1d6d90b8c8b1a.jpeg

    推荐阅读

    cd5a88f8f1612d3bea7bcae5e5baa7d5.jpeg

    1bc43b522d705440a00704d607ba9737.jpeg

    36237c84bd56874ddc09516b6a16cd35.jpeg

    关注腾讯云大数据公众号

    邀您探索数据的无限可能

    16ac07ab09825b545b09ce1998139361.png

    点击“阅读原文”,了解相关产品最新动态

    ↓↓↓

  • 相关阅读:
    SSM框架-Spring整合Mybatis
    Parallels Desktop 20破解版(Mac虚拟机) v20.0.0 for Mac 最新商业版(支持M系列)
    Waiting for table metadata lock
    设备驱动程序的原理
    手把手教你彻底卸载MySQL
    【Javascript保姆级教程】Javascript数据类型和算术运算符
    数据类型概括
    享元模式具体实例(含代码)
    torch.autograd
    Spring Boot 入门笔记
  • 原文地址:https://blog.csdn.net/cloudbigdata/article/details/126188596