This is an automated email from the ASF dual-hosted git repository.
rdhabalia pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar.git
The following commit(s) were added to refs/heads/master by this push:
new d3643a0 [pulsar-broker] auto refresh new tls certs for jetty
webserver (#3645)
d3643a0 is described below
commit d3643a072c6dfd444974e0f8b864fc053cfdb4f8
Author: Rajan Dhabalia <[email protected]>
AuthorDate: Fri Feb 22 11:47:05 2019 -0800
[pulsar-broker] auto refresh new tls certs for jetty webserver (#3645)
* [pulsar-broker] auto refresh new tls certs for jetty webserver
* Fix: function worker
* revert expired test
---
conf/broker.conf | 3 +
conf/discovery.conf | 2 +
conf/functions_worker.yml | 2 +
conf/proxy.conf | 3 +
conf/websocket.conf | 2 +
.../apache/pulsar/broker/ServiceConfiguration.java | 4 +-
.../broker/service/PulsarChannelInitializer.java | 8 +-
.../org/apache/pulsar/broker/web/WebService.java | 6 +-
.../pulsar/broker/admin/AdminApiTlsAuthTest.java | 2 +-
.../common/util/DefaultSslContextBuilder.java | 51 +++++++++
.../pulsar/common/util/NettySslContextBuilder.java | 53 ++++++++++
.../apache/pulsar/common/util/SecurityUtility.java | 40 +++++++-
.../common/util/ServerSslContextRefresher.java | 87 ----------------
.../common/util/SslContextAutoRefreshBuilder.java | 114 +++++++++++++++++++++
.../service/ServiceChannelInitializer.java | 9 +-
.../discovery/service/server/ServerManager.java | 6 +-
.../discovery/service/server/ServiceConfig.java | 12 +--
.../pulsar/functions/worker/WorkerConfig.java | 5 +
.../pulsar/functions/worker/rest/WorkerServer.java | 6 +-
.../pulsar/proxy/server/ProxyConfiguration.java | 4 +-
.../proxy/server/ServiceChannelInitializer.java | 9 +-
.../org/apache/pulsar/proxy/server/WebServer.java | 6 +-
.../pulsar/websocket/service/ProxyServer.java | 6 +-
.../service/WebSocketProxyConfiguration.java | 10 ++
24 files changed, 324 insertions(+), 126 deletions(-)
diff --git a/conf/broker.conf b/conf/broker.conf
index befb9ba..262c44c 100644
--- a/conf/broker.conf
+++ b/conf/broker.conf
@@ -240,6 +240,9 @@ authenticateOriginalAuthData=false
# Deprecated - Use webServicePortTls and brokerServicePortTls instead
tlsEnabled=false
+# Tls cert refresh duration in seconds (set 0 to check on every new
connection)
+tlsCertRefreshCheckDurationSec=300
+
# Path for the TLS certificate file
tlsCertificateFilePath=
diff --git a/conf/discovery.conf b/conf/discovery.conf
index 907f546..57709dc 100644
--- a/conf/discovery.conf
+++ b/conf/discovery.conf
@@ -78,6 +78,8 @@ tlsKeyFilePath=
# Reject the Connection if the Client Certificate is not trusted.
tlsRequireTrustedClientCertOnConnect=false
+# Tls cert refresh duration in seconds (set 0 to check on every new
connection)
+tlsCertRefreshCheckDurationSec=300
### --- Deprecated config variables --- ###
diff --git a/conf/functions_worker.yml b/conf/functions_worker.yml
index ea1456d..0c1125d 100644
--- a/conf/functions_worker.yml
+++ b/conf/functions_worker.yml
@@ -145,6 +145,8 @@ tlsKeyFilePath:
tlsTrustCertsFilePath:
# Accept untrusted TLS certificate from client
tlsAllowInsecureConnection: false
+# Tls cert refresh duration in seconds (set 0 to check on every new
connection)
+tlsCertRefreshCheckDurationSec: 300
########################
# State Management
diff --git a/conf/proxy.conf b/conf/proxy.conf
index 0e4a117..4d1904f 100644
--- a/conf/proxy.conf
+++ b/conf/proxy.conf
@@ -100,6 +100,9 @@ brokerClientTrustCertsFilePath=
# Whether TLS is enabled when communicating with Pulsar brokers
tlsEnabledWithBroker=false
+# Tls cert refresh duration in seconds (set 0 to check on every new
connection)
+tlsCertRefreshCheckDurationSec=300
+
##### --- Rate Limiting --- #####
# Max concurrent inbound connections. The proxy will reject requests beyond
that.
diff --git a/conf/websocket.conf b/conf/websocket.conf
index a4dbe99..600b138 100644
--- a/conf/websocket.conf
+++ b/conf/websocket.conf
@@ -111,6 +111,8 @@ tlsTrustCertsFilePath=
# Reject the Connection if the Client Certificate is not trusted.
tlsRequireTrustedClientCertOnConnect=false
+# Tls cert refresh duration in seconds (set 0 to check on every new
connection)
+tlsCertRefreshCheckDurationSec=300
### --- Deprecated config variables --- ###
diff --git
a/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/ServiceConfiguration.java
b/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/ServiceConfiguration.java
index 1d697b2..cb36df4 100644
---
a/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/ServiceConfiguration.java
+++
b/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/ServiceConfiguration.java
@@ -449,9 +449,9 @@ public class ServiceConfiguration implements
PulsarConfiguration {
private boolean tlsEnabled = false;
@FieldContext(
category = CATEGORY_TLS,
- doc = "Time Interval in Mins between checks for Cert Refresh."
+ doc = "Tls cert refresh duration in seconds (set 0 to check on every
new connection)"
)
- private long certRefreshCheckDurationInMins = 0;
+ private long tlsCertRefreshCheckDurationSec = 300;
@FieldContext(
category = CATEGORY_TLS,
doc = "Path for the TLS certificate file"
diff --git
a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/PulsarChannelInitializer.java
b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/PulsarChannelInitializer.java
index d774bd4..ff24caa 100644
---
a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/PulsarChannelInitializer.java
+++
b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/PulsarChannelInitializer.java
@@ -22,7 +22,7 @@ import org.apache.pulsar.broker.PulsarService;
import org.apache.pulsar.broker.ServiceConfiguration;
import org.apache.pulsar.common.api.ByteBufPair;
import org.apache.pulsar.common.api.PulsarDecoder;
-import org.apache.pulsar.common.util.ServerSslContextRefresher;
+import org.apache.pulsar.common.util.NettySslContextBuilder;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel;
@@ -34,7 +34,7 @@ public class PulsarChannelInitializer extends
ChannelInitializer<SocketChannel>
private final PulsarService pulsar;
private final boolean enableTls;
- private final ServerSslContextRefresher sslCtxRefresher;
+ private final NettySslContextBuilder sslCtxRefresher;
/**
*
@@ -46,11 +46,11 @@ public class PulsarChannelInitializer extends
ChannelInitializer<SocketChannel>
this.enableTls = enableTLS;
if (this.enableTls) {
ServiceConfiguration serviceConfig = pulsar.getConfiguration();
- sslCtxRefresher = new
ServerSslContextRefresher(serviceConfig.isTlsAllowInsecureConnection(),
+ sslCtxRefresher = new
NettySslContextBuilder(serviceConfig.isTlsAllowInsecureConnection(),
serviceConfig.getTlsTrustCertsFilePath(),
serviceConfig.getTlsCertificateFilePath(),
serviceConfig.getTlsKeyFilePath(),
serviceConfig.getTlsCiphers(), serviceConfig.getTlsProtocols(),
serviceConfig.isTlsRequireTrustedClientCertOnConnect(),
- serviceConfig.getCertRefreshCheckDurationInMins());
+ serviceConfig.getTlsCertRefreshCheckDurationSec());
} else {
this.sslCtxRefresher = null;
}
diff --git
a/pulsar-broker/src/main/java/org/apache/pulsar/broker/web/WebService.java
b/pulsar-broker/src/main/java/org/apache/pulsar/broker/web/WebService.java
index 1610779..3ae55bc 100644
--- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/web/WebService.java
+++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/web/WebService.java
@@ -22,7 +22,6 @@ import com.google.common.collect.Lists;
import io.prometheus.client.jetty.JettyStatisticsCollector;
-import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
@@ -98,12 +97,13 @@ public class WebService implements AutoCloseable {
pulsar.getConfiguration().getTlsTrustCertsFilePath(),
pulsar.getConfiguration().getTlsCertificateFilePath(),
pulsar.getConfiguration().getTlsKeyFilePath(),
-
pulsar.getConfiguration().isTlsRequireTrustedClientCertOnConnect());
+
pulsar.getConfiguration().isTlsRequireTrustedClientCertOnConnect(), true,
+
pulsar.getConfiguration().getTlsCertRefreshCheckDurationSec());
ServerConnector tlsConnector = new
PulsarServerConnector(server, 1, 1, sslCtxFactory);
tlsConnector.setPort(tlsPort.get());
tlsConnector.setHost(pulsar.getBindAddress());
connectors.add(tlsConnector);
- } catch (GeneralSecurityException e) {
+ } catch (Exception e) {
throw new PulsarServerException(e);
}
}
diff --git
a/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/AdminApiTlsAuthTest.java
b/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/AdminApiTlsAuthTest.java
index f179780..0e731aa 100644
---
a/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/AdminApiTlsAuthTest.java
+++
b/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/AdminApiTlsAuthTest.java
@@ -369,4 +369,4 @@ public class AdminApiTlsAuthTest extends
MockedPulsarServiceBaseTest {
admin.namespaces().deleteNamespace("tenant1/ns1");
}
}
-}
+}
\ No newline at end of file
diff --git
a/pulsar-common/src/main/java/org/apache/pulsar/common/util/DefaultSslContextBuilder.java
b/pulsar-common/src/main/java/org/apache/pulsar/common/util/DefaultSslContextBuilder.java
new file mode 100644
index 0000000..4716254
--- /dev/null
+++
b/pulsar-common/src/main/java/org/apache/pulsar/common/util/DefaultSslContextBuilder.java
@@ -0,0 +1,51 @@
+/**
+ * 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.pulsar.common.util;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLException;
+
+public class DefaultSslContextBuilder extends
SslContextAutoRefreshBuilder<SSLContext> {
+ private volatile SSLContext sslContext;
+
+ public DefaultSslContextBuilder(boolean allowInsecure, String
trustCertsFilePath, String certificateFilePath,
+ String keyFilePath, boolean requireTrustedClientCertOnConnect,
long certRefreshInSec)
+ throws SSLException, FileNotFoundException,
GeneralSecurityException, IOException {
+ super(allowInsecure, trustCertsFilePath, certificateFilePath,
keyFilePath, null, null,
+ requireTrustedClientCertOnConnect, certRefreshInSec);
+ }
+
+ @Override
+ public synchronized SSLContext update() throws GeneralSecurityException {
+ this.sslContext =
SecurityUtility.createSslContext(tlsAllowInsecureConnection,
+ tlsTrustCertsFilePath.getFileName(),
tlsCertificateFilePath.getFileName(),
+ tlsKeyFilePath.getFileName());
+ return this.sslContext;
+ }
+
+ @Override
+ public SSLContext getSslContext() {
+ return this.sslContext;
+ }
+
+}
diff --git
a/pulsar-common/src/main/java/org/apache/pulsar/common/util/NettySslContextBuilder.java
b/pulsar-common/src/main/java/org/apache/pulsar/common/util/NettySslContextBuilder.java
new file mode 100644
index 0000000..e1ee4ab
--- /dev/null
+++
b/pulsar-common/src/main/java/org/apache/pulsar/common/util/NettySslContextBuilder.java
@@ -0,0 +1,53 @@
+/**
+ * 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.pulsar.common.util;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.util.Set;
+
+import javax.net.ssl.SSLException;
+
+import io.netty.handler.ssl.SslContext;
+
+public class NettySslContextBuilder extends
SslContextAutoRefreshBuilder<SslContext> {
+ private volatile SslContext sslNettyContext;
+
+ public NettySslContextBuilder(boolean allowInsecure, String
trustCertsFilePath, String certificateFilePath,
+ String keyFilePath, Set<String> ciphers, Set<String> protocols,
boolean requireTrustedClientCertOnConnect,
+ long delayInSeconds) throws SSLException, FileNotFoundException,
GeneralSecurityException, IOException {
+ super(allowInsecure, trustCertsFilePath, certificateFilePath,
keyFilePath, ciphers, protocols,
+ requireTrustedClientCertOnConnect, delayInSeconds);
+ }
+
+ @Override
+ public synchronized SslContext update() throws SSLException,
FileNotFoundException, GeneralSecurityException, IOException {
+ this.sslNettyContext =
SecurityUtility.createNettySslContextForServer(tlsAllowInsecureConnection,
+ tlsTrustCertsFilePath.getFileName(),
tlsCertificateFilePath.getFileName(), tlsKeyFilePath.getFileName(),
+ tlsCiphers, tlsProtocols,
tlsRequireTrustedClientCertOnConnect);
+ return this.sslNettyContext;
+ }
+
+ @Override
+ public SslContext getSslContext() {
+ return this.sslNettyContext;
+ }
+
+}
diff --git
a/pulsar-common/src/main/java/org/apache/pulsar/common/util/SecurityUtility.java
b/pulsar-common/src/main/java/org/apache/pulsar/common/util/SecurityUtility.java
index 8449b34..b454116 100644
---
a/pulsar-common/src/main/java/org/apache/pulsar/common/util/SecurityUtility.java
+++
b/pulsar-common/src/main/java/org/apache/pulsar/common/util/SecurityUtility.java
@@ -254,11 +254,18 @@ public class SecurityUtility {
public static SslContextFactory createSslContextFactory(boolean
tlsAllowInsecureConnection,
String tlsTrustCertsFilePath, String tlsCertificateFilePath,
String tlsKeyFilePath,
- boolean tlsRequireTrustedClientCertOnConnect) throws
GeneralSecurityException {
- SslContextFactory sslCtxFactory = new SslContextFactory();
- SSLContext sslCtx = createSslContext(tlsAllowInsecureConnection,
tlsTrustCertsFilePath, tlsCertificateFilePath,
- tlsKeyFilePath);
- sslCtxFactory.setSslContext(sslCtx);
+ boolean tlsRequireTrustedClientCertOnConnect, boolean autoRefresh,
long certRefreshInSec)
+ throws GeneralSecurityException, SSLException,
FileNotFoundException, IOException {
+ SslContextFactory sslCtxFactory = null;
+ if (autoRefresh) {
+ sslCtxFactory = new
SslContextFactoryWithAutoRefresh(tlsAllowInsecureConnection,
tlsTrustCertsFilePath,
+ tlsCertificateFilePath, tlsKeyFilePath,
tlsRequireTrustedClientCertOnConnect, 0);
+ } else {
+ sslCtxFactory = new SslContextFactory();
+ SSLContext sslCtx = createSslContext(tlsAllowInsecureConnection,
tlsTrustCertsFilePath,
+ tlsCertificateFilePath, tlsKeyFilePath);
+ sslCtxFactory.setSslContext(sslCtx);
+ }
if (tlsRequireTrustedClientCertOnConnect) {
sslCtxFactory.setNeedClientAuth(true);
} else {
@@ -267,4 +274,27 @@ public class SecurityUtility {
sslCtxFactory.setTrustAll(true);
return sslCtxFactory;
}
+
+ /**
+ * {@link SslContextFactory} that auto-refresh SSLContext
+ *
+ */
+ static class SslContextFactoryWithAutoRefresh extends SslContextFactory {
+
+ private final DefaultSslContextBuilder sslCtxRefresher;
+
+ public SslContextFactoryWithAutoRefresh(boolean
tlsAllowInsecureConnection, String tlsTrustCertsFilePath,
+ String tlsCertificateFilePath, String tlsKeyFilePath, boolean
tlsRequireTrustedClientCertOnConnect,
+ long certRefreshInSec)
+ throws SSLException, FileNotFoundException,
GeneralSecurityException, IOException {
+ super();
+ sslCtxRefresher = new
DefaultSslContextBuilder(tlsAllowInsecureConnection, tlsTrustCertsFilePath,
+ tlsCertificateFilePath, tlsKeyFilePath,
tlsRequireTrustedClientCertOnConnect, certRefreshInSec);
+ }
+
+ @Override
+ public SSLContext getSslContext() {
+ return sslCtxRefresher.get();
+ }
+ }
}
diff --git
a/pulsar-common/src/main/java/org/apache/pulsar/common/util/ServerSslContextRefresher.java
b/pulsar-common/src/main/java/org/apache/pulsar/common/util/ServerSslContextRefresher.java
deleted file mode 100644
index a638454..0000000
---
a/pulsar-common/src/main/java/org/apache/pulsar/common/util/ServerSslContextRefresher.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/**
- * 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.pulsar.common.util;
-
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.security.GeneralSecurityException;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-
-import javax.net.ssl.SSLException;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import io.netty.handler.ssl.SslContext;
-
-public class ServerSslContextRefresher {
- private final boolean tlsAllowInsecureConnection;
- private final FileModifiedTimeUpdater tlsTrustCertsFilePath,
tlsCertificateFilePath, tlsKeyFilePath;
- private final Set<String> tlsCiphers;
- private final Set<String> tlsProtocols;
- private final boolean tlsRequireTrustedClientCertOnConnect;
- private final long delayInMins;
- private long nextRefreshTimeInMins;
- private volatile SslContext sslContext;
-
- public ServerSslContextRefresher(boolean allowInsecure, String
trustCertsFilePath, String certificateFilePath,
- String keyFilePath, Set<String> ciphers, Set<String> protocols,
boolean requireTrustedClientCertOnConnect,
- long delayInMins) throws SSLException, FileNotFoundException,
GeneralSecurityException, IOException {
- this.tlsAllowInsecureConnection = allowInsecure;
- this.tlsTrustCertsFilePath = new
FileModifiedTimeUpdater(trustCertsFilePath);
- this.tlsCertificateFilePath = new
FileModifiedTimeUpdater(certificateFilePath);
- this.tlsKeyFilePath = new FileModifiedTimeUpdater(keyFilePath);
- this.tlsCiphers = ciphers;
- this.tlsProtocols = protocols;
- this.tlsRequireTrustedClientCertOnConnect =
requireTrustedClientCertOnConnect;
- this.delayInMins = delayInMins;
- this.nextRefreshTimeInMins =
TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()) + delayInMins;
-
- buildSSLContext();
-
- if (LOG.isDebugEnabled()) {
- LOG.debug("Certs will be refreshed every {} minutes", delayInMins);
- }
- }
-
- public void buildSSLContext() throws SSLException, FileNotFoundException,
GeneralSecurityException, IOException {
- this.sslContext =
SecurityUtility.createNettySslContextForServer(tlsAllowInsecureConnection,
- tlsTrustCertsFilePath.getFileName(),
tlsCertificateFilePath.getFileName(), tlsKeyFilePath.getFileName(),
- tlsCiphers, tlsProtocols,
tlsRequireTrustedClientCertOnConnect);
- }
-
- public synchronized SslContext get() {
- long nowInSeconds =
TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis());
- if (nextRefreshTimeInMins > nowInSeconds) {
- nextRefreshTimeInMins = nowInSeconds + delayInMins;
- if (tlsTrustCertsFilePath.checkAndRefresh() ||
tlsCertificateFilePath.checkAndRefresh()
- || tlsKeyFilePath.checkAndRefresh()) {
- try {
- buildSSLContext();
- } catch (GeneralSecurityException | IOException e) {
- LOG.error("Execption while trying to refresh ssl Context:
", e);
- }
- }
- }
- return this.sslContext;
- }
-
- private static final Logger LOG =
LoggerFactory.getLogger(ServerSslContextRefresher.class);
-}
diff --git
a/pulsar-common/src/main/java/org/apache/pulsar/common/util/SslContextAutoRefreshBuilder.java
b/pulsar-common/src/main/java/org/apache/pulsar/common/util/SslContextAutoRefreshBuilder.java
new file mode 100644
index 0000000..8d1b472
--- /dev/null
+++
b/pulsar-common/src/main/java/org/apache/pulsar/common/util/SslContextAutoRefreshBuilder.java
@@ -0,0 +1,114 @@
+/**
+ * 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.pulsar.common.util;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+import javax.net.ssl.SSLException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Auto refresher and builder of SSLContext.
+ *
+ * @param <T>
+ * type of SSLContext
+ */
+public abstract class SslContextAutoRefreshBuilder<T> {
+ protected final boolean tlsAllowInsecureConnection;
+ protected final FileModifiedTimeUpdater tlsTrustCertsFilePath,
tlsCertificateFilePath, tlsKeyFilePath;
+ protected final Set<String> tlsCiphers;
+ protected final Set<String> tlsProtocols;
+ protected final boolean tlsRequireTrustedClientCertOnConnect;
+ protected final long refreshTime;
+ protected long lastRefreshTime;
+
+ public SslContextAutoRefreshBuilder(boolean allowInsecure, String
trustCertsFilePath, String certificateFilePath,
+ String keyFilePath, Set<String> ciphers, Set<String> protocols,
boolean requireTrustedClientCertOnConnect,
+ long certRefreshInSec) throws SSLException, FileNotFoundException,
GeneralSecurityException, IOException {
+ this.tlsAllowInsecureConnection = allowInsecure;
+ this.tlsTrustCertsFilePath = new
FileModifiedTimeUpdater(trustCertsFilePath);
+ this.tlsCertificateFilePath = new
FileModifiedTimeUpdater(certificateFilePath);
+ this.tlsKeyFilePath = new FileModifiedTimeUpdater(keyFilePath);
+ this.tlsCiphers = ciphers;
+ this.tlsProtocols = protocols;
+ this.tlsRequireTrustedClientCertOnConnect =
requireTrustedClientCertOnConnect;
+ this.refreshTime = TimeUnit.SECONDS.toMillis(certRefreshInSec);
+ this.lastRefreshTime = -1;
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Certs will be refreshed every {} seconds",
certRefreshInSec);
+ }
+ }
+
+ /**
+ * udpates and returns cached SSLContext.
+ *
+ * @return
+ * @throws GeneralSecurityException
+ * @throws IOException
+ */
+ protected abstract T update() throws GeneralSecurityException, IOException;
+
+ /**
+ * Returns cached SSLContext.
+ *
+ * @return
+ */
+ protected abstract T getSslContext();
+
+ /**
+ * It updates SSLContext at every configured refresh time and returns
updated SSLContext
+ *
+ * @return
+ */
+ public T get() {
+ T ctx = getSslContext();
+ if (ctx == null) {
+ try {
+ update();
+ lastRefreshTime = System.currentTimeMillis();
+ return getSslContext();
+ } catch (GeneralSecurityException | IOException e) {
+ LOG.error("Execption while trying to refresh ssl Context {}",
e.getMessage(), e);
+ }
+ } else {
+ long now = System.currentTimeMillis();
+ if (refreshTime <= 0 || now > (lastRefreshTime + refreshTime)) {
+ if (tlsTrustCertsFilePath.checkAndRefresh() ||
tlsCertificateFilePath.checkAndRefresh()
+ || tlsKeyFilePath.checkAndRefresh()) {
+ try {
+ ctx = update();
+ lastRefreshTime = now;
+ } catch (GeneralSecurityException | IOException e) {
+ LOG.error("Execption while trying to refresh ssl
Context {} ", e.getMessage(), e);
+ }
+ }
+ }
+ }
+ return ctx;
+ }
+
+ private static final Logger LOG =
LoggerFactory.getLogger(SslContextAutoRefreshBuilder.class);
+}
diff --git
a/pulsar-discovery-service/src/main/java/org/apache/pulsar/discovery/service/ServiceChannelInitializer.java
b/pulsar-discovery-service/src/main/java/org/apache/pulsar/discovery/service/ServiceChannelInitializer.java
index 5c9da3a..212a740 100644
---
a/pulsar-discovery-service/src/main/java/org/apache/pulsar/discovery/service/ServiceChannelInitializer.java
+++
b/pulsar-discovery-service/src/main/java/org/apache/pulsar/discovery/service/ServiceChannelInitializer.java
@@ -19,7 +19,8 @@
package org.apache.pulsar.discovery.service;
import org.apache.pulsar.common.api.PulsarDecoder;
-import org.apache.pulsar.common.util.ServerSslContextRefresher;
+import org.apache.pulsar.common.util.NettySslContextBuilder;
+import org.apache.pulsar.common.util.SslContextAutoRefreshBuilder;
import org.apache.pulsar.discovery.service.server.ServiceConfig;
import io.netty.channel.ChannelInitializer;
@@ -36,7 +37,7 @@ public class ServiceChannelInitializer extends
ChannelInitializer<SocketChannel>
public static final String TLS_HANDLER = "tls";
private final DiscoveryService discoveryService;
private final boolean enableTls;
- private final ServerSslContextRefresher sslCtxRefresher;
+ private final NettySslContextBuilder sslCtxRefresher;
public ServiceChannelInitializer(DiscoveryService discoveryService,
ServiceConfig serviceConfig, boolean e)
throws Exception {
@@ -44,11 +45,11 @@ public class ServiceChannelInitializer extends
ChannelInitializer<SocketChannel>
this.discoveryService = discoveryService;
this.enableTls = e;
if (this.enableTls) {
- sslCtxRefresher = new
ServerSslContextRefresher(serviceConfig.isTlsAllowInsecureConnection(),
+ sslCtxRefresher = new
NettySslContextBuilder(serviceConfig.isTlsAllowInsecureConnection(),
serviceConfig.getTlsTrustCertsFilePath(),
serviceConfig.getTlsCertificateFilePath(),
serviceConfig.getTlsKeyFilePath(),
serviceConfig.getTlsCiphers(), serviceConfig.getTlsProtocols(),
serviceConfig.getTlsRequireTrustedClientCertOnConnect(),
- serviceConfig.getCertRefreshCheckDurationInMins());
+ serviceConfig.getTlsCertRefreshCheckDurationSec());
} else {
this.sslCtxRefresher = null;
}
diff --git
a/pulsar-discovery-service/src/main/java/org/apache/pulsar/discovery/service/server/ServerManager.java
b/pulsar-discovery-service/src/main/java/org/apache/pulsar/discovery/service/server/ServerManager.java
index 4cd3239..79e5c36 100644
---
a/pulsar-discovery-service/src/main/java/org/apache/pulsar/discovery/service/server/ServerManager.java
+++
b/pulsar-discovery-service/src/main/java/org/apache/pulsar/discovery/service/server/ServerManager.java
@@ -74,11 +74,13 @@ public class ServerManager {
config.getTlsTrustCertsFilePath(),
config.getTlsCertificateFilePath(),
config.getTlsKeyFilePath(),
- config.getTlsRequireTrustedClientCertOnConnect());
+ config.getTlsRequireTrustedClientCertOnConnect(),
+ true,
+ config.getTlsCertRefreshCheckDurationSec());
ServerConnector tlsConnector = new ServerConnector(server, 1,
1, sslCtxFactory);
tlsConnector.setPort(config.getWebServicePortTls().get());
connectors.add(tlsConnector);
- } catch (GeneralSecurityException e) {
+ } catch (Exception e) {
throw new RestException(e);
}
}
diff --git
a/pulsar-discovery-service/src/main/java/org/apache/pulsar/discovery/service/server/ServiceConfig.java
b/pulsar-discovery-service/src/main/java/org/apache/pulsar/discovery/service/server/ServiceConfig.java
index 5c5e161..5f89527 100644
---
a/pulsar-discovery-service/src/main/java/org/apache/pulsar/discovery/service/server/ServiceConfig.java
+++
b/pulsar-discovery-service/src/main/java/org/apache/pulsar/discovery/service/server/ServiceConfig.java
@@ -78,8 +78,8 @@ public class ServiceConfig implements PulsarConfiguration {
/***** --- TLS --- ****/
@Deprecated
private boolean tlsEnabled = false;
- // run certificate checks every X Mins
- private long certRefreshCheckDurationInMins = 0;
+ // Tls cert refresh duration in seconds (set 0 to check on every new
connection)
+ private long tlsCertRefreshCheckDurationSec = 300;
// Path for the TLS certificate file
private String tlsCertificateFilePath;
// Path for the TLS private key file
@@ -280,12 +280,12 @@ public class ServiceConfig implements PulsarConfiguration
{
this.tlsProtocols = tlsProtocols;
}
- public long getCertRefreshCheckDurationInMins() {
- return certRefreshCheckDurationInMins;
+ public long getTlsCertRefreshCheckDurationSec() {
+ return tlsCertRefreshCheckDurationSec;
}
- public void setCertRefreshCheckDurationInMins(long
certRefreshCheckDurationInMins) {
- this.certRefreshCheckDurationInMins = certRefreshCheckDurationInMins;
+ public void setTlsCertRefreshCheckDurationSec(long
tlsCertRefreshCheckDurationSec) {
+ this.tlsCertRefreshCheckDurationSec = tlsCertRefreshCheckDurationSec;
}
public Set<String> getTlsCiphers() {
diff --git
a/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/WorkerConfig.java
b/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/WorkerConfig.java
index 7404718..6efcbd2 100644
---
a/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/WorkerConfig.java
+++
b/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/WorkerConfig.java
@@ -254,6 +254,11 @@ public class WorkerConfig implements Serializable,
PulsarConfiguration {
)
private boolean tlsHostnameVerificationEnable = false;
@FieldContext(
+ category = CATEGORY_SECURITY,
+ doc = "Tls cert refresh duration in seconds (set 0 to check on
every new connection)"
+ )
+ private long tlsCertRefreshCheckDurationSec = 300;
+ @FieldContext(
category = CATEGORY_WORKER_SECURITY,
doc = "Enforce authentication"
)
diff --git
a/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/WorkerServer.java
b/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/WorkerServer.java
index 44cffbc..a6c4974 100644
---
a/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/WorkerServer.java
+++
b/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/WorkerServer.java
@@ -122,11 +122,13 @@ public class WorkerServer {
SslContextFactory sslCtxFactory =
SecurityUtility.createSslContextFactory(
this.workerConfig.isTlsAllowInsecureConnection(),
this.workerConfig.getTlsTrustCertsFilePath(),
this.workerConfig.getTlsCertificateFilePath(),
this.workerConfig.getTlsKeyFilePath(),
-
this.workerConfig.isTlsRequireTrustedClientCertOnConnect());
+
this.workerConfig.isTlsRequireTrustedClientCertOnConnect(),
+ true,
+ this.workerConfig.getTlsCertRefreshCheckDurationSec());
ServerConnector tlsConnector = new ServerConnector(server, 1,
1, sslCtxFactory);
tlsConnector.setPort(this.workerConfig.getWorkerPortTls());
connectors.add(tlsConnector);
- } catch (GeneralSecurityException e) {
+ } catch (Exception e) {
throw new RuntimeException(e);
}
}
diff --git
a/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/ProxyConfiguration.java
b/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/ProxyConfiguration.java
index 252d6e9..ae54d6e 100644
---
a/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/ProxyConfiguration.java
+++
b/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/ProxyConfiguration.java
@@ -226,9 +226,9 @@ public class ProxyConfiguration implements
PulsarConfiguration {
private boolean tlsEnabledInProxy = false;
@FieldContext(
category = CATEGORY_TLS,
- doc = "Time Interval in Mins between checks for Cert Refresh."
+ doc = "Tls cert refresh duration in seconds (set 0 to check on every
new connection)"
)
- private long certRefreshCheckDurationInMins = 0;
+ private long tlsCertRefreshCheckDurationSec = 300; // 5 mins
@FieldContext(
category = CATEGORY_TLS,
doc = "Path for the TLS certificate file"
diff --git
a/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/ServiceChannelInitializer.java
b/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/ServiceChannelInitializer.java
index bbccd26..b03afbf 100644
---
a/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/ServiceChannelInitializer.java
+++
b/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/ServiceChannelInitializer.java
@@ -24,7 +24,8 @@ import
org.apache.pulsar.client.api.AuthenticationDataProvider;
import org.apache.pulsar.client.api.AuthenticationFactory;
import org.apache.pulsar.common.api.PulsarDecoder;
import org.apache.pulsar.common.util.ClientSslContextRefresher;
-import org.apache.pulsar.common.util.ServerSslContextRefresher;
+import org.apache.pulsar.common.util.NettySslContextBuilder;
+import org.apache.pulsar.common.util.SslContextAutoRefreshBuilder;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel;
@@ -39,7 +40,7 @@ public class ServiceChannelInitializer extends
ChannelInitializer<SocketChannel>
public static final String TLS_HANDLER = "tls";
private final ProxyService proxyService;
- private final ServerSslContextRefresher serverSslCtxRefresher;
+ private final NettySslContextBuilder serverSslCtxRefresher;
private final ClientSslContextRefresher clientSslCtxRefresher;
private final boolean enableTls;
@@ -50,11 +51,11 @@ public class ServiceChannelInitializer extends
ChannelInitializer<SocketChannel>
this.enableTls = enableTls;
if (enableTls) {
- serverSslCtxRefresher = new
ServerSslContextRefresher(serviceConfig.isTlsAllowInsecureConnection(),
+ serverSslCtxRefresher = new
NettySslContextBuilder(serviceConfig.isTlsAllowInsecureConnection(),
serviceConfig.getTlsTrustCertsFilePath(),
serviceConfig.getTlsCertificateFilePath(),
serviceConfig.getTlsKeyFilePath(),
serviceConfig.getTlsCiphers(), serviceConfig.getTlsProtocols(),
serviceConfig.isTlsRequireTrustedClientCertOnConnect(),
- serviceConfig.getCertRefreshCheckDurationInMins());
+ serviceConfig.getTlsCertRefreshCheckDurationSec());
} else {
this.serverSslCtxRefresher = null;
}
diff --git
a/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/WebServer.java
b/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/WebServer.java
index 35378c2..2c4a4c2 100644
--- a/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/WebServer.java
+++ b/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/WebServer.java
@@ -102,11 +102,13 @@ public class WebServer {
config.getTlsTrustCertsFilePath(),
config.getTlsCertificateFilePath(),
config.getTlsKeyFilePath(),
- config.isTlsRequireTrustedClientCertOnConnect());
+ config.isTlsRequireTrustedClientCertOnConnect(),
+ true,
+ config.getTlsCertRefreshCheckDurationSec());
ServerConnector tlsConnector = new ServerConnector(server, 1,
1, sslCtxFactory);
tlsConnector.setPort(config.getWebServicePortTls().get());
connectors.add(tlsConnector);
- } catch (GeneralSecurityException e) {
+ } catch (Exception e) {
throw new RuntimeException(e);
}
}
diff --git
a/pulsar-websocket/src/main/java/org/apache/pulsar/websocket/service/ProxyServer.java
b/pulsar-websocket/src/main/java/org/apache/pulsar/websocket/service/ProxyServer.java
index e2cdf43..1df925e 100644
---
a/pulsar-websocket/src/main/java/org/apache/pulsar/websocket/service/ProxyServer.java
+++
b/pulsar-websocket/src/main/java/org/apache/pulsar/websocket/service/ProxyServer.java
@@ -77,11 +77,13 @@ public class ProxyServer {
config.getTlsTrustCertsFilePath(),
config.getTlsCertificateFilePath(),
config.getTlsKeyFilePath(),
- config.getTlsRequireTrustedClientCertOnConnect());
+ config.getTlsRequireTrustedClientCertOnConnect(),
+ true,
+ config.getTlsCertRefreshCheckDurationSec());
ServerConnector tlsConnector = new ServerConnector(server, -1,
-1, sslCtxFactory);
tlsConnector.setPort(config.getWebServicePortTls().get());
connectors.add(tlsConnector);
- } catch (GeneralSecurityException e) {
+ } catch (Exception e) {
throw new PulsarServerException(e);
}
}
diff --git
a/pulsar-websocket/src/main/java/org/apache/pulsar/websocket/service/WebSocketProxyConfiguration.java
b/pulsar-websocket/src/main/java/org/apache/pulsar/websocket/service/WebSocketProxyConfiguration.java
index 2317c95..72dd160 100644
---
a/pulsar-websocket/src/main/java/org/apache/pulsar/websocket/service/WebSocketProxyConfiguration.java
+++
b/pulsar-websocket/src/main/java/org/apache/pulsar/websocket/service/WebSocketProxyConfiguration.java
@@ -119,6 +119,8 @@ public class WebSocketProxyConfiguration implements
PulsarConfiguration {
// Specify whether Client certificates are required for TLS
// Reject the Connection if the Client Certificate is not trusted.
private boolean tlsRequireTrustedClientCertOnConnect = false;
+ // Tls cert refresh duration in seconds (set 0 to check on every new
connection)
+ private long tlsCertRefreshCheckDurationSec = 300;
private Properties properties = new Properties();
@@ -407,4 +409,12 @@ public class WebSocketProxyConfiguration implements
PulsarConfiguration {
public void setTlsRequireTrustedClientCertOnConnect(boolean
tlsRequireTrustedClientCertOnConnect) {
this.tlsRequireTrustedClientCertOnConnect =
tlsRequireTrustedClientCertOnConnect;
}
+
+ public long getTlsCertRefreshCheckDurationSec() {
+ return tlsCertRefreshCheckDurationSec;
+ }
+
+ public void setTlsCertRefreshCheckDurationSec(long
tlsCertRefreshCheckDurationSec) {
+ this.tlsCertRefreshCheckDurationSec = tlsCertRefreshCheckDurationSec;
+ }
}