Skip to content

Commit 5328e3c

Browse files
authored
feat: support opensearch client cert auth (#13641)
1 parent ef4504a commit 5328e3c

29 files changed

Lines changed: 896 additions & 190 deletions

File tree

.github/workflows/skywalking.yaml

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -387,9 +387,6 @@ jobs:
387387
- name: Storage ES 8.9.0
388388
config: test/e2e-v2/cases/storage/es/e2e.yaml
389389
env: ES_VERSION=8.18.1
390-
- name: Storage OpenSearch 1.1.0
391-
config: test/e2e-v2/cases/storage/opensearch/e2e.yaml
392-
env: OPENSEARCH_VERSION=1.1.0
393390
- name: Storage OpenSearch 1.3.10
394391
config: test/e2e-v2/cases/storage/opensearch/e2e.yaml
395392
env: OPENSEARCH_VERSION=1.3.10
@@ -1121,4 +1118,4 @@ jobs:
11211118
[[ ${e2eJavaVersionResults} == 'success' ]] || [[ ${execute} != 'true' && ${e2eJavaVersionResults} == 'skipped' ]] || exit -7;
11221119
[[ ${timeConsumingITResults} == 'success' ]] || [[ ${execute} != 'true' && ${timeConsumingITResults} == 'skipped' ]] || exit -8;
11231120
1124-
exit 0;
1121+
exit 0;

.licenserc.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,10 @@ dependency:
109109
version: 2.13.4
110110
license: Apache-2.0
111111
- name: com.fasterxml.jackson.datatype:jackson-datatype-jsr310
112-
version: 2.18.2
112+
version: 2.20.1
113113
license: Apache-2.0
114114
- name: com.fasterxml.jackson.datatype:jackson-datatype-jdk8
115-
version: 2.18.2
115+
version: 2.20.1
116116
license: Apache-2.0
117117
- name: com.fasterxml.jackson.dataformat:jackson-dataformat-yaml
118118
version: 2.15.2
@@ -139,7 +139,7 @@ dependency:
139139
version: 1.2.1
140140
license: Apache-2.0
141141
- name: com.aayushatharva.brotli4j:service
142-
version: 1.18.0
142+
version: 1.20.0
143143
license: Apache-2.0
144144
- name: io.vertx:vertx-grpc
145145
version: 4.5.9

dist-material/release-docs/LICENSE

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -210,8 +210,8 @@ The following components are provided under the Apache-2.0 License. See project
210210
The text of each license is the standard Apache 2.0 license.
211211
https://mvnrepository.com/artifact/build.buf.protoc-gen-validate/pgv-java-stub/1.2.1 Apache-2.0
212212
https://mvnrepository.com/artifact/build.buf.protoc-gen-validate/protoc-gen-validate/1.2.1 Apache-2.0
213-
https://mvnrepository.com/artifact/com.aayushatharva.brotli4j/brotli4j/1.18.0 Apache-2.0
214-
https://mvnrepository.com/artifact/com.aayushatharva.brotli4j/service/1.18.0 Apache-2.0
213+
https://mvnrepository.com/artifact/com.aayushatharva.brotli4j/brotli4j/1.20.0 Apache-2.0
214+
https://mvnrepository.com/artifact/com.aayushatharva.brotli4j/service/1.20.0 Apache-2.0
215215
https://mvnrepository.com/artifact/com.alibaba.nacos/nacos-auth-plugin/2.3.2 Apache-2.0
216216
https://mvnrepository.com/artifact/com.alibaba.nacos/nacos-client/2.3.2 Apache-2.0
217217
https://mvnrepository.com/artifact/com.alibaba.nacos/nacos-encryption-plugin/2.3.2 Apache-2.0
@@ -222,8 +222,8 @@ The text of each license is the standard Apache 2.0 license.
222222
https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind/2.16.0 Apache-2.0
223223
https://mvnrepository.com/artifact/com.fasterxml.jackson.dataformat/jackson-dataformat-yaml/2.15.2 Apache-2.0
224224
https://mvnrepository.com/artifact/com.fasterxml.jackson.datatype/jackson-datatype-guava/2.12.0 Apache-2.0
225-
https://mvnrepository.com/artifact/com.fasterxml.jackson.datatype/jackson-datatype-jdk8/2.18.2 Apache-2.0
226-
https://mvnrepository.com/artifact/com.fasterxml.jackson.datatype/jackson-datatype-jsr310/2.18.2 Apache-2.0
225+
https://mvnrepository.com/artifact/com.fasterxml.jackson.datatype/jackson-datatype-jdk8/2.20.1 Apache-2.0
226+
https://mvnrepository.com/artifact/com.fasterxml.jackson.datatype/jackson-datatype-jsr310/2.20.1 Apache-2.0
227227
https://mvnrepository.com/artifact/com.fasterxml.jackson.module/jackson-module-kotlin/2.13.4 Apache-2.0
228228
https://mvnrepository.com/artifact/com.fasterxml/classmate/1.5.1 Apache-2.0
229229
https://mvnrepository.com/artifact/com.google.api.grpc/proto-google-common-protos/2.48.0 Apache-2.0
@@ -238,12 +238,12 @@ The text of each license is the standard Apache 2.0 license.
238238
https://mvnrepository.com/artifact/com.google.inject/guice/4.1.0 Apache-2.0
239239
https://mvnrepository.com/artifact/com.google.j2objc/j2objc-annotations/2.8 Apache-2.0
240240
https://mvnrepository.com/artifact/com.graphql-java/java-dataloader/3.2.1 Apache-2.0
241-
https://mvnrepository.com/artifact/com.linecorp.armeria/armeria/1.32.0 Apache-2.0
242-
https://mvnrepository.com/artifact/com.linecorp.armeria/armeria-graphql/1.32.0 Apache-2.0
243-
https://mvnrepository.com/artifact/com.linecorp.armeria/armeria-graphql-protocol/1.32.0 Apache-2.0
244-
https://mvnrepository.com/artifact/com.linecorp.armeria/armeria-grpc/1.32.0 Apache-2.0
245-
https://mvnrepository.com/artifact/com.linecorp.armeria/armeria-grpc-protocol/1.32.0 Apache-2.0
246-
https://mvnrepository.com/artifact/com.linecorp.armeria/armeria-protobuf/1.32.0 Apache-2.0
241+
https://mvnrepository.com/artifact/com.linecorp.armeria/armeria/1.34.2 Apache-2.0
242+
https://mvnrepository.com/artifact/com.linecorp.armeria/armeria-graphql/1.34.2 Apache-2.0
243+
https://mvnrepository.com/artifact/com.linecorp.armeria/armeria-graphql-protocol/1.34.2 Apache-2.0
244+
https://mvnrepository.com/artifact/com.linecorp.armeria/armeria-grpc/1.34.2 Apache-2.0
245+
https://mvnrepository.com/artifact/com.linecorp.armeria/armeria-grpc-protocol/1.34.2 Apache-2.0
246+
https://mvnrepository.com/artifact/com.linecorp.armeria/armeria-protobuf/1.34.2 Apache-2.0
247247
https://mvnrepository.com/artifact/com.orbitz.consul/consul-client/1.5.3 Apache-2.0
248248
https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp/3.14.9 Apache-2.0
249249
https://mvnrepository.com/artifact/com.squareup.okio/okio/1.17.2 Apache-2.0
@@ -300,6 +300,7 @@ The text of each license is the standard Apache 2.0 license.
300300
https://mvnrepository.com/artifact/io.grpc/grpc-services/1.70.0 Apache-2.0
301301
https://mvnrepository.com/artifact/io.grpc/grpc-stub/1.70.0 Apache-2.0
302302
https://mvnrepository.com/artifact/io.grpc/grpc-util/1.70.0 Apache-2.0
303+
https://mvnrepository.com/artifact/io.micrometer/context-propagation/1.2.0 Apache-2.0
303304
https://mvnrepository.com/artifact/io.micrometer/micrometer-commons/1.14.4 Apache-2.0
304305
https://mvnrepository.com/artifact/io.micrometer/micrometer-core/1.14.4 Apache-2.0
305306
https://mvnrepository.com/artifact/io.micrometer/micrometer-observation/1.14.4 Apache-2.0
@@ -369,6 +370,7 @@ The text of each license is the standard Apache 2.0 license.
369370
https://mvnrepository.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-jdk8/1.6.4 Apache-2.0
370371
https://mvnrepository.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-reactive/1.6.4 Apache-2.0
371372
https://mvnrepository.com/artifact/org.jetbrains/annotations/13.0 Apache-2.0
373+
https://mvnrepository.com/artifact/org.jspecify/jspecify/1.0.0 Apache-2.0
372374
https://mvnrepository.com/artifact/org.lz4/lz4-java/1.8.0 Apache-2.0
373375
https://mvnrepository.com/artifact/org.slf4j/jcl-over-slf4j/1.7.30 Apache-2.0
374376
https://mvnrepository.com/artifact/org.slf4j/log4j-over-slf4j/1.7.30 Apache-2.0
@@ -543,7 +545,7 @@ The text of each license is also included in licenses/LICENSE-[project].txt.
543545
https://npmjs.com/package/nanoid/v/3.3.8 3.3.8 MIT
544546
https://mvnrepository.com/artifact/org.checkerframework/checker-qual/3.33.0 MIT
545547
https://mvnrepository.com/artifact/org.codehaus.mojo/animal-sniffer-annotations/1.24 MIT
546-
https://mvnrepository.com/artifact/org.curioswitch.curiostack/protobuf-jackson/2.7.0 MIT
548+
https://mvnrepository.com/artifact/org.curioswitch.curiostack/protobuf-jackson/2.8.1 MIT
547549
https://mvnrepository.com/artifact/org.slf4j/slf4j-api/1.7.30 MIT
548550
https://npmjs.com/package/pinia/v/2.0.28 2.0.28 MIT
549551
https://npmjs.com/package/pinia/node_modules/vue-demi/v/0.13.11 0.13.11 MIT

docs/en/changes/changes.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
* Add `LatestLabeledFunction` for meter.
1515
* MAL Labeled metrics support additional attributes.
1616
* Bump up netty to 4.2.9.Final.
17+
* Add support for OpenSearch/ElasticSearch client certificate authentication.
1718

1819
#### UI
1920
* Fix the missing icon in new native trace view.

docs/en/setup/backend/storages/elasticsearch.md

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ In order to activate OpenSearch as storage, set the storage provider to **elasti
1111

1212
We support and tested the following versions of OpenSearch:
1313

14-
- 1.1.0, 1.3.10
14+
- 1.3.10
1515
- 2.4.0, 2.8.0, 3.0.0
1616

1717
## Elasticsearch
@@ -51,6 +51,8 @@ storage:
5151
protocol: ${SW_STORAGE_ES_HTTP_PROTOCOL:"http"}
5252
trustStorePath: ${SW_STORAGE_ES_SSL_JKS_PATH:""}
5353
trustStorePass: ${SW_STORAGE_ES_SSL_JKS_PASS:""}
54+
keyStorePath: ${SW_STORAGE_ES_SSL_KEY_STORE_PATH:""} # Path to client certificate keystore for mutual TLS (OpenSearch/Elasticsearch client cert auth). Supports PKCS12 (.p12, .pfx) and JKS (.jks) formats.
55+
keyStorePass: ${SW_STORAGE_ES_SSL_KEY_STORE_PASS:""} # Password for the client certificate keystore. Can be managed via secretsManagementFile.
5456
user: ${SW_ES_USER:""}
5557
password: ${SW_ES_PASSWORD:""}
5658
secretsManagementFile: ${SW_ES_SECRETS_MANAGEMENT_FILE:""} # Secrets management file in the properties format includes the username, password, which are managed by 3rd party tool.
@@ -83,7 +85,9 @@ storage:
8385
enableCustomRouting: ${SW_STORAGE_ES_ENABLE_CUSTOM_ROUTING:false}
8486
```
8587
86-
### ElasticSearch With Https SSL Encrypting communications.
88+
### ElasticSearch/OpenSearch With HTTPS SSL Encrypting Communications
89+
90+
#### Basic HTTPS with Server Certificate Verification
8791
8892
Example:
8993
@@ -103,6 +107,32 @@ storage:
103107
- File at `trustStorePath` is being monitored. Once it is changed, the ElasticSearch client will reconnect.
104108
- `trustStorePass` could be changed in the runtime through [**Secrets Management File Of ElasticSearch Authentication**](#secrets-management-file-of-elasticsearch-authentication).
105109

110+
#### Mutual TLS (mTLS) with Client Certificate Authentication
111+
112+
For enhanced security, you can configure mutual TLS where the client presents a certificate to the server. This is commonly used with OpenSearch security plugin's client certificate authentication.
113+
114+
Example:
115+
116+
```yaml
117+
storage:
118+
selector: ${SW_STORAGE:elasticsearch}
119+
elasticsearch:
120+
namespace: ${SW_NAMESPACE:""}
121+
clusterNodes: ${SW_STORAGE_ES_CLUSTER_NODES:localhost:9200}
122+
protocol: ${SW_STORAGE_ES_HTTP_PROTOCOL:"https"}
123+
trustStorePath: ${SW_STORAGE_ES_SSL_JKS_PATH:"../truststore.jks"}
124+
trustStorePass: ${SW_STORAGE_ES_SSL_JKS_PASS:"changeit"}
125+
keyStorePath: ${SW_STORAGE_ES_SSL_KEY_STORE_PATH:"../client.p12"}
126+
keyStorePass: ${SW_STORAGE_ES_SSL_KEY_STORE_PASS:"changeit"}
127+
...
128+
```
129+
130+
- `keyStorePath` points to the client certificate keystore file. Supports both PKCS12 (`.p12`, `.pfx`) and JKS (`.jks`) formats.
131+
- `keyStorePass` is the password for the client keystore. Use empty string `""` for keystores without password.
132+
- Both `trustStorePath` and `keyStorePath` files are being monitored. Once they are changed, the ElasticSearch client will reconnect.
133+
- `trustStorePass` and `keyStorePass` could be changed in the runtime through [**Secrets Management File Of ElasticSearch Authentication**](#secrets-management-file-of-elasticsearch-authentication).
134+
- When `keyStorePath` is configured, `keyStorePass` must also be provided (can be empty string for no password).
135+
106136
### Daily Index Step
107137
Daily index step(`storage/elasticsearch/dayStep`, default 1) represents the index creation period. In this period, metrics for several days (dayStep value) are saved.
108138

@@ -121,17 +151,18 @@ NOTE: TTL deletion would be affected by these steps. You should set an extra day
121151

122152
### Secrets Management File Of ElasticSearch Authentication
123153
The value of `secretsManagementFile` should point to the secrets management file absolute path.
124-
The file includes the username, password, and JKS password of the ElasticSearch server in the properties format.
154+
The file includes the username, password, JKS password, and keystore password of the ElasticSearch server in the properties format.
125155
```properties
126156
user=xxx
127157
password=yyy
128158
trustStorePass=zzz
159+
keyStorePass=aaa
129160
```
130161

131-
The major difference between using `user, password, trustStorePass` configs in the `application.yaml` file is that the **Secrets Management File** is being watched by the OAP server.
162+
The major difference between using `user, password, trustStorePass, keyStorePass` configs in the `application.yaml` file is that the **Secrets Management File** is being watched by the OAP server.
132163
Once it is changed manually or through a 3rd party tool, such as [Vault](https://github.com/hashicorp/vault),
133-
the storage provider will use the new username, password, and JKS password to establish the connection and close the old one. If the information exists in the file,
134-
the `user/password` will be overridden.
164+
the storage provider will use the new username, password, JKS password, and keystore password to establish the connection and close the old one. If the information exists in the file,
165+
the `user/password/trustStorePass/keyStorePass` will be overridden.
135166

136167

137168
### Index Settings

oap-server-bom/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
<postgresql.version>42.4.4</postgresql.version>
6868
<jetcd.version>0.6.1</jetcd.version>
6969
<testcontainers.version>1.17.6</testcontainers.version>
70-
<armeria.version>1.32.0</armeria.version>
70+
<armeria.version>1.34.2</armeria.version>
7171
<awaitility.version>3.0.0</awaitility.version>
7272
<httpcore.version>4.4.16</httpcore.version>
7373
<httpasyncclient.version>4.1.5</httpasyncclient.version>

oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ElasticSearchClient.java

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@ public class ElasticSearchClient implements Client, HealthCheckable {
7676
@Setter
7777
private volatile String trustStorePass;
7878

79+
private final String keyStorePath;
80+
81+
@Setter
82+
private volatile String keyStorePass;
83+
7984
@Setter
8085
private volatile String user;
8186

@@ -107,6 +112,8 @@ public ElasticSearchClient(ModuleManager moduleManager,
107112
String protocol,
108113
String trustStorePath,
109114
String trustStorePass,
115+
String keyStorePath,
116+
String keyStorePass,
110117
String user,
111118
String password,
112119
Function<String, String> indexNameConverter,
@@ -119,6 +126,8 @@ public ElasticSearchClient(ModuleManager moduleManager,
119126
this.protocol = protocol;
120127
this.trustStorePath = trustStorePath;
121128
this.trustStorePass = trustStorePass;
129+
this.keyStorePath = keyStorePath;
130+
this.keyStorePass = keyStorePass;
122131
this.user = user;
123132
this.password = password;
124133
this.indexNameConverter = indexNameConverter;
@@ -152,9 +161,17 @@ public void connect() {
152161

153162
if (!Strings.isNullOrEmpty(trustStorePath)) {
154163
cb.trustStorePath(trustStorePath);
164+
// Always set trustStorePass if trustStorePath is set (even if empty string)
165+
if (trustStorePass != null) {
166+
cb.trustStorePass(trustStorePass);
167+
}
155168
}
156-
if (!Strings.isNullOrEmpty(trustStorePass)) {
157-
cb.trustStorePass(trustStorePass);
169+
if (!Strings.isNullOrEmpty(keyStorePath)) {
170+
cb.keyStorePath(keyStorePath);
171+
// Always set keyStorePass if keyStorePath is set (even if empty string)
172+
if (keyStorePass != null) {
173+
cb.keyStorePass(keyStorePass);
174+
}
158175
}
159176
if (!Strings.isNullOrEmpty(user)) {
160177
cb.username(user);

oap-server/server-library/library-client/src/test/java/org/apache/skywalking/library/elasticsearch/bulk/ElasticSearchIT.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ public void indexOperate(final ElasticsearchContainer server,
112112
final ElasticSearchClient client = new ElasticSearchClient(
113113
moduleManager,
114114
server.getHttpHostAddress(),
115-
"http", "", "", "test", "test",
115+
"http", "", "", "", "", "test", "test",
116116
indexNameConverter(namespace), 500, 6000,
117117
0, 15
118118
);
@@ -165,7 +165,7 @@ public void documentOperate(final ElasticsearchContainer server,
165165
final ElasticSearchClient client = new ElasticSearchClient(
166166
moduleManager,
167167
server.getHttpHostAddress(),
168-
"http", "", "", "test", "test",
168+
"http", "", "", "", "", "test", "test",
169169
indexNameConverter(namespace), 500, 6000,
170170
0, 15
171171
);
@@ -241,7 +241,7 @@ public void templateOperate(final ElasticsearchContainer server,
241241
final ElasticSearchClient client = new ElasticSearchClient(
242242
moduleManager,
243243
server.getHttpHostAddress(),
244-
"http", "", "", "test", "test",
244+
"http", "", "", "", "", "test", "test",
245245
indexNameConverter(namespace), 500, 6000,
246246
0, 15
247247
);
@@ -297,7 +297,7 @@ public void bulk(final ElasticsearchContainer server,
297297
final ElasticSearchClient client = new ElasticSearchClient(
298298
moduleManager,
299299
server.getHttpHostAddress(),
300-
"http", "", "", "test", "test",
300+
"http", "", "", "", "", "test", "test",
301301
indexNameConverter(namespace), 500, 6000,
302302
0, 15
303303
);
@@ -331,7 +331,7 @@ public void bulkPer_1KB(final ElasticsearchContainer server,
331331
final ElasticSearchClient client = new ElasticSearchClient(
332332
moduleManager,
333333
server.getHttpHostAddress(),
334-
"http", "", "", "test", "test",
334+
"http", "", "", "", "", "test", "test",
335335
indexNameConverter(namespace), 500, 6000,
336336
0, 15
337337
);
@@ -361,7 +361,7 @@ public void timeSeriesOperate(final ElasticsearchContainer server,
361361
final ElasticSearchClient client = new ElasticSearchClient(
362362
moduleManager,
363363
server.getHttpHostAddress(),
364-
"http", "", "", "test", "test",
364+
"http", "", "", "", "", "test", "test",
365365
indexNameConverter(namespace), 500, 6000,
366366
0, 15
367367
);

0 commit comments

Comments
 (0)