add more tls configs to enable/disable specific cipher suites and protocols (#4902)

* add more tls configs to enable/disable specific cipher suites and protocols

* fix doc, allow empty list
This commit is contained in:
Parag Jain 2017-10-09 15:53:12 -05:00 committed by Jonathan Wei
parent 797b54d283
commit 7cc18226cd
4 changed files with 111 additions and 18 deletions

View File

@ -30,8 +30,17 @@ values for the below mentioned configs among others provided by Java implementat
|`druid.server.https.keyStoreType`|The type of the key store.|none|yes| |`druid.server.https.keyStoreType`|The type of the key store.|none|yes|
|`druid.server.https.certAlias`|Alias of TLS/SSL certificate for the connector.|none|yes| |`druid.server.https.certAlias`|Alias of TLS/SSL certificate for the connector.|none|yes|
|`druid.server.https.keyStorePassword`|The [Password Provider](../operations/password-provider.html) or String password for the Key Store.|none|yes| |`druid.server.https.keyStorePassword`|The [Password Provider](../operations/password-provider.html) or String password for the Key Store.|none|yes|
Following table contains non-mandatory advanced configuration options, use caution.
|Property|Description|Default|Required|
|--------|-----------|-------|--------|
|`druid.server.https.keyManagerFactoryAlgorithm`|Algorithm to use for creating KeyManager, more details [here](https://docs.oracle.com/javase/7/docs/technotes/guides/security/jsse/JSSERefGuide.html#KeyManager).|`javax.net.ssl.KeyManagerFactory.getDefaultAlgorithm()`|no| |`druid.server.https.keyManagerFactoryAlgorithm`|Algorithm to use for creating KeyManager, more details [here](https://docs.oracle.com/javase/7/docs/technotes/guides/security/jsse/JSSERefGuide.html#KeyManager).|`javax.net.ssl.KeyManagerFactory.getDefaultAlgorithm()`|no|
|`druid.server.https.keyManagerPassword`|The [Password Provider](../operations/password-provider.html) or String password for the Key Manager.|none|no| |`druid.server.https.keyManagerPassword`|The [Password Provider](../operations/password-provider.html) or String password for the Key Manager.|none|no|
|`druid.server.https.includeCipherSuites`|List of cipher suite names to include. You can either use the exact cipher suite name or a regular expression.|Jetty's default include cipher list|no|
|`druid.server.https.excludeCipherSuites`|List of cipher suite names to exclude. You can either use the exact cipher suite name or a regular expression.|Jetty's default exclude cipher list|no|
|`druid.server.https.includeProtocols`|List of exact protocols names to include.|Jetty's default include protocol list|no|
|`druid.server.https.excludeProtocols`|List of exact protocols names to exclude.|Jetty's default exclude protocol list|no|
# Druid's internal communication over TLS # Druid's internal communication over TLS

View File

@ -21,6 +21,8 @@ package io.druid.server.initialization;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import io.druid.metadata.PasswordProvider; import io.druid.metadata.PasswordProvider;
import java.util.List;
public class TLSServerConfig public class TLSServerConfig
{ {
@JsonProperty @JsonProperty
@ -32,15 +34,27 @@ public class TLSServerConfig
@JsonProperty @JsonProperty
private String certAlias; private String certAlias;
@JsonProperty
private String keyManagerFactoryAlgorithm;
@JsonProperty("keyStorePassword") @JsonProperty("keyStorePassword")
private PasswordProvider keyStorePasswordProvider; private PasswordProvider keyStorePasswordProvider;
@JsonProperty("keyManagerPassword") @JsonProperty("keyManagerPassword")
private PasswordProvider keyManagerPasswordProvider; private PasswordProvider keyManagerPasswordProvider;
@JsonProperty
private String keyManagerFactoryAlgorithm;
@JsonProperty
private List<String> includeCipherSuites;
@JsonProperty
private List<String> excludeCipherSuites;
@JsonProperty
private List<String> includeProtocols;
@JsonProperty
private List<String> excludeProtocols;
public String getKeyStorePath() public String getKeyStorePath()
{ {
return keyStorePath; return keyStorePath;
@ -71,6 +85,26 @@ public class TLSServerConfig
return keyManagerFactoryAlgorithm; return keyManagerFactoryAlgorithm;
} }
public List<String> getIncludeCipherSuites()
{
return includeCipherSuites;
}
public List<String> getExcludeCipherSuites()
{
return excludeCipherSuites;
}
public List<String> getIncludeProtocols()
{
return includeProtocols;
}
public List<String> getExcludeProtocols()
{
return excludeProtocols;
}
@Override @Override
public String toString() public String toString()
{ {
@ -79,6 +113,10 @@ public class TLSServerConfig
", keyStoreType='" + keyStoreType + '\'' + ", keyStoreType='" + keyStoreType + '\'' +
", certAlias='" + certAlias + '\'' + ", certAlias='" + certAlias + '\'' +
", keyManagerFactoryAlgorithm='" + keyManagerFactoryAlgorithm + '\'' + ", keyManagerFactoryAlgorithm='" + keyManagerFactoryAlgorithm + '\'' +
", includeCipherSuites=" + includeCipherSuites +
", excludeCipherSuites=" + excludeCipherSuites +
", includeProtocols=" + includeProtocols +
", excludeProtocols=" + excludeProtocols +
'}'; '}';
} }
} }

View File

@ -120,13 +120,13 @@ public class ChatHandlerServerModule implements Module
@RemoteChatHandler TLSServerConfig TLSServerConfig @RemoteChatHandler TLSServerConfig TLSServerConfig
) )
{ {
final Server server = JettyServerModule.makeJettyServer( return JettyServerModule.makeAndInitializeServer(
injector,
lifecycle,
node, node,
config, config,
TLSServerConfig, TLSServerConfig,
injector.getExistingBinding(Key.get(SslContextFactory.class)) injector.getExistingBinding(Key.get(SslContextFactory.class))
); );
JettyServerModule.initializeServer(injector, lifecycle, server);
return server;
} }
} }

View File

@ -22,6 +22,7 @@ package io.druid.server.initialization.jetty;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider; import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
import com.fasterxml.jackson.jaxrs.smile.JacksonSmileProvider; import com.fasterxml.jackson.jaxrs.smile.JacksonSmileProvider;
import com.google.common.base.Preconditions;
import com.google.common.primitives.Ints; import com.google.common.primitives.Ints;
import com.google.inject.Binder; import com.google.inject.Binder;
import com.google.inject.Binding; import com.google.inject.Binding;
@ -48,6 +49,7 @@ import io.druid.guice.annotations.JSR311Resource;
import io.druid.guice.annotations.Json; import io.druid.guice.annotations.Json;
import io.druid.guice.annotations.Self; import io.druid.guice.annotations.Self;
import io.druid.guice.annotations.Smile; import io.druid.guice.annotations.Smile;
import io.druid.java.util.common.ISE;
import io.druid.java.util.common.RE; import io.druid.java.util.common.RE;
import io.druid.java.util.common.lifecycle.Lifecycle; import io.druid.java.util.common.lifecycle.Lifecycle;
import io.druid.java.util.common.logger.Logger; import io.druid.java.util.common.logger.Logger;
@ -72,8 +74,10 @@ import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler; import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler;
import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLEngine;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -147,14 +151,14 @@ public class JettyServerModule extends JerseyServletModule
final TLSServerConfig TLSServerConfig final TLSServerConfig TLSServerConfig
) )
{ {
final Server server = makeJettyServer( return makeAndInitializeServer(
injector,
lifecycle,
node, node,
config, config,
TLSServerConfig, TLSServerConfig,
injector.getExistingBinding(Key.get(SslContextFactory.class)) injector.getExistingBinding(Key.get(SslContextFactory.class))
); );
initializeServer(injector, lifecycle, server);
return server;
} }
@Provides @Provides
@ -175,7 +179,9 @@ public class JettyServerModule extends JerseyServletModule
return provider; return provider;
} }
static Server makeJettyServer( static Server makeAndInitializeServer(
Injector injector,
Lifecycle lifecycle,
DruidNode node, DruidNode node,
ServerConfig config, ServerConfig config,
TLSServerConfig tlsServerConfig, TLSServerConfig tlsServerConfig,
@ -216,9 +222,10 @@ public class JettyServerModule extends JerseyServletModule
connector.setPort(node.getPlaintextPort()); connector.setPort(node.getPlaintextPort());
serverConnectors.add(connector); serverConnectors.add(connector);
} }
final SslContextFactory sslContextFactory;
if (node.isEnableTlsPort()) { if (node.isEnableTlsPort()) {
log.info("Creating https connector with port [%d]", node.getTlsPort()); log.info("Creating https connector with port [%d]", node.getTlsPort());
final SslContextFactory sslContextFactory;
if (sslContextFactoryBinding == null) { if (sslContextFactoryBinding == null) {
// Never trust all certificates by default // Never trust all certificates by default
sslContextFactory = new SslContextFactory(false); sslContextFactory = new SslContextFactory(false);
@ -229,8 +236,26 @@ public class JettyServerModule extends JerseyServletModule
sslContextFactory.setKeyManagerFactoryAlgorithm(tlsServerConfig.getKeyManagerFactoryAlgorithm() == null sslContextFactory.setKeyManagerFactoryAlgorithm(tlsServerConfig.getKeyManagerFactoryAlgorithm() == null
? KeyManagerFactory.getDefaultAlgorithm() ? KeyManagerFactory.getDefaultAlgorithm()
: tlsServerConfig.getKeyManagerFactoryAlgorithm()); : tlsServerConfig.getKeyManagerFactoryAlgorithm());
sslContextFactory.setKeyManagerPassword(tlsServerConfig.getKeyManagerPasswordProvider() == null ? null sslContextFactory.setKeyManagerPassword(tlsServerConfig.getKeyManagerPasswordProvider() == null ?
: tlsServerConfig.getKeyManagerPasswordProvider().getPassword()); null : tlsServerConfig.getKeyManagerPasswordProvider().getPassword());
if (tlsServerConfig.getIncludeCipherSuites() != null) {
sslContextFactory.setIncludeCipherSuites(
tlsServerConfig.getIncludeCipherSuites()
.toArray(new String[tlsServerConfig.getIncludeCipherSuites().size()]));
}
if (tlsServerConfig.getExcludeCipherSuites() != null) {
sslContextFactory.setExcludeCipherSuites(
tlsServerConfig.getExcludeCipherSuites()
.toArray(new String[tlsServerConfig.getExcludeCipherSuites().size()]));
}
if (tlsServerConfig.getIncludeProtocols() != null) {
sslContextFactory.setIncludeProtocols(
tlsServerConfig.getIncludeProtocols().toArray(new String[tlsServerConfig.getIncludeProtocols().size()]));
}
if (tlsServerConfig.getExcludeProtocols() != null) {
sslContextFactory.setExcludeProtocols(
tlsServerConfig.getExcludeProtocols().toArray(new String[tlsServerConfig.getExcludeProtocols().size()]));
}
} else { } else {
sslContextFactory = sslContextFactoryBinding.getProvider().get(); sslContextFactory = sslContextFactoryBinding.getProvider().get();
} }
@ -246,6 +271,8 @@ public class JettyServerModule extends JerseyServletModule
); );
connector.setPort(node.getTlsPort()); connector.setPort(node.getTlsPort());
serverConnectors.add(connector); serverConnectors.add(connector);
} else {
sslContextFactory = null;
} }
final ServerConnector[] connectors = new ServerConnector[serverConnectors.size()]; final ServerConnector[] connectors = new ServerConnector[serverConnectors.size()];
@ -266,11 +293,7 @@ public class JettyServerModule extends JerseyServletModule
server.setConnectors(connectors); server.setConnectors(connectors);
return server; // initialize server
}
static void initializeServer(Injector injector, Lifecycle lifecycle, final Server server)
{
JettyServerInitializer initializer = injector.getInstance(JettyServerInitializer.class); JettyServerInitializer initializer = injector.getInstance(JettyServerInitializer.class);
try { try {
initializer.initialize(server, injector); initializer.initialize(server, injector);
@ -286,6 +309,27 @@ public class JettyServerModule extends JerseyServletModule
public void start() throws Exception public void start() throws Exception
{ {
server.start(); server.start();
if (node.isEnableTlsPort()) {
// Perform validation
Preconditions.checkNotNull(sslContextFactory);
final SSLEngine sslEngine = sslContextFactory.newSSLEngine();
if (sslEngine.getEnabledCipherSuites() == null || sslEngine.getEnabledCipherSuites().length == 0) {
throw new ISE(
"No supported cipher suites found, supported suites [%s], configured suites include list: [%s] exclude list: [%s]",
Arrays.toString(sslEngine.getSupportedCipherSuites()),
tlsServerConfig.getIncludeCipherSuites(),
tlsServerConfig.getExcludeCipherSuites()
);
}
if (sslEngine.getEnabledProtocols() == null || sslEngine.getEnabledProtocols().length == 0) {
throw new ISE(
"No supported protocols found, supported protocols [%s], configured protocols include list: [%s] exclude list: [%s]",
Arrays.toString(sslEngine.getSupportedProtocols()),
tlsServerConfig.getIncludeProtocols(),
tlsServerConfig.getExcludeProtocols()
);
}
}
} }
@Override @Override
@ -300,6 +344,8 @@ public class JettyServerModule extends JerseyServletModule
} }
} }
); );
return server;
} }
private static int getMaxJettyAcceptorsSelectorsNum(DruidNode druidNode) private static int getMaxJettyAcceptorsSelectorsNum(DruidNode druidNode)