This is an automated email from the ASF dual-hosted git repository.
wanghailin pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/seatunnel.git
The following commit(s) were added to refs/heads/dev by this push:
new 53325aa3e7 [Feature][Zeta] Support enable https protocol for rest-api
v2 (#9010)
53325aa3e7 is described below
commit 53325aa3e76e3939f41a4bf3eaaf3ee56f13f311
Author: Jast <[email protected]>
AuthorDate: Fri Mar 28 21:23:34 2025 +0800
[Feature][Zeta] Support enable https protocol for rest-api v2 (#9010)
---
docs/en/seatunnel-engine/rest-api-v1.md | 4 -
docs/en/seatunnel-engine/rest-api-v2.md | 8 +-
docs/en/seatunnel-engine/security.md | 104 +++++++++++++
docs/sidebars.js | 11 +-
docs/zh/seatunnel-engine/rest-api-v1.md | 4 -
docs/zh/seatunnel-engine/rest-api-v2.md | 8 +-
docs/zh/seatunnel-engine/security.md | 108 +++++++++++++
.../api/file/AllFileSpecificationCheckTest.java | 3 +-
.../config/YamlSeaTunnelDomConfigProcessor.java | 31 ++++
.../engine/common/config/server/HttpConfig.java | 27 ++++
.../common/config/server/ServerConfigOptions.java | 42 +++++
.../src/main/resources/seatunnel.yaml | 2 +-
.../seatunnel/engine/server/JettyService.java | 48 +++++-
.../seatunnel/engine/server/SeaTunnelServer.java | 3 +-
.../server/rest/RestApiHttpsForTruststoreTest.java | 172 +++++++++++++++++++++
.../engine/server/rest/RestApiHttpsTest.java | 129 ++++++++++++++++
.../seatunnel/engine/server/rest/SSLUtils.java | 105 +++++++++++++
.../src/test/resources/https/client_keystore.jks | Bin 0 -> 2728 bytes
.../src/test/resources/https/client_truststore.jks | Bin 0 -> 1254 bytes
.../src/test/resources/https/server_keystore.jks | Bin 0 -> 2728 bytes
.../src/test/resources/https/server_truststore.jks | Bin 0 -> 1254 bytes
21 files changed, 787 insertions(+), 22 deletions(-)
diff --git a/docs/en/seatunnel-engine/rest-api-v1.md
b/docs/en/seatunnel-engine/rest-api-v1.md
index 5e9b772edc..c144e481cb 100644
--- a/docs/en/seatunnel-engine/rest-api-v1.md
+++ b/docs/en/seatunnel-engine/rest-api-v1.md
@@ -1,7 +1,3 @@
----
-sidebar_position: 11
----
-
# RESTful API V1
:::caution warn
diff --git a/docs/en/seatunnel-engine/rest-api-v2.md
b/docs/en/seatunnel-engine/rest-api-v2.md
index 72eb904443..e5b85de941 100644
--- a/docs/en/seatunnel-engine/rest-api-v2.md
+++ b/docs/en/seatunnel-engine/rest-api-v2.md
@@ -1,7 +1,3 @@
----
-sidebar_position: 12
----
-
# RESTful API V2
SeaTunnel has a monitoring API that can be used to query status and statistics
of running jobs, as well as recent
@@ -37,6 +33,10 @@ seatunnel:
context-path: /seatunnel
```
+## Enable HTTPS
+
+Please refer [security](security.md)
+
## API reference
### Returns an overview over the Zeta engine cluster.
diff --git a/docs/en/seatunnel-engine/security.md
b/docs/en/seatunnel-engine/security.md
new file mode 100644
index 0000000000..363f1b9200
--- /dev/null
+++ b/docs/en/seatunnel-engine/security.md
@@ -0,0 +1,104 @@
+# Security
+
+## HTTPS Configuration
+
+You can secure your REST-API-V2 service by enabling HTTPS. Both HTTP and HTTPS
can be enabled simultaneously, or only one of them can be enabled.
+
+| Parameter Name | Required | Description |
+|----------------|----------|-------------|
+| `enable-http` | No | Whether to enable HTTP service, default is `true` |
+| `port` | No | HTTP service port, default is `8080` |
+| `enable-https` | No | Whether to enable HTTPS service, default is `false` |
+| `https-port` | No | HTTPS service port, default is `8443` |
+| `key-store-path` | Required when `enable-https` is `true` | Path to the
KeyStore file, used to store the server's private key and certificate |
+| `key-store-password` | Required when `enable-https` is `true` | KeyStore
password |
+| `key-manager-password` | Required when `enable-https` is `true` | KeyManager
password, usually the same as the KeyStore password |
+| `trust-store-path` | No | Path to the TrustStore file, used to verify client
certificates |
+| `trust-store-password` | No | TrustStore password |
+
+**Note**: When `trust-store-path` and `trust-store-password` are not empty,
mutual SSL authentication (client authentication) will be enabled, requiring
the client to provide a valid certificate.
+
+```yaml
+seatunnel:
+ engine:
+ http:
+ enable-http: true
+ port: 8080
+ enable-https: true
+ https-port: 8443
+ key-store-path: "${YOUR_KEY_STORE_PATH}"
+ key-store-password: "${YOUR_KEY_STORE_PASSWORD}"
+ key-manager-password: "${YOUR_KEY_MANAGER_PASSWORD}"
+ # Optional: Mutual authentication
+ trust-store-path: "${YOUR_TRUST_STORE_PATH}"
+ trust-store-password: "${YOUR_TRUST_STORE_PASSWORD}"
+```
+
+### Example of Generating Keys
+
+```shell
+#!/bin/bash
+
+# Define the project root directory
+PROJECT_DIR="/Users/mac/IdeaProjects/data"
+
+# Define passwords
+SERVER_KEYSTORE_PASSWORD="server_keystore_password"
+SERVER_KEY_PASSWORD="server_keystore_password"
+CLIENT_KEYSTORE_PASSWORD="client_keystore_password"
+CLIENT_KEY_PASSWORD="client_keystore_password"
+SERVER_TRUSTSTORE_PASSWORD="server_truststore_password"
+CLIENT_TRUSTSTORE_PASSWORD="client_truststore_password"
+
+# Generate server keystore
+keytool -genkeypair \
+ -alias server \
+ -keyalg RSA \
+ -keysize 2048 \
+ -validity 365 \
+ -keystore "$PROJECT_DIR/server_keystore.jks" \
+ -storepass "$SERVER_KEYSTORE_PASSWORD" \
+ -keypass "$SERVER_KEY_PASSWORD" \
+ -dname "CN=localhost,OU=IT,O=MyCompany,L=Shanghai,ST=Shanghai,C=CN"
+
+# Export server certificate
+keytool -exportcert \
+ -alias server \
+ -keystore "$PROJECT_DIR/server_keystore.jks" \
+ -storepass "$SERVER_KEYSTORE_PASSWORD" \
+ -file "$PROJECT_DIR/server.crt"
+
+# Generate client keystore
+keytool -genkeypair \
+ -alias client \
+ -keyalg RSA \
+ -keysize 2048 \
+ -validity 365 \
+ -keystore "$PROJECT_DIR/client_keystore.jks" \
+ -storepass "$CLIENT_KEYSTORE_PASSWORD" \
+ -keypass "$CLIENT_KEY_PASSWORD" \
+ -dname "CN=client,OU=IT,O=MyCompany,L=Shanghai,ST=Shanghai,C=CN"
+
+# Export client certificate
+keytool -exportcert \
+ -alias client \
+ -keystore "$PROJECT_DIR/client_keystore.jks" \
+ -storepass "$CLIENT_KEYSTORE_PASSWORD" \
+ -file "$PROJECT_DIR/client.crt"
+
+# Create server truststore and import client certificate
+keytool -importcert \
+ -alias client \
+ -file "$PROJECT_DIR/client.crt" \
+ -keystore "$PROJECT_DIR/server_truststore.jks" \
+ -storepass "$SERVER_TRUSTSTORE_PASSWORD" \
+ -noprompt
+
+# Create client truststore and import server certificate
+keytool -importcert \
+ -alias server \
+ -file "$PROJECT_DIR/server.crt" \
+ -keystore "$PROJECT_DIR/client_truststore.jks" \
+ -storepass "$CLIENT_TRUSTSTORE_PASSWORD" \
+ -noprompt
+```
\ No newline at end of file
diff --git a/docs/sidebars.js b/docs/sidebars.js
index 9bf23b5e7b..17373b40dc 100644
--- a/docs/sidebars.js
+++ b/docs/sidebars.js
@@ -208,8 +208,15 @@ const sidebars = {
"seatunnel-engine/engine-jar-storage-mode",
"seatunnel-engine/tcp",
"seatunnel-engine/resource-isolation",
- "seatunnel-engine/rest-api-v1",
- "seatunnel-engine/rest-api-v2",
+ {
+ "type": "category",
+ "label": "RESTFul API",
+ "items": [
+ "seatunnel-engine/rest-api-v1",
+ "seatunnel-engine/rest-api-v2",
+ "seatunnel-engine/security"
+ ]
+ },
"seatunnel-engine/user-command",
"seatunnel-engine/logging",
"seatunnel-engine/telemetry",
diff --git a/docs/zh/seatunnel-engine/rest-api-v1.md
b/docs/zh/seatunnel-engine/rest-api-v1.md
index 1fe4eaf6f4..dbffcabada 100644
--- a/docs/zh/seatunnel-engine/rest-api-v1.md
+++ b/docs/zh/seatunnel-engine/rest-api-v1.md
@@ -1,7 +1,3 @@
----
-sidebar_position: 11
----
-
# RESTful API V1
:::caution warn
diff --git a/docs/zh/seatunnel-engine/rest-api-v2.md
b/docs/zh/seatunnel-engine/rest-api-v2.md
index ed3c6803c7..b2951b5e13 100644
--- a/docs/zh/seatunnel-engine/rest-api-v2.md
+++ b/docs/zh/seatunnel-engine/rest-api-v2.md
@@ -1,7 +1,3 @@
----
-sidebar_position: 12
----
-
# RESTful API V2
SeaTunnel有一个用于监控的API,可用于查询运行作业的状态和统计信息,以及最近完成的作业。监控API是RESTful风格的,它接受HTTP请求并使用JSON数据格式进行响应。
@@ -35,6 +31,10 @@ seatunnel:
context-path: /seatunnel
```
+## 开启 HTTPS
+
+请参考 [security](security.md)
+
## API参考
### 返回Zeta集群的概览
diff --git a/docs/zh/seatunnel-engine/security.md
b/docs/zh/seatunnel-engine/security.md
new file mode 100644
index 0000000000..d4d228880e
--- /dev/null
+++ b/docs/zh/seatunnel-engine/security.md
@@ -0,0 +1,108 @@
+---
+sidebar_position: 16
+---
+
+# Security
+
+## HTTPS 配置
+
+您可以通过开启 HTTPS 来保护您的 API 服务。HTTP 和 HTTPS 可同时开启,也可以只开启其中一个。
+
+| 参数名称 | 是否必填 | 参数描述 |
+|--------|---------|--------|
+| `enable-http` | 否 | 是否开启 HTTP 服务,默认为 `true` |
+| `port` | 否 | HTTP 服务端口,默认为 `8080` |
+| `enable-https` | 否 | 是否开启 HTTPS 服务,默认为 `false` |
+| `https-port` | 否 | HTTPS 服务端口,默认为 `8443` |
+| `key-store-path` | 当 `enable-https` 为 `true` 时必填 | KeyStore
文件路径,用于存储服务器私钥和证书 |
+| `key-store-password` | 当 `enable-https` 为 `true` 时必填 | KeyStore 密码 |
+| `key-manager-password` | 当 `enable-https` 为 `true` 时必填 | KeyManager 密码,通常与
KeyStore 密码相同 |
+| `trust-store-path` | 否 | TrustStore 文件路径,用于验证客户端证书 |
+| `trust-store-password` | 否 | TrustStore 密码 |
+
+**注意**:当 `trust-store-path` 和 `trust-store-password` 配置项不为空时,将启用双向 SSL
认证(客户端认证),要求客户端提供有效证书。
+
+```yaml
+seatunnel:
+ engine:
+ http:
+ enable-http: true
+ port: 8080
+ enable-https: true
+ https-port: 8443
+ key-store-path: "${YOUR_KEY_STORE_PATH}"
+ key-store-password: "${YOUR_KEY_STORE_PASSWORD}"
+ key-manager-password: "${YOUR_KEY_MANAGER_PASSWORD}"
+ # 可选:双向认证
+ trust-store-path: "${YOUR_TRUST_STORE_PATH}"
+ trust-store-password: "${YOUR_TRUST_STORE_PASSWORD}"
+```
+
+### 生成密钥样例
+
+```shell
+#!/bin/bash
+
+# 定义项目根目录
+PROJECT_DIR="/Users/mac/IdeaProjects/data"
+
+# 定义密码
+SERVER_KEYSTORE_PASSWORD="server_keystore_password"
+SERVER_KEY_PASSWORD="server_keystore_password"
+CLIENT_KEYSTORE_PASSWORD="client_keystore_password"
+CLIENT_KEY_PASSWORD="client_keystore_password"
+SERVER_TRUSTSTORE_PASSWORD="server_truststore_password"
+CLIENT_TRUSTSTORE_PASSWORD="client_truststore_password"
+
+# 生成服务端密钥库
+keytool -genkeypair \
+ -alias server \
+ -keyalg RSA \
+ -keysize 2048 \
+ -validity 365 \
+ -keystore "$PROJECT_DIR/server_keystore.jks" \
+ -storepass "$SERVER_KEYSTORE_PASSWORD" \
+ -keypass "$SERVER_KEY_PASSWORD" \
+ -dname "CN=localhost,OU=IT,O=MyCompany,L=Shanghai,ST=Shanghai,C=CN"
+
+# 导出服务端证书
+keytool -exportcert \
+ -alias server \
+ -keystore "$PROJECT_DIR/server_keystore.jks" \
+ -storepass "$SERVER_KEYSTORE_PASSWORD" \
+ -file "$PROJECT_DIR/server.crt"
+
+# 生成客户端密钥库
+keytool -genkeypair \
+ -alias client \
+ -keyalg RSA \
+ -keysize 2048 \
+ -validity 365 \
+ -keystore "$PROJECT_DIR/client_keystore.jks" \
+ -storepass "$CLIENT_KEYSTORE_PASSWORD" \
+ -keypass "$CLIENT_KEY_PASSWORD" \
+ -dname "CN=client,OU=IT,O=MyCompany,L=Shanghai,ST=Shanghai,C=CN"
+
+# 导出客户端证书
+keytool -exportcert \
+ -alias client \
+ -keystore "$PROJECT_DIR/client_keystore.jks" \
+ -storepass "$CLIENT_KEYSTORE_PASSWORD" \
+ -file "$PROJECT_DIR/client.crt"
+
+# 创建服务端信任库并导入客户端证书
+keytool -importcert \
+ -alias client \
+ -file "$PROJECT_DIR/client.crt" \
+ -keystore "$PROJECT_DIR/server_truststore.jks" \
+ -storepass "$SERVER_TRUSTSTORE_PASSWORD" \
+ -noprompt
+
+# 创建客户端信任库并导入服务端证书
+keytool -importcert \
+ -alias server \
+ -file "$PROJECT_DIR/server.crt" \
+ -keystore "$PROJECT_DIR/client_truststore.jks" \
+ -storepass "$CLIENT_TRUSTSTORE_PASSWORD" \
+ -noprompt
+```
\ No newline at end of file
diff --git
a/seatunnel-ci-tools/src/test/java/org/apache/seatunnel/api/file/AllFileSpecificationCheckTest.java
b/seatunnel-ci-tools/src/test/java/org/apache/seatunnel/api/file/AllFileSpecificationCheckTest.java
index 58f9c7c682..68f5fd65ef 100644
---
a/seatunnel-ci-tools/src/test/java/org/apache/seatunnel/api/file/AllFileSpecificationCheckTest.java
+++
b/seatunnel-ci-tools/src/test/java/org/apache/seatunnel/api/file/AllFileSpecificationCheckTest.java
@@ -46,7 +46,8 @@ public class AllFileSpecificationCheckTest {
@BeforeAll
public static void beforeAll() throws IOException {
List<String> fileTypesCanNotRead =
- Arrays.asList("parquet", "orc", "xlsx", "xls", "png", "jar",
"lzo", "zip", "ico");
+ Arrays.asList(
+ "parquet", "orc", "xlsx", "xls", "png", "jar", "lzo",
"zip", "ico", "jks");
List<String> fileCanNotRead =
Arrays.asList(
"seatunnel-connectors-v2/connector-file/connector-file-base/src/test/resources/encoding/gbk.json",
diff --git
a/seatunnel-engine/seatunnel-engine-common/src/main/java/org/apache/seatunnel/engine/common/config/YamlSeaTunnelDomConfigProcessor.java
b/seatunnel-engine/seatunnel-engine-common/src/main/java/org/apache/seatunnel/engine/common/config/YamlSeaTunnelDomConfigProcessor.java
index 7b4c968dd2..c54b2305de 100644
---
a/seatunnel-engine/seatunnel-engine-common/src/main/java/org/apache/seatunnel/engine/common/config/YamlSeaTunnelDomConfigProcessor.java
+++
b/seatunnel-engine/seatunnel-engine-common/src/main/java/org/apache/seatunnel/engine/common/config/YamlSeaTunnelDomConfigProcessor.java
@@ -518,6 +518,37 @@ public class YamlSeaTunnelDomConfigProcessor extends
AbstractDomConfigProcessor
getIntegerValue(
ServerConfigOptions.MasterServerConfigOptions.PORT_RANGE.key(),
getTextContent(node)));
+ } else if
(ServerConfigOptions.MasterServerConfigOptions.ENABLE_HTTPS
+ .key()
+ .equals(name)) {
+
httpConfig.setEnableHttps(getBooleanValue(getTextContent(node)));
+ } else if (ServerConfigOptions.MasterServerConfigOptions.HTTPS_PORT
+ .key()
+ .equals(name)) {
+ httpConfig.setHttpsPort(
+ getIntegerValue(
+
ServerConfigOptions.MasterServerConfigOptions.HTTPS_PORT.key(),
+ getTextContent(node)));
+ } else if
(ServerConfigOptions.MasterServerConfigOptions.KEY_STORE_PATH
+ .key()
+ .equals(name)) {
+ httpConfig.setKeyStorePath(getTextContent(node));
+ } else if
(ServerConfigOptions.MasterServerConfigOptions.KEY_STORE_PASSWORD
+ .key()
+ .equals(name)) {
+ httpConfig.setKeyStorePassword(getTextContent(node));
+ } else if
(ServerConfigOptions.MasterServerConfigOptions.KEY_MANAGER_PASSWORD
+ .key()
+ .equals(name)) {
+ httpConfig.setKeyManagerPassword(getTextContent(node));
+ } else if
(ServerConfigOptions.MasterServerConfigOptions.TRUST_STORE_PATH
+ .key()
+ .equals(name)) {
+ httpConfig.setTrustStorePath(getTextContent(node));
+ } else if
(ServerConfigOptions.MasterServerConfigOptions.TRUST_STORE_PASSWORD
+ .key()
+ .equals(name)) {
+ httpConfig.setTrustStorePassword(getTextContent(node));
} else {
LOGGER.warning("Unrecognized element: " + name);
}
diff --git
a/seatunnel-engine/seatunnel-engine-common/src/main/java/org/apache/seatunnel/engine/common/config/server/HttpConfig.java
b/seatunnel-engine/seatunnel-engine-common/src/main/java/org/apache/seatunnel/engine/common/config/server/HttpConfig.java
index 4aaabc49b1..ba7c8e8492 100644
---
a/seatunnel-engine/seatunnel-engine-common/src/main/java/org/apache/seatunnel/engine/common/config/server/HttpConfig.java
+++
b/seatunnel-engine/seatunnel-engine-common/src/main/java/org/apache/seatunnel/engine/common/config/server/HttpConfig.java
@@ -31,6 +31,33 @@ public class HttpConfig implements Serializable {
private int port =
ServerConfigOptions.MasterServerConfigOptions.PORT.defaultValue();
+ /** Whether to enable https. */
+ private boolean enableHttps =
+
ServerConfigOptions.MasterServerConfigOptions.ENABLE_HTTPS.defaultValue();
+
+ /** The port of https. */
+ private int httpsPort =
ServerConfigOptions.MasterServerConfigOptions.HTTPS_PORT.defaultValue();
+
+ /** The path of keystore file. */
+ private String keyStorePath =
+
ServerConfigOptions.MasterServerConfigOptions.KEY_STORE_PATH.defaultValue();
+
+ /** The password of keystore file. */
+ private String keyStorePassword =
+
ServerConfigOptions.MasterServerConfigOptions.KEY_STORE_PASSWORD.defaultValue();
+
+ /** The password of key manager. */
+ private String keyManagerPassword =
+
ServerConfigOptions.MasterServerConfigOptions.KEY_MANAGER_PASSWORD.defaultValue();
+
+ /** The path of truststore file. */
+ private String trustStorePath =
+
ServerConfigOptions.MasterServerConfigOptions.TRUST_STORE_PATH.defaultValue();
+
+ /** The password of truststore file. */
+ private String trustStorePassword =
+
ServerConfigOptions.MasterServerConfigOptions.TRUST_STORE_PASSWORD.defaultValue();
+
private String contextPath =
ServerConfigOptions.MasterServerConfigOptions.CONTEXT_PATH.defaultValue();
diff --git
a/seatunnel-engine/seatunnel-engine-common/src/main/java/org/apache/seatunnel/engine/common/config/server/ServerConfigOptions.java
b/seatunnel-engine/seatunnel-engine-common/src/main/java/org/apache/seatunnel/engine/common/config/server/ServerConfigOptions.java
index 6aab8dfa79..cc7fb3503a 100644
---
a/seatunnel-engine/seatunnel-engine-common/src/main/java/org/apache/seatunnel/engine/common/config/server/ServerConfigOptions.java
+++
b/seatunnel-engine/seatunnel-engine-common/src/main/java/org/apache/seatunnel/engine/common/config/server/ServerConfigOptions.java
@@ -193,6 +193,48 @@ public class ServerConfigOptions {
.defaultValue(false)
.withDescription("Whether to enable the http server.");
+ public static final Option<Boolean> ENABLE_HTTPS =
+ Options.key("enable-https")
+ .booleanType()
+ .defaultValue(false)
+ .withDescription("Whether to enable the https
server.");
+
+ public static final Option<Integer> HTTPS_PORT =
+ Options.key("port")
+ .intType()
+ .defaultValue(8443)
+ .withDescription("The port of the https server.");
+
+ public static final Option<String> KEY_STORE_PATH =
+ Options.key("key-store-path")
+ .stringType()
+ .noDefaultValue()
+ .withDescription("The key store path of the https
server.");
+
+ public static final Option<String> KEY_STORE_PASSWORD =
+ Options.key("key-store-password")
+ .stringType()
+ .noDefaultValue()
+ .withDescription("The key store password of the https
server.");
+
+ public static final Option<String> KEY_MANAGER_PASSWORD =
+ Options.key("key-manager-password")
+ .stringType()
+ .noDefaultValue()
+ .withDescription("The key manager password of the
https server.");
+
+ public static final Option<String> TRUST_STORE_PATH =
+ Options.key("trust-store-path")
+ .stringType()
+ .noDefaultValue()
+ .withDescription("The trust store path of the https
server.");
+
+ public static final Option<String> TRUST_STORE_PASSWORD =
+ Options.key("trust-store-password")
+ .stringType()
+ .noDefaultValue()
+ .withDescription("The trust store password of the
https server.");
+
public static final Option<String> CONTEXT_PATH =
Options.key("context-path")
.stringType()
diff --git
a/seatunnel-engine/seatunnel-engine-common/src/main/resources/seatunnel.yaml
b/seatunnel-engine/seatunnel-engine-common/src/main/resources/seatunnel.yaml
index 9177a9afca..0d51dd5305 100644
--- a/seatunnel-engine/seatunnel-engine-common/src/main/resources/seatunnel.yaml
+++ b/seatunnel-engine/seatunnel-engine-common/src/main/resources/seatunnel.yaml
@@ -44,4 +44,4 @@ seatunnel:
enabled: false
http:
enable-http: true
- port: 8080
\ No newline at end of file
+ port: 8080
diff --git
a/seatunnel-engine/seatunnel-engine-server/src/main/java/org/apache/seatunnel/engine/server/JettyService.java
b/seatunnel-engine/seatunnel-engine-server/src/main/java/org/apache/seatunnel/engine/server/JettyService.java
index 4d9b75abf5..7f88c25662 100644
---
a/seatunnel-engine/seatunnel-engine-server/src/main/java/org/apache/seatunnel/engine/server/JettyService.java
+++
b/seatunnel-engine/seatunnel-engine-server/src/main/java/org/apache/seatunnel/engine/server/JettyService.java
@@ -18,12 +18,15 @@
package org.apache.seatunnel.engine.server;
import org.apache.seatunnel.shade.org.eclipse.jetty.server.Server;
+import org.apache.seatunnel.shade.org.eclipse.jetty.server.ServerConnector;
import org.apache.seatunnel.shade.org.eclipse.jetty.servlet.DefaultServlet;
import org.apache.seatunnel.shade.org.eclipse.jetty.servlet.FilterHolder;
import
org.apache.seatunnel.shade.org.eclipse.jetty.servlet.ServletContextHandler;
import org.apache.seatunnel.shade.org.eclipse.jetty.servlet.ServletHolder;
+import org.apache.seatunnel.shade.org.eclipse.jetty.util.ssl.SslContextFactory;
import org.apache.seatunnel.engine.common.config.SeaTunnelConfig;
+import org.apache.seatunnel.engine.common.config.server.HttpConfig;
import org.apache.seatunnel.engine.server.rest.filter.ExceptionHandlingFilter;
import org.apache.seatunnel.engine.server.rest.servlet.AllLogNameServlet;
import org.apache.seatunnel.engine.server.rest.servlet.AllNodeLogServlet;
@@ -46,6 +49,7 @@ import
org.apache.seatunnel.engine.server.rest.servlet.UpdateTagsServlet;
import com.hazelcast.spi.impl.NodeEngineImpl;
import lombok.extern.slf4j.Slf4j;
+import shade.org.apache.commons.lang3.StringUtils;
import javax.servlet.DispatcherType;
import javax.servlet.MultipartConfigElement;
@@ -95,7 +99,49 @@ public class JettyService {
port,
seaTunnelConfig.getEngineConfig().getHttpConfig().getPortRange());
}
log.info("SeaTunnel REST service will start on port {}", port);
- this.server = new Server(port);
+ this.server = new Server();
+
+ if (seaTunnelConfig.getEngineConfig().getHttpConfig().isEnabled()) {
+ // Enable http
+ ServerConnector httpConnector = new ServerConnector(server);
+ httpConnector.setPort(port);
+ server.addConnector(httpConnector);
+ }
+
+ if (seaTunnelConfig.getEngineConfig().getHttpConfig().isEnableHttps())
{
+ // Enable https
+ log.info("SeaTunnel REST service will start on https port {}",
port);
+ enableHttps(server, seaTunnelConfig);
+ }
+ }
+
+ public void enableHttps(Server server, SeaTunnelConfig seaTunnelConfig) {
+
+ HttpConfig httpConfig =
seaTunnelConfig.getEngineConfig().getHttpConfig();
+ int httpsPort = httpConfig.getHttpsPort();
+ String keyStorePath = httpConfig.getKeyStorePath();
+ String keyStorePassword = httpConfig.getKeyStorePassword();
+ String keyManagerPassword = httpConfig.getKeyManagerPassword();
+ String trustStorePath = httpConfig.getTrustStorePath();
+ String trustStorePassword = httpConfig.getTrustStorePassword();
+
+ SslContextFactory.Server sslContextFactory = new
SslContextFactory.Server();
+
+ sslContextFactory.setKeyStorePath(keyStorePath);
+ sslContextFactory.setKeyStorePassword(keyStorePassword);
+ sslContextFactory.setKeyManagerPassword(keyManagerPassword);
+
+ if (StringUtils.isNotBlank(trustStorePath) &&
StringUtils.isNotBlank(trustStorePassword)) {
+ sslContextFactory.setTrustStorePath(trustStorePath);
+ sslContextFactory.setTrustStorePassword(trustStorePassword);
+ sslContextFactory.setNeedClientAuth(true);
+ log.info("SeaTunnel REST service will start with mutual auth");
+ }
+
+ ServerConnector sslConnector = new ServerConnector(server,
sslContextFactory);
+ sslConnector.setPort(httpsPort);
+ server.addConnector(sslConnector);
+ log.info("SeaTunnel REST service will start on https port {}",
httpsPort);
}
public void createJettyServer() {
diff --git
a/seatunnel-engine/seatunnel-engine-server/src/main/java/org/apache/seatunnel/engine/server/SeaTunnelServer.java
b/seatunnel-engine/seatunnel-engine-server/src/main/java/org/apache/seatunnel/engine/server/SeaTunnelServer.java
index bd39f21ed0..36428cfbe0 100644
---
a/seatunnel-engine/seatunnel-engine-server/src/main/java/org/apache/seatunnel/engine/server/SeaTunnelServer.java
+++
b/seatunnel-engine/seatunnel-engine-server/src/main/java/org/apache/seatunnel/engine/server/SeaTunnelServer.java
@@ -152,7 +152,8 @@ public class SeaTunnelServer
}
// Start Jetty server
- if (seaTunnelConfig.getEngineConfig().getHttpConfig().isEnabled()) {
+ if (seaTunnelConfig.getEngineConfig().getHttpConfig().isEnabled()
+ ||
seaTunnelConfig.getEngineConfig().getHttpConfig().isEnableHttps()) {
jettyService = new JettyService(nodeEngine, seaTunnelConfig);
jettyService.createJettyServer();
}
diff --git
a/seatunnel-engine/seatunnel-engine-server/src/test/java/org/apache/seatunnel/engine/server/rest/RestApiHttpsForTruststoreTest.java
b/seatunnel-engine/seatunnel-engine-server/src/test/java/org/apache/seatunnel/engine/server/rest/RestApiHttpsForTruststoreTest.java
new file mode 100644
index 0000000000..847ff7e7fb
--- /dev/null
+++
b/seatunnel-engine/seatunnel-engine-server/src/test/java/org/apache/seatunnel/engine/server/rest/RestApiHttpsForTruststoreTest.java
@@ -0,0 +1,172 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.seatunnel.engine.server.rest;
+
+import org.apache.seatunnel.engine.common.config.SeaTunnelConfig;
+import org.apache.seatunnel.engine.common.config.server.HttpConfig;
+import org.apache.seatunnel.engine.common.runtime.ExecutionMode;
+import org.apache.seatunnel.engine.server.AbstractSeaTunnelServerTest;
+import org.apache.seatunnel.engine.server.SeaTunnelServer;
+import org.apache.seatunnel.engine.server.SeaTunnelServerStarter;
+import org.apache.seatunnel.engine.server.TestUtils;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.DisabledOnOs;
+import org.junit.jupiter.api.condition.OS;
+
+import com.hazelcast.config.Config;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLHandshakeException;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.net.ConnectException;
+import java.net.HttpURLConnection;
+import java.util.stream.Collectors;
+
+/** Test for Rest API with HTTPS. */
+@DisabledOnOs(OS.WINDOWS)
+public class RestApiHttpsForTruststoreTest extends AbstractSeaTunnelServerTest
{
+ private static final int HTTP_PORT = 18080;
+ private static final int HTTPS_PORT = 18443;
+ private static final String SERVER_KEYSTORE_PASSWORD =
"server_keystore_password";
+ private static final String SERVER_TRUSTSTORE_PASSWORD =
"server_truststore_password";
+ private static final String CLIENT_KEYSTORE_PASSWORD =
"client_keystore_password";
+ private static final String CLIENT_TRUSTSTORE_PASSWORD =
"client_truststore_password";
+
+ @BeforeAll
+ public void setUp() {
+ String name = this.getClass().getName();
+ Config hazelcastConfig = Config.loadFromString(getHazelcastConfig());
+ hazelcastConfig.setClusterName(
+ TestUtils.getClusterName("RestApiHttpsForTruststoreTest_" +
name));
+ SeaTunnelConfig seaTunnelConfig = loadSeaTunnelConfig();
+ seaTunnelConfig.setHazelcastConfig(hazelcastConfig);
+ seaTunnelConfig.getEngineConfig().setMode(ExecutionMode.LOCAL);
+
+ HttpConfig httpConfig =
seaTunnelConfig.getEngineConfig().getHttpConfig();
+ // Not enabled Http
+ httpConfig.setEnabled(false);
+ httpConfig.setPort(HTTP_PORT);
+ // Enabled Https
+ httpConfig.setHttpsPort(HTTPS_PORT);
+ httpConfig.setEnableHttps(true);
+
+ httpConfig.setKeyStorePath(getPath("server_keystore.jks"));
+ httpConfig.setTrustStorePath(getPath("server_truststore.jks"));
+ httpConfig.setKeyManagerPassword(SERVER_KEYSTORE_PASSWORD);
+ httpConfig.setKeyStorePassword(SERVER_KEYSTORE_PASSWORD);
+ httpConfig.setTrustStorePassword(SERVER_TRUSTSTORE_PASSWORD);
+
+ instance =
SeaTunnelServerStarter.createHazelcastInstance(seaTunnelConfig);
+ nodeEngine = instance.node.nodeEngine;
+ server = nodeEngine.getService(SeaTunnelServer.SERVICE_NAME);
+ LOGGER = nodeEngine.getLogger(AbstractSeaTunnelServerTest.class);
+ }
+
+ public String getPath(String confFile) {
+ return System.getProperty("user.dir") + "/src/test/resources/https/" +
confFile;
+ }
+
+ @Test
+ public void testRestApiHttp() {
+ Assertions.assertThrows(
+ ConnectException.class,
+ () -> {
+ HttpURLConnection conn = null;
+ BufferedReader in = null;
+ try {
+ java.net.URL url =
+ new java.net.URL("http://localhost:" +
HTTP_PORT + "/overview");
+ conn = (HttpURLConnection) url.openConnection();
+
+ Assertions.assertEquals(200, conn.getResponseCode());
+
+ in = new BufferedReader(new
InputStreamReader(conn.getInputStream()));
+ String response =
in.lines().collect(Collectors.joining());
+
+
Assertions.assertTrue(response.contains("projectVersion"));
+ } finally {
+ if (in != null) {
+ in.close();
+ }
+ if (conn != null) {
+ conn.disconnect();
+ }
+ }
+ });
+ }
+
+ @Test
+ public void testRestApiHttps() throws Exception {
+ SSLContext sslContext =
+ SSLUtils.createSSLContextWithTrustStore(
+ getPath("client_keystore.jks"),
+ CLIENT_KEYSTORE_PASSWORD,
+ getPath("client_truststore.jks"),
+ CLIENT_TRUSTSTORE_PASSWORD);
+
+ HttpsURLConnection conn =
+ (HttpsURLConnection)
+ new java.net.URL("https://localhost:" + HTTPS_PORT +
"/overview")
+ .openConnection();
+ conn.setSSLSocketFactory(sslContext.getSocketFactory());
+
+ try (BufferedReader in = new BufferedReader(new
InputStreamReader(conn.getInputStream()))) {
+ Assertions.assertEquals(200, conn.getResponseCode());
+ String response = in.lines().collect(Collectors.joining());
+ Assertions.assertTrue(response.contains("projectVersion"));
+ } finally {
+ conn.disconnect();
+ }
+ }
+
+ @Test
+ public void testRestApiHttpsFailed() throws Exception {
+ Assertions.assertThrows(
+ SSLHandshakeException.class,
+ () -> {
+ java.net.URL url =
+ new java.net.URL("https://localhost:" + HTTPS_PORT
+ "/overview");
+ HttpURLConnection conn = (HttpURLConnection)
url.openConnection();
+ conn.getResponseCode();
+ });
+ }
+
+ @Test
+ public void testRestApiHttpsFailedWithTwoWayAuthentication() throws
Exception {
+ Assertions.assertThrows(
+ SSLHandshakeException.class,
+ () -> {
+ SSLContext sslContext =
+ SSLUtils.createSSLContextWithoutTrustStore(
+ getPath("client_keystore.jks"),
CLIENT_KEYSTORE_PASSWORD);
+ HttpsURLConnection conn =
+ (HttpsURLConnection)
+ new java.net.URL(
+ "https://localhost:" +
HTTPS_PORT + "/overview")
+ .openConnection();
+ conn.setSSLSocketFactory(sslContext.getSocketFactory());
+ conn.getInputStream();
+ });
+ }
+}
diff --git
a/seatunnel-engine/seatunnel-engine-server/src/test/java/org/apache/seatunnel/engine/server/rest/RestApiHttpsTest.java
b/seatunnel-engine/seatunnel-engine-server/src/test/java/org/apache/seatunnel/engine/server/rest/RestApiHttpsTest.java
new file mode 100644
index 0000000000..fe55a70e91
--- /dev/null
+++
b/seatunnel-engine/seatunnel-engine-server/src/test/java/org/apache/seatunnel/engine/server/rest/RestApiHttpsTest.java
@@ -0,0 +1,129 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.seatunnel.engine.server.rest;
+
+import org.apache.seatunnel.engine.common.config.SeaTunnelConfig;
+import org.apache.seatunnel.engine.common.config.server.HttpConfig;
+import org.apache.seatunnel.engine.common.runtime.ExecutionMode;
+import org.apache.seatunnel.engine.server.AbstractSeaTunnelServerTest;
+import org.apache.seatunnel.engine.server.SeaTunnelServer;
+import org.apache.seatunnel.engine.server.SeaTunnelServerStarter;
+import org.apache.seatunnel.engine.server.TestUtils;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.DisabledOnOs;
+import org.junit.jupiter.api.condition.OS;
+
+import com.hazelcast.config.Config;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLHandshakeException;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
+import java.util.stream.Collectors;
+
+/** Test for Rest API with HTTPS. */
+@DisabledOnOs(OS.WINDOWS)
+public class RestApiHttpsTest extends AbstractSeaTunnelServerTest {
+ private static final int HTTP_PORT = 28080;
+ private static final int HTTPS_PORT = 28443;
+ private static final String SERVER_KEYSTORE_PASSWORD =
"server_keystore_password";
+ private static final String CLIENT_KEYSTORE_PASSWORD =
"client_keystore_password";
+
+ @BeforeAll
+ public void setUp() {
+ String name = this.getClass().getName();
+ Config hazelcastConfig = Config.loadFromString(getHazelcastConfig());
+
hazelcastConfig.setClusterName(TestUtils.getClusterName("RestApiHttpsTest_" +
name));
+ SeaTunnelConfig seaTunnelConfig = loadSeaTunnelConfig();
+ seaTunnelConfig.setHazelcastConfig(hazelcastConfig);
+ seaTunnelConfig.getEngineConfig().setMode(ExecutionMode.LOCAL);
+
+ HttpConfig httpConfig =
seaTunnelConfig.getEngineConfig().getHttpConfig();
+ httpConfig.setEnabled(true);
+ httpConfig.setPort(HTTP_PORT);
+ httpConfig.setHttpsPort(HTTPS_PORT);
+ httpConfig.setEnableHttps(true);
+
+ httpConfig.setKeyStorePath(getPath("server_keystore.jks"));
+ httpConfig.setKeyManagerPassword(SERVER_KEYSTORE_PASSWORD);
+ httpConfig.setKeyStorePassword(SERVER_KEYSTORE_PASSWORD);
+
+ instance =
SeaTunnelServerStarter.createHazelcastInstance(seaTunnelConfig);
+ nodeEngine = instance.node.nodeEngine;
+ server = nodeEngine.getService(SeaTunnelServer.SERVICE_NAME);
+ LOGGER = nodeEngine.getLogger(AbstractSeaTunnelServerTest.class);
+ }
+
+ public String getPath(String confFile) {
+ return System.getProperty("user.dir") + "/src/test/resources/https/" +
confFile;
+ }
+
+ @Test
+ public void testRestApiHttp() throws Exception {
+ HttpURLConnection conn =
+ (HttpURLConnection)
+ new java.net.URL("http://localhost:" + HTTP_PORT +
"/overview")
+ .openConnection();
+ try (BufferedReader in = new BufferedReader(new
InputStreamReader(conn.getInputStream()))) {
+
+ Assertions.assertEquals(200, conn.getResponseCode());
+ String response = in.lines().collect(Collectors.joining());
+ Assertions.assertTrue(response.contains("projectVersion"));
+ } finally {
+ conn.disconnect();
+ }
+ }
+
+ @Test
+ public void testRestApiHttps() throws Exception {
+ SSLContext sslContext =
+ SSLUtils.createSSLContext(getPath("client_keystore.jks"),
CLIENT_KEYSTORE_PASSWORD);
+
+ HttpsURLConnection conn =
+ (HttpsURLConnection)
+ new java.net.URL("https://localhost:" + HTTPS_PORT +
"/overview")
+ .openConnection();
+ conn.setSSLSocketFactory(sslContext.getSocketFactory());
+
+ try (BufferedReader in = new BufferedReader(new
InputStreamReader(conn.getInputStream()))) {
+ Assertions.assertEquals(200, conn.getResponseCode());
+ String response = in.lines().collect(Collectors.joining());
+ Assertions.assertTrue(response.contains("projectVersion"));
+ } finally {
+ conn.disconnect();
+ }
+ }
+
+ @Test
+ public void testRestApiHttpsFailed() {
+ Assertions.assertThrows(
+ SSLHandshakeException.class,
+ () -> {
+ java.net.URL url =
+ new java.net.URL("https://localhost:" + HTTPS_PORT
+ "/overview");
+ HttpURLConnection conn = (HttpURLConnection)
url.openConnection();
+ conn.getResponseCode();
+ });
+ }
+}
diff --git
a/seatunnel-engine/seatunnel-engine-server/src/test/java/org/apache/seatunnel/engine/server/rest/SSLUtils.java
b/seatunnel-engine/seatunnel-engine-server/src/test/java/org/apache/seatunnel/engine/server/rest/SSLUtils.java
new file mode 100644
index 0000000000..ed2583704d
--- /dev/null
+++
b/seatunnel-engine/seatunnel-engine-server/src/test/java/org/apache/seatunnel/engine/server/rest/SSLUtils.java
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.seatunnel.engine.server.rest;
+
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509TrustManager;
+
+import java.io.FileInputStream;
+import java.security.KeyStore;
+import java.security.cert.X509Certificate;
+
+public class SSLUtils {
+
+ public static SSLContext createSSLContext(String keystorePath, String
keystorePass)
+ throws Exception {
+ KeyStore clientStore = KeyStore.getInstance("JKS");
+ try (FileInputStream fis = new FileInputStream(keystorePath)) {
+ clientStore.load(fis, keystorePass.toCharArray());
+ }
+
+ KeyManagerFactory kmf =
+
KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+ kmf.init(clientStore, keystorePass.toCharArray());
+
+ TrustManager[] trustAllCerts =
+ new TrustManager[] {
+ new X509TrustManager() {
+ public X509Certificate[] getAcceptedIssuers() {
+ return null;
+ }
+
+ public void checkClientTrusted(X509Certificate[]
certs, String authType) {}
+
+ public void checkServerTrusted(X509Certificate[]
certs, String authType) {}
+ }
+ };
+
+ SSLContext sslContext = SSLContext.getInstance("TLS");
+ sslContext.init(kmf.getKeyManagers(), trustAllCerts, null);
+
+ return sslContext;
+ }
+
+ public static SSLContext createSSLContextWithTrustStore(
+ String keystorePath, String keystorePass, String truststorePath,
String truststorePass)
+ throws Exception {
+ KeyStore clientStore = KeyStore.getInstance("JKS");
+ try (FileInputStream fis = new FileInputStream(keystorePath)) {
+ clientStore.load(fis, keystorePass.toCharArray());
+ }
+
+ KeyManagerFactory kmf =
+
KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+ kmf.init(clientStore, keystorePass.toCharArray());
+
+ KeyStore trustStore = KeyStore.getInstance("JKS");
+ try (FileInputStream fis = new FileInputStream(truststorePath)) {
+ trustStore.load(fis, truststorePass.toCharArray());
+ }
+
+ TrustManagerFactory tmf =
+
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ tmf.init(trustStore);
+
+ SSLContext sslContext = SSLContext.getInstance("TLS");
+ sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+
+ return sslContext;
+ }
+
+ public static SSLContext createSSLContextWithoutTrustStore(
+ String keystorePath, String keystorePass) throws Exception {
+ KeyStore clientStore = KeyStore.getInstance("JKS");
+ try (FileInputStream fis = new FileInputStream(keystorePath)) {
+ clientStore.load(fis, keystorePass.toCharArray());
+ }
+
+ KeyManagerFactory kmf =
+
KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+ kmf.init(clientStore, keystorePass.toCharArray());
+
+ SSLContext sslContext = SSLContext.getInstance("TLS");
+ sslContext.init(kmf.getKeyManagers(), null, null);
+
+ return sslContext;
+ }
+}
diff --git
a/seatunnel-engine/seatunnel-engine-server/src/test/resources/https/client_keystore.jks
b/seatunnel-engine/seatunnel-engine-server/src/test/resources/https/client_keystore.jks
new file mode 100644
index 0000000000..f869d68a8a
Binary files /dev/null and
b/seatunnel-engine/seatunnel-engine-server/src/test/resources/https/client_keystore.jks
differ
diff --git
a/seatunnel-engine/seatunnel-engine-server/src/test/resources/https/client_truststore.jks
b/seatunnel-engine/seatunnel-engine-server/src/test/resources/https/client_truststore.jks
new file mode 100644
index 0000000000..02c936e1dd
Binary files /dev/null and
b/seatunnel-engine/seatunnel-engine-server/src/test/resources/https/client_truststore.jks
differ
diff --git
a/seatunnel-engine/seatunnel-engine-server/src/test/resources/https/server_keystore.jks
b/seatunnel-engine/seatunnel-engine-server/src/test/resources/https/server_keystore.jks
new file mode 100644
index 0000000000..afbd5db6bc
Binary files /dev/null and
b/seatunnel-engine/seatunnel-engine-server/src/test/resources/https/server_keystore.jks
differ
diff --git
a/seatunnel-engine/seatunnel-engine-server/src/test/resources/https/server_truststore.jks
b/seatunnel-engine/seatunnel-engine-server/src/test/resources/https/server_truststore.jks
new file mode 100644
index 0000000000..b37f6af76d
Binary files /dev/null and
b/seatunnel-engine/seatunnel-engine-server/src/test/resources/https/server_truststore.jks
differ