This is an automated email from the ASF dual-hosted git repository.

jiangtian pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iotdb.git


The following commit(s) were added to refs/heads/master by this push:
     new ff20bbf315d Metric connection security enhanced (#16379)
ff20bbf315d is described below

commit ff20bbf315d67fd8a1c5f311fa72b5488eb84ebd
Author: Haonan <[email protected]>
AuthorDate: Wed Sep 10 16:21:58 2025 +0800

    Metric connection security enhanced (#16379)
    
    * dev
    
    * dev function
    
    * function works
    
    * dev
    
    * finish config
    
    * finish config
    
    * remove switch
    
    * fix pom issue
---
 iotdb-core/metrics/interface/pom.xml               |  4 ++
 .../apache/iotdb/metrics/config/MetricConfig.java  | 54 ++++++++++++++++++-
 .../metrics/config/MetricConfigDescriptor.java     | 13 +++++
 .../reporter/iotdb/IoTDBSessionReporter.java       | 22 +++++---
 .../reporter/prometheus/PrometheusReporter.java    | 63 ++++++++++++++++++++--
 5 files changed, 145 insertions(+), 11 deletions(-)

diff --git a/iotdb-core/metrics/interface/pom.xml 
b/iotdb-core/metrics/interface/pom.xml
index cb53d65b903..1e5028f6859 100644
--- a/iotdb-core/metrics/interface/pom.xml
+++ b/iotdb-core/metrics/interface/pom.xml
@@ -79,6 +79,10 @@
             <groupId>io.netty</groupId>
             <artifactId>netty-transport</artifactId>
         </dependency>
+      <dependency>
+        <groupId>io.netty</groupId>
+        <artifactId>netty-handler</artifactId>
+      </dependency>
         <dependency>
             <groupId>io.netty</groupId>
             <artifactId>netty-codec-http</artifactId>
diff --git 
a/iotdb-core/metrics/interface/src/main/java/org/apache/iotdb/metrics/config/MetricConfig.java
 
b/iotdb-core/metrics/interface/src/main/java/org/apache/iotdb/metrics/config/MetricConfig.java
index 090ef3eae2c..317290e3435 100644
--- 
a/iotdb-core/metrics/interface/src/main/java/org/apache/iotdb/metrics/config/MetricConfig.java
+++ 
b/iotdb-core/metrics/interface/src/main/java/org/apache/iotdb/metrics/config/MetricConfig.java
@@ -79,6 +79,12 @@ public class MetricConfig {
   private long upTimeInNs = 0;
   private String internalDatabase = "root.__system";
 
+  private boolean enableSSL = false;
+  private String keyStorePath = "";
+  private String keyStorePassword = "";
+  private String trustStorePath = "";
+  private String trustStorePassword = "";
+
   public MetricConfig() {
     // try to get pid of iotdb instance
     try {
@@ -95,7 +101,7 @@ public class MetricConfig {
   public void setMetricReporterList(String metricReporterList) {
     this.metricReporterList = new ArrayList<>();
     for (String type : metricReporterList.split(",")) {
-      if (type.trim().length() != 0) {
+      if (!type.trim().isEmpty()) {
         this.metricReporterList.add(ReporterType.valueOf(type));
       }
     }
@@ -163,6 +169,46 @@ public class MetricConfig {
     this.prometheusReporterPassword = prometheusReporterPassword;
   }
 
+  public boolean isEnableSSL() {
+    return enableSSL;
+  }
+
+  public void setEnableSSL(boolean enableSSL) {
+    this.enableSSL = enableSSL;
+  }
+
+  public String getKeyStorePath() {
+    return keyStorePath;
+  }
+
+  public void setKeyStorePath(String keyStorePath) {
+    this.keyStorePath = keyStorePath;
+  }
+
+  public String getKeyStorePassword() {
+    return keyStorePassword;
+  }
+
+  public void setKeyStorePassword(String keyStorePassword) {
+    this.keyStorePassword = keyStorePassword;
+  }
+
+  public String getTrustStorePath() {
+    return trustStorePath;
+  }
+
+  public void setTrustStorePath(String trustStorePath) {
+    this.trustStorePath = trustStorePath;
+  }
+
+  public String getTrustStorePassword() {
+    return trustStorePassword;
+  }
+
+  public void setTrustStorePassword(String trustStorePassword) {
+    this.trustStorePassword = trustStorePassword;
+  }
+
   public IoTDBReporterConfig getIoTDBReporterConfig() {
     return iotdbReporterConfig;
   }
@@ -221,6 +267,12 @@ public class MetricConfig {
     prometheusReporterPassword = 
newMetricConfig.getPrometheusReporterPassword();
     internalReporterType = newMetricConfig.getInternalReportType();
 
+    enableSSL = newMetricConfig.isEnableSSL();
+    keyStorePath = newMetricConfig.getKeyStorePath();
+    keyStorePassword = newMetricConfig.getKeyStorePassword();
+    trustStorePath = newMetricConfig.getTrustStorePath();
+    trustStorePassword = newMetricConfig.getTrustStorePassword();
+
     iotdbReporterConfig.copy(newMetricConfig.getIoTDBReporterConfig());
   }
 
diff --git 
a/iotdb-core/metrics/interface/src/main/java/org/apache/iotdb/metrics/config/MetricConfigDescriptor.java
 
b/iotdb-core/metrics/interface/src/main/java/org/apache/iotdb/metrics/config/MetricConfigDescriptor.java
index 2cc5c2a986d..def3d1e50c0 100644
--- 
a/iotdb-core/metrics/interface/src/main/java/org/apache/iotdb/metrics/config/MetricConfigDescriptor.java
+++ 
b/iotdb-core/metrics/interface/src/main/java/org/apache/iotdb/metrics/config/MetricConfigDescriptor.java
@@ -124,6 +124,19 @@ public class MetricConfigDescriptor {
             loadConfig.getPrometheusReporterPassword(),
             properties));
 
+    loadConfig.setKeyStorePath(
+        getPropertyWithoutPrefix("key_store_path", 
loadConfig.getKeyStorePath(), properties));
+
+    loadConfig.setKeyStorePassword(
+        getPropertyWithoutPrefix("key_store_pwd", 
loadConfig.getKeyStorePassword(), properties));
+
+    loadConfig.setTrustStorePath(
+        getPropertyWithoutPrefix("trust_store_path", 
loadConfig.getTrustStorePath(), properties));
+
+    loadConfig.setTrustStorePassword(
+        getPropertyWithoutPrefix(
+            "trust_store_pwd", loadConfig.getTrustStorePassword(), 
properties));
+
     IoTDBReporterConfig reporterConfig = loadConfig.getIoTDBReporterConfig();
     reporterConfig.setHost(
         getProperty(
diff --git 
a/iotdb-core/metrics/interface/src/main/java/org/apache/iotdb/metrics/reporter/iotdb/IoTDBSessionReporter.java
 
b/iotdb-core/metrics/interface/src/main/java/org/apache/iotdb/metrics/reporter/iotdb/IoTDBSessionReporter.java
index b70ecebfff2..62392b8b124 100644
--- 
a/iotdb-core/metrics/interface/src/main/java/org/apache/iotdb/metrics/reporter/iotdb/IoTDBSessionReporter.java
+++ 
b/iotdb-core/metrics/interface/src/main/java/org/apache/iotdb/metrics/reporter/iotdb/IoTDBSessionReporter.java
@@ -62,13 +62,21 @@ public class IoTDBSessionReporter extends IoTDBReporter {
 
   public IoTDBSessionReporter(AbstractMetricManager metricManager) {
     this.metricManager = metricManager;
-    this.sessionPool =
-        new SessionPool(
-            ioTDBReporterConfig.getHost(),
-            ioTDBReporterConfig.getPort(),
-            ioTDBReporterConfig.getUsername(),
-            ioTDBReporterConfig.getPassword(),
-            ioTDBReporterConfig.getMaxConnectionNumber());
+    SessionPool.Builder sessionPoolBuilder =
+        new SessionPool.Builder()
+            .host(ioTDBReporterConfig.getHost())
+            .port(ioTDBReporterConfig.getPort())
+            .user(ioTDBReporterConfig.getUsername())
+            .password(ioTDBReporterConfig.getPassword())
+            .maxSize(ioTDBReporterConfig.getMaxConnectionNumber());
+    if (metricConfig.isEnableSSL()) {
+      sessionPoolBuilder =
+          sessionPoolBuilder
+              .useSSL(true)
+              .trustStore(metricConfig.getTrustStorePath())
+              .trustStorePwd(metricConfig.getTrustStorePassword());
+    }
+    this.sessionPool = sessionPoolBuilder.build();
     try (SessionDataSetWrapper result =
         this.sessionPool.executeQueryStatement(
             "SHOW DATABASES " + metricConfig.getInternalDatabase())) {
diff --git 
a/iotdb-core/metrics/interface/src/main/java/org/apache/iotdb/metrics/reporter/prometheus/PrometheusReporter.java
 
b/iotdb-core/metrics/interface/src/main/java/org/apache/iotdb/metrics/reporter/prometheus/PrometheusReporter.java
index 9bc8f2d9cae..1e0c33d61c2 100644
--- 
a/iotdb-core/metrics/interface/src/main/java/org/apache/iotdb/metrics/reporter/prometheus/PrometheusReporter.java
+++ 
b/iotdb-core/metrics/interface/src/main/java/org/apache/iotdb/metrics/reporter/prometheus/PrometheusReporter.java
@@ -39,6 +39,9 @@ import io.netty.channel.ChannelOption;
 import io.netty.channel.group.DefaultChannelGroup;
 import io.netty.handler.codec.http.HttpHeaderNames;
 import io.netty.handler.codec.http.HttpResponseStatus;
+import io.netty.handler.ssl.ClientAuth;
+import io.netty.handler.ssl.SslContext;
+import io.netty.handler.ssl.SslContextBuilder;
 import io.netty.util.concurrent.GlobalEventExecutor;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -48,10 +51,15 @@ import reactor.netty.http.server.HttpServer;
 import reactor.netty.http.server.HttpServerRequest;
 import reactor.netty.http.server.HttpServerResponse;
 
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.TrustManagerFactory;
+
+import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.StringWriter;
 import java.io.Writer;
 import java.nio.charset.StandardCharsets;
+import java.security.KeyStore;
 import java.time.Duration;
 import java.util.Base64;
 import java.util.HashMap;
@@ -81,7 +89,7 @@ public class PrometheusReporter implements Reporter {
       return false;
     }
     try {
-      httpServer =
+      HttpServer serverTransport =
           HttpServer.create()
               .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 2000)
               .channelGroup(new 
DefaultChannelGroup(GlobalEventExecutor.INSTANCE))
@@ -97,8 +105,22 @@ public class PrometheusReporter implements Reporter {
                             }
                             return res.header(HttpHeaderNames.CONTENT_TYPE, 
"text/plain")
                                 .sendString(Mono.just(scrape()));
-                          }))
-              .bindNow();
+                          }));
+      if (METRIC_CONFIG.isEnableSSL()) {
+        SslContext sslContext;
+        try {
+          sslContext =
+              createSslContext(
+                  METRIC_CONFIG.getKeyStorePath(),
+                  METRIC_CONFIG.getKeyStorePassword(),
+                  METRIC_CONFIG.getTrustStorePath(),
+                  METRIC_CONFIG.getTrustStorePassword());
+        } catch (Exception e) {
+          throw new RuntimeException(e);
+        }
+        serverTransport = serverTransport.secure(spec -> 
spec.sslContext(sslContext));
+      }
+      httpServer = serverTransport.bindNow();
     } catch (Throwable e) {
       // catch Throwable rather than Exception here because the code above 
might cause a
       // NoClassDefFoundError
@@ -257,6 +279,41 @@ public class PrometheusReporter implements Reporter {
     return result;
   }
 
+  private SslContext createSslContext(
+      String keystorePath,
+      String keystorePassword,
+      String truststorePath,
+      String truststorePassword)
+      throws Exception {
+    SslContextBuilder sslContextBuilder = null;
+    if (keystorePath != null && keystorePassword != null) {
+      KeyStore keyStore = KeyStore.getInstance("JKS");
+      try (FileInputStream fis = new FileInputStream(keystorePath)) {
+        keyStore.load(fis, keystorePassword.toCharArray());
+      }
+      KeyManagerFactory kmf =
+          
KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+      kmf.init(keyStore, keystorePassword.toCharArray());
+      sslContextBuilder = SslContextBuilder.forServer(kmf);
+    }
+
+    if (sslContextBuilder != null && truststorePath != null && 
truststorePassword != null) {
+      KeyStore trustStore = KeyStore.getInstance("JKS");
+      try (FileInputStream fis = new FileInputStream(truststorePath)) {
+        trustStore.load(fis, truststorePassword.toCharArray());
+      }
+      TrustManagerFactory tmf =
+          
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+      tmf.init(trustStore);
+      sslContextBuilder.trustManager(tmf);
+    }
+    if (sslContextBuilder == null) {
+      throw new Exception("Keystore or Truststore is null");
+    }
+    sslContextBuilder.clientAuth(ClientAuth.REQUIRE);
+    return sslContextBuilder.build();
+  }
+
   @Override
   public boolean stop() {
     if (httpServer != null) {

Reply via email to