Skip to content

Commit 9d23039

Browse files
authored
ZOOKEEPER-5024: Allow to set TLS version and ciphers for PrometheusMetricsProvider
Reviewers: meszibalu, anmolnar Author: PDavid Closes #2360 from PDavid/ZOOKEEPER-5024-prometheus-https-ciphers-protocols
1 parent 83221ec commit 9d23039

4 files changed

Lines changed: 337 additions & 56 deletions

File tree

zookeeper-docs/src/main/resources/markdown/zookeeperAdmin.md

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2286,8 +2286,17 @@ options are used to configure the [AdminServer](#sc_adminserver).
22862286
**New in 3.8.0:** Prometheus.io exporter will start a Jetty server and listen this address, default is "0.0.0.0"
22872287

22882288
* *metricsProvider.httpPort* :
2289-
Prometheus.io exporter will start a Jetty server and bind to this port, it defaults to 7000.
2290-
Prometheus end point will be http://hostname:httPort/metrics.
2289+
Prometheus.io exporter will start a Jetty server and bind to this port.
2290+
Prometheus end point will be `http://hostname:httpPort/metrics`.
2291+
If omitted no HTTP port will be opened.
2292+
* Note: Either HTTP or HTTPS port has to be specified or both.
2293+
2294+
* *metricsProvider.httpsPort* :
2295+
**New in 3.10.0:**
2296+
Prometheus.io exporter will start a Jetty server and bind to this port.
2297+
Prometheus end point will be `https://hostname:httpsPort/metrics`.
2298+
If omitted no HTTPS port will be opened.
2299+
* Note: Either HTTP or HTTPS port has to be specified or both.
22912300

22922301
* *metricsProvider.exportJvmInfo* :
22932302
If this property is set to **true** Prometheus.io will export useful metrics about the JVM.
@@ -2308,7 +2317,51 @@ options are used to configure the [AdminServer](#sc_adminserver).
23082317
**New in 3.7.1:**
23092318
The timeout in ms for Prometheus worker threads shutdown.
23102319
Default value is 1000ms.
2311-
2320+
2321+
* *metricsProvider.ssl.keyStore.location* and *metricsProvider.ssl.keyStore.password*:
2322+
**New in 3.10.0:**
2323+
Specifies the file path to a Java keystore containing the local
2324+
credentials to be used for PrometheusMetricsProvider TLS connections and the
2325+
password to unlock the file.
2326+
2327+
* *metricsProvider.ssl.keyStore.type*:
2328+
**New in 3.10.0:**
2329+
Specifies the file format of the PrometheusMetricsProvider keystore. Values: JKS, PEM, PKCS12 or null (detect by filename).
2330+
Default: null.
2331+
2332+
* *metricsProvider.ssl.trustStore.location* and *metricsProvider.ssl.trustStore.password*:
2333+
**New in 3.10.0:**
2334+
Specifies the file path to a Java truststore containing the remote
2335+
credentials to be used for PrometheusMetricsProvider TLS connections and the
2336+
password to unlock the file.
2337+
2338+
* *metricsProvider.ssl.trustStore.type*:
2339+
**New in 3.10.0:**
2340+
Specifies the file format of the PrometheusMetricsProvider truststore. Values: JKS, PEM, PKCS12 or null (detect by filename).
2341+
Default: null.
2342+
2343+
* *metricsProvider.ssl.need.client.auth*:
2344+
**New in 3.10.0:**
2345+
Specifies options to authenticate SSL connections from clients.
2346+
When set to true, PrometheusMetricsProvider will "require" client authentication.
2347+
Default: true
2348+
2349+
* *metricsProvider.ssl.want.client.auth*:
2350+
**New in 3.10.0:**
2351+
Specifies options to authenticate SSL connections from clients.
2352+
When set to true, PrometheusMetricsProvider will "request" client authentication.
2353+
Default: true
2354+
2355+
* *metricsProvider.ssl.ciphersuites* :
2356+
**New in 3.10.0:**
2357+
The enabled cipher suites to be used in TLS negotiation for PrometheusMetricsProvider.
2358+
Default value is Jetty default.
2359+
2360+
* *metricsProvider.ssl.enabledProtocols* :
2361+
**New in 3.10.0:**
2362+
The enabled protocols to be used in TLS negotiation for PrometheusMetricsProvider.
2363+
Default value is Jetty default.
2364+
23122365
<a name="Communication+using+the+Netty+framework"></a>
23132366

23142367
### Communication using the Netty framework

zookeeper-docs/src/main/resources/markdown/zookeeperMonitor.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,24 @@ ZooKeeper also supports SSL for Prometheus metrics, which provides secure data t
8181
metricsProvider.httpPort=7000
8282
metricsProvider.httpsPort=4443
8383
```
84+
85+
#### Configure TLS protocols and cipher suites for SSL/TLS negotiation in Prometheus Metrics:
86+
87+
It is also possible to restrict TLS versions and cipher suites for PrometheusMetricsProvider.
88+
Add the following configuration settings to the `zoo.cfg` config file:
89+
90+
```
91+
metricsProvider.ssl.enabledProtocols=TLSv1.2,TLSv1.3
92+
metricsProvider.ssl.ciphersuites=TLS_AES_128_GCM_SHA256,TLS_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
93+
```
94+
95+
To verify raise the log level of PrometheusMetricsProvider to DEBUG and check that the following entries can be seen in the logs:
96+
97+
```
98+
2026-03-11 15:46:36,997 [myid:] - INFO [main:o.a.z.m.p.PrometheusMetricsProvider@245] - Setting enabled protocols: 'TLSv1.2,TLSv1.3'
99+
2026-03-11 15:46:36,997 [myid:] - INFO [main:o.a.z.m.p.PrometheusMetricsProvider@251] - Setting enabled cipherSuites: 'TLS_AES_128_GCM_SHA256,TLS_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384'
100+
```
101+
84102
### Prometheus
85103
- Running a [Prometheus](https://prometheus.io/) monitoring service is the easiest way to ingest and record ZooKeeper's metrics.
86104

zookeeper-metrics-providers/zookeeper-prometheus-metrics/src/main/java/org/apache/zookeeper/metrics/prometheus/PrometheusMetricsProvider.java

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@
3737
import org.apache.zookeeper.metrics.Gauge;
3838
import org.apache.zookeeper.metrics.GaugeSet;
3939
import org.apache.zookeeper.metrics.MetricsContext;
40-
import org.apache.zookeeper.metrics.MetricsContext.DetailLevel;
4140
import org.apache.zookeeper.metrics.MetricsProvider;
4241
import org.apache.zookeeper.metrics.MetricsProviderLifeCycleException;
4342
import org.apache.zookeeper.metrics.Summary;
@@ -83,8 +82,14 @@ public class PrometheusMetricsProvider implements MetricsProvider {
8382
private String trustStoreType;
8483
private boolean needClientAuth = true; // Secure default
8584
private boolean wantClientAuth = true; // Secure default
85+
private String enabledProtocols;
86+
private String cipherSuites;
8687

8788
// Constants for configuration
89+
public static final String HTTP_HOST = "httpHost";
90+
public static final String HTTP_PORT = "httpPort";
91+
public static final String EXPORT_JVM_INFO = "exportJvmInfo";
92+
public static final String HTTPS_PORT = "httpsPort";
8893
public static final String NUM_WORKER_THREADS = "numWorkerThreads";
8994
public static final String SSL_KEYSTORE_LOCATION = "ssl.keyStore.location";
9095
public static final String SSL_KEYSTORE_PASSWORD = "ssl.keyStore.password";
@@ -94,6 +99,8 @@ public class PrometheusMetricsProvider implements MetricsProvider {
9499
public static final String SSL_TRUSTSTORE_TYPE = "ssl.trustStore.type";
95100
public static final String SSL_NEED_CLIENT_AUTH = "ssl.need.client.auth";
96101
public static final String SSL_WANT_CLIENT_AUTH = "ssl.want.client.auth";
102+
public static final String SSL_ENABLED_PROTOCOLS = "ssl.enabledProtocols";
103+
public static final String SSL_ENABLED_CIPHERS = "ssl.ciphersuites";
97104
public static final int SCAN_INTERVAL = 60 * 10; // 10 minutes
98105

99106
/**
@@ -114,10 +121,10 @@ protected void doTrace(HttpServletRequest req, HttpServletResponse resp) throws
114121
public void configure(Properties configuration) throws MetricsProviderLifeCycleException {
115122
LOG.info("Initializing Prometheus metrics with Jetty, configuration: {}", configuration);
116123

117-
this.host = configuration.getProperty("httpHost", "0.0.0.0");
118-
this.httpPort = Integer.parseInt(configuration.getProperty("httpPort", "-1"));
119-
this.httpsPort = Integer.parseInt(configuration.getProperty("httpsPort", "-1"));
120-
this.exportJvmInfo = Boolean.parseBoolean(configuration.getProperty("exportJvmInfo", "true"));
124+
this.host = configuration.getProperty(HTTP_HOST, "0.0.0.0");
125+
this.httpPort = Integer.parseInt(configuration.getProperty(HTTP_PORT, "-1"));
126+
this.httpsPort = Integer.parseInt(configuration.getProperty(HTTPS_PORT, "-1"));
127+
this.exportJvmInfo = Boolean.parseBoolean(configuration.getProperty(EXPORT_JVM_INFO, "true"));
121128
this.numWorkerThreads = Integer.parseInt(configuration.getProperty(NUM_WORKER_THREADS, "10"));
122129

123130
// If httpsPort is specified, parse all SSL properties
@@ -130,6 +137,8 @@ public void configure(Properties configuration) throws MetricsProviderLifeCycleE
130137
this.trustStoreType = configuration.getProperty(SSL_TRUSTSTORE_TYPE, "PKCS12");
131138
this.needClientAuth = Boolean.parseBoolean(configuration.getProperty(SSL_NEED_CLIENT_AUTH, "true"));
132139
this.wantClientAuth = Boolean.parseBoolean(configuration.getProperty(SSL_WANT_CLIENT_AUTH, "true"));
140+
this.enabledProtocols = configuration.getProperty(SSL_ENABLED_PROTOCOLS);
141+
this.cipherSuites = configuration.getProperty(SSL_ENABLED_CIPHERS);
133142
}
134143

135144
// Validate that at least one port is configured.
@@ -232,6 +241,18 @@ private SslContextFactory.Server createSslContextFactory() {
232241
sslContextFactory.setNeedClientAuth(this.needClientAuth);
233242
sslContextFactory.setWantClientAuth(this.wantClientAuth);
234243

244+
if (enabledProtocols != null) {
245+
LOG.debug("Setting enabled protocols: '{}'", enabledProtocols);
246+
String[] enabledProtocolsArray = enabledProtocols.split(",");
247+
sslContextFactory.setIncludeProtocols(enabledProtocolsArray);
248+
}
249+
250+
if (cipherSuites != null) {
251+
LOG.debug("Setting enabled cipherSuites: '{}'", cipherSuites);
252+
String[] cipherSuitesArray = cipherSuites.split(",");
253+
sslContextFactory.setIncludeCipherSuites(cipherSuitesArray);
254+
}
255+
235256
return sslContextFactory;
236257
}
237258

0 commit comments

Comments
 (0)