diff options
Diffstat (limited to 'jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl')
5 files changed, 184 insertions, 0 deletions
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/DefaultSslKeyStoreConfigurator.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/DefaultSslKeyStoreConfigurator.java new file mode 100644 index 00000000000..fb0a5869bb3 --- /dev/null +++ b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/DefaultSslKeyStoreConfigurator.java @@ -0,0 +1,95 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.jdisc.http.ssl; + +import com.google.inject.Inject; +import com.yahoo.jdisc.http.ConnectorConfig; +import com.yahoo.jdisc.http.SecretStore; +import com.yahoo.jdisc.http.ssl.pem.PemSslKeyStore; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.KeyStore; +import java.util.logging.Logger; + +/** + * @author bjorncs + */ +public class DefaultSslKeyStoreConfigurator implements SslKeyStoreConfigurator { + + private static final Logger log = Logger.getLogger(DefaultSslKeyStoreConfigurator.class.getName()); + + private final SecretStore secretStore; + private final ConnectorConfig.Ssl config; + + @Inject + public DefaultSslKeyStoreConfigurator(ConnectorConfig config, SecretStore secretStore) { + validateConfig(config.ssl()); + this.secretStore = secretStore; + this.config = config.ssl(); + } + + private static void validateConfig(ConnectorConfig.Ssl config) { + if (!config.enabled()) return; + switch (config.keyStoreType()) { + case JKS: + validateJksConfig(config); + break; + case PEM: + validatePemConfig(config); + break; + } + } + + @Override + public void configure(SslKeyStoreContext context) { + if (!config.enabled()) return; + switch (config.keyStoreType()) { + case JKS: + context.updateKeyStore(config.keyStorePath(), "JKS", secretStore.getSecret(config.keyDbKey())); + break; + case PEM: + context.updateKeyStore(createPemKeyStore(config.pemKeyStore())); + break; + } + } + + private static void validateJksConfig(ConnectorConfig.Ssl ssl) { + if (!ssl.pemKeyStore().keyPath().isEmpty() || ! ssl.pemKeyStore().certificatePath().isEmpty()) { + throw new IllegalArgumentException("pemKeyStore attributes can not be set when keyStoreType is JKS."); + } + if (ssl.keyDbKey().isEmpty()) { + throw new IllegalArgumentException("Missing password for JKS keystore"); + } + } + + private static void validatePemConfig(ConnectorConfig.Ssl ssl) { + if (! ssl.keyStorePath().isEmpty()) { + throw new IllegalArgumentException("keyStorePath can not be set when keyStoreType is PEM"); + } + if (!ssl.keyDbKey().isEmpty()) { + // TODO Make an error once there are separate passwords for truststore and keystore + log.warning("Encrypted PEM key stores are not supported. Password is only applied to truststore"); + } + if (ssl.pemKeyStore().certificatePath().isEmpty()) { + throw new IllegalArgumentException("Missing certificate path."); + } + if (ssl.pemKeyStore().keyPath().isEmpty()) { + throw new IllegalArgumentException("Missing key path."); + } + } + + private static KeyStore createPemKeyStore(ConnectorConfig.Ssl.PemKeyStore pemKeyStore) { + try { + Path certificatePath = Paths.get(pemKeyStore.certificatePath()); + Path keyPath = Paths.get(pemKeyStore.keyPath()); + return new PemSslKeyStore(certificatePath, keyPath).loadJavaKeyStore(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } catch (Exception e) { + throw new RuntimeException("Failed setting up key store for " + pemKeyStore.keyPath() + ", " + pemKeyStore.certificatePath(), e); + } + } + +} diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/DefaultSslKeyStoreContext.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/DefaultSslKeyStoreContext.java new file mode 100644 index 00000000000..8a95893eaeb --- /dev/null +++ b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/DefaultSslKeyStoreContext.java @@ -0,0 +1,51 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.jdisc.http.ssl; + +import org.eclipse.jetty.util.ssl.SslContextFactory; + +import java.security.KeyStore; +import java.util.function.Consumer; + +/** + * @author bjorncs + */ +public class DefaultSslKeyStoreContext implements SslKeyStoreContext { + + private final SslContextFactory sslContextFactory; + + public DefaultSslKeyStoreContext(SslContextFactory sslContextFactory) { + this.sslContextFactory = sslContextFactory; + } + + @Override + public void updateKeyStore(KeyStore keyStore) { + updateKeyStore(keyStore, null); + } + + @Override + public void updateKeyStore(KeyStore keyStore, String password) { + updateKeyStore(sslContextFactory -> { + sslContextFactory.setKeyStore(keyStore); + if (password != null) { + sslContextFactory.setKeyStorePassword(null); + } + }); + } + + @Override + public void updateKeyStore(String keyStorePath, String keyStoreType, String keyStorePassword) { + updateKeyStore(sslContextFactory -> { + sslContextFactory.setKeyStorePath(keyStorePath); + sslContextFactory.setKeyStoreType(keyStoreType); + sslContextFactory.setKeyStorePassword(keyStorePassword); + }); + } + + private void updateKeyStore(Consumer<SslContextFactory> reloader) { + try { + sslContextFactory.reload(reloader); + } catch (Exception e) { + throw new RuntimeException("Could not update keystore: " + e.getMessage(), e); + } + } +} diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/SslKeyStoreConfigurator.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/SslKeyStoreConfigurator.java new file mode 100644 index 00000000000..619f4a636ed --- /dev/null +++ b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/SslKeyStoreConfigurator.java @@ -0,0 +1,14 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.jdisc.http.ssl; + +/** + * An interface for an component that can configure an {@link SslKeyStoreContext}. The implementor can assume that + * the {@link SslKeyStoreContext} instance is thread-safe and be updated at any time + * during and after the call to{@link #configure(SslKeyStoreContext)}. + * Modifying the {@link SslKeyStoreContext} instance will trigger a hot reload of the keystore in JDisc. + * + * @author bjorncs + */ +public interface SslKeyStoreConfigurator { + void configure(SslKeyStoreContext context); +} diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/SslKeyStoreContext.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/SslKeyStoreContext.java new file mode 100644 index 00000000000..2a25f6d78b5 --- /dev/null +++ b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/SslKeyStoreContext.java @@ -0,0 +1,16 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.jdisc.http.ssl; + +import java.security.KeyStore; + +/** + * An interface to update the keystore in JDisc. Any update will trigger a hot reload and new connections will + * immediately see the new certificate chain. + * + * @author bjorncs + */ +public interface SslKeyStoreContext { + void updateKeyStore(KeyStore keyStore); + void updateKeyStore(KeyStore keyStore, String password); + void updateKeyStore(String keyStorePath, String keyStoreType, String keyStorePassword); +} diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/package-info.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/package-info.java new file mode 100644 index 00000000000..5f817d4cfc2 --- /dev/null +++ b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/package-info.java @@ -0,0 +1,8 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +/** + * @author bjorncs + */ +@ExportPackage +package com.yahoo.jdisc.http.ssl; + +import com.yahoo.osgi.annotation.ExportPackage; |