pulsar-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From rdhaba...@apache.org
Subject [pulsar] branch master updated: [pulsar-broker] auto refresh new tls certs for jetty webserver (#3645)
Date Fri, 22 Feb 2019 19:47:10 GMT
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 <rdhabalia@apache.org>
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;
+    }
 }


Mime
View raw message