diff --git a/src/main/java/org/opensearch/security/ssl/DefaultSecurityKeyStore.java b/src/main/java/org/opensearch/security/ssl/DefaultSecurityKeyStore.java index 61dac199ae..41d103ac87 100644 --- a/src/main/java/org/opensearch/security/ssl/DefaultSecurityKeyStore.java +++ b/src/main/java/org/opensearch/security/ssl/DefaultSecurityKeyStore.java @@ -69,6 +69,7 @@ import org.opensearch.SpecialPermission; import org.opensearch.common.settings.Settings; import org.opensearch.env.Environment; +import org.opensearch.security.ssl.config.CertType; import org.opensearch.security.ssl.util.CertFileProps; import org.opensearch.security.ssl.util.CertFromFile; import org.opensearch.security.ssl.util.CertFromKeystore; @@ -874,16 +875,16 @@ private String[] getEnabledSSLProtocols(final SslProvider provider, boolean http private void initEnabledSSLCiphers() { final ImmutableSet<String> allowedSecureHttpSSLCiphers = ImmutableSet.copyOf( - SSLConfigConstants.getSecureSSLCiphers(settings, true) + SSLConfigConstants.getSecureSSLCiphers(settings, CertType.HTTP) ); final ImmutableSet<String> allowedSecureTransportSSLCiphers = ImmutableSet.copyOf( - SSLConfigConstants.getSecureSSLCiphers(settings, false) + SSLConfigConstants.getSecureSSLCiphers(settings, CertType.TRANSPORT) ); final ImmutableSet<String> allowedSecureHttpSSLProtocols = ImmutableSet.copyOf( - (SSLConfigConstants.getSecureSSLProtocols(settings, true)) + (SSLConfigConstants.getSecureSSLProtocols(settings, CertType.HTTP)) ); final ImmutableSet<String> allowedSecureTransportSSLProtocols = ImmutableSet.copyOf( - SSLConfigConstants.getSecureSSLProtocols(settings, false) + SSLConfigConstants.getSecureSSLProtocols(settings, CertType.TRANSPORT) ); if (OpenSearchSecuritySSLPlugin.OPENSSL_SUPPORTED && OpenSsl.isAvailable()) { diff --git a/src/main/java/org/opensearch/security/ssl/ExternalSecurityKeyStore.java b/src/main/java/org/opensearch/security/ssl/ExternalSecurityKeyStore.java index 25d0599c58..1adb326e8f 100644 --- a/src/main/java/org/opensearch/security/ssl/ExternalSecurityKeyStore.java +++ b/src/main/java/org/opensearch/security/ssl/ExternalSecurityKeyStore.java @@ -31,6 +31,7 @@ import org.opensearch.OpenSearchException; import org.opensearch.common.settings.Settings; +import org.opensearch.security.ssl.config.CertType; import org.opensearch.security.ssl.util.SSLConfigConstants; public class ExternalSecurityKeyStore implements SecurityKeyStore { @@ -72,17 +73,17 @@ public SSLEngine createClientTransportSSLEngine(final String peerHost, final int final SSLParameters sslParams = new SSLParameters(); sslParams.setEndpointIdentificationAlgorithm("HTTPS"); engine.setSSLParameters(sslParams); - engine.setEnabledProtocols(evalSecure(engine.getEnabledProtocols(), SSLConfigConstants.getSecureSSLProtocols(settings, false))); + engine.setEnabledProtocols(evalSecure(engine.getEnabledProtocols(), SSLConfigConstants.getSecureSSLProtocols(settings, CertType.TRANSPORT))); engine.setEnabledCipherSuites( - evalSecure(engine.getEnabledCipherSuites(), SSLConfigConstants.getSecureSSLCiphers(settings, false).toArray(new String[0])) + evalSecure(engine.getEnabledCipherSuites(), SSLConfigConstants.getSecureSSLCiphers(settings, CertType.TRANSPORT).toArray(new String[0])) ); engine.setUseClientMode(true); return engine; } else { final SSLEngine engine = externalSslContext.createSSLEngine(); - engine.setEnabledProtocols(evalSecure(engine.getEnabledProtocols(), SSLConfigConstants.getSecureSSLProtocols(settings, false))); + engine.setEnabledProtocols(evalSecure(engine.getEnabledProtocols(), SSLConfigConstants.getSecureSSLProtocols(settings, CertType.TRANSPORT))); engine.setEnabledCipherSuites( - evalSecure(engine.getEnabledCipherSuites(), SSLConfigConstants.getSecureSSLCiphers(settings, false).toArray(new String[0])) + evalSecure(engine.getEnabledCipherSuites(), SSLConfigConstants.getSecureSSLCiphers(settings, CertType.TRANSPORT).toArray(new String[0])) ); engine.setUseClientMode(true); return engine; diff --git a/src/main/java/org/opensearch/security/ssl/OpenSearchSecureSettingsFactory.java b/src/main/java/org/opensearch/security/ssl/OpenSearchSecureSettingsFactory.java index 3b511ba002..f860b53a28 100644 --- a/src/main/java/org/opensearch/security/ssl/OpenSearchSecureSettingsFactory.java +++ b/src/main/java/org/opensearch/security/ssl/OpenSearchSecureSettingsFactory.java @@ -14,16 +14,23 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.Optional; +import java.util.function.Supplier; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLException; import javax.net.ssl.TrustManagerFactory; +import org.opensearch.common.network.NetworkService; +import org.opensearch.common.settings.ClusterSettings; import org.opensearch.common.settings.Settings; +import org.opensearch.core.indices.breaker.CircuitBreakerService; import org.opensearch.http.HttpServerTransport; import org.opensearch.http.netty4.ssl.SecureNetty4HttpServerTransport; +import org.opensearch.plugins.NetworkPlugin; import org.opensearch.plugins.SecureHttpTransportSettingsProvider; +import org.opensearch.plugins.SecureAuxTransportSettingsProvider; import org.opensearch.plugins.SecureSettingsFactory; import org.opensearch.plugins.SecureTransportSettingsProvider; import org.opensearch.plugins.TransportExceptionHandler; @@ -32,6 +39,7 @@ import org.opensearch.security.ssl.http.netty.Netty4ConditionalDecompressor; import org.opensearch.security.ssl.http.netty.Netty4HttpRequestHeaderVerifier; import org.opensearch.security.ssl.transport.SSLConfig; +import org.opensearch.telemetry.tracing.Tracer; import org.opensearch.threadpool.ThreadPool; import org.opensearch.transport.Transport; import org.opensearch.transport.TransportAdapterProvider; @@ -185,4 +193,49 @@ public Optional<SSLEngine> buildSecureHttpServerEngine(Settings settings, HttpSe } }); } + + @Override + public Optional<SecureAuxTransportSettingsProvider> getSecureAuxTransportSettingsProvider(Settings settings) { + return Optional.of(new SecureAuxTransportSettingsProvider() { + @Override + public Optional<SecureAuxTransportSettingsProvider.SecureAuxTransportParameters> parameters() { + return Optional.of(new SecureAuxTransportSettingsProvider.SecureAuxTransportParameters() { + + @Override + public Optional<String> sslProvider() { + return sslSettingsManager.sslConfiguration(CertType.AUX).map(config -> config.sslParameters().provider().name()); + } + + @Override + public Optional<String> clientAuth() { + return sslSettingsManager.sslConfiguration(CertType.AUX).map(config -> config.sslParameters().clientAuth().name()); + } + + @Override + public Collection<String> protocols() { + return sslSettingsManager.sslConfiguration(CertType.AUX) + .map(config -> config.sslParameters().allowedProtocols()) + .orElse(Collections.emptyList()); + } + + @Override + public Collection<String> cipherSuites() { + return sslSettingsManager.sslConfiguration(CertType.AUX) + .map(config -> config.sslParameters().allowedCiphers()) + .orElse(Collections.emptyList()); + } + + @Override + public Optional<KeyManagerFactory> keyManagerFactory() { + return sslSettingsManager.sslConfiguration(CertType.AUX).map(SslConfiguration::keyStoreFactory); + } + + @Override + public Optional<TrustManagerFactory> trustManagerFactory() { + return sslSettingsManager.sslConfiguration(CertType.AUX).map(SslConfiguration::trustStoreFactory); + } + }); + } + }); + } } diff --git a/src/main/java/org/opensearch/security/ssl/OpenSearchSecuritySSLPlugin.java b/src/main/java/org/opensearch/security/ssl/OpenSearchSecuritySSLPlugin.java index 7068f40dd7..4a29a59b69 100644 --- a/src/main/java/org/opensearch/security/ssl/OpenSearchSecuritySSLPlugin.java +++ b/src/main/java/org/opensearch/security/ssl/OpenSearchSecuritySSLPlugin.java @@ -651,6 +651,89 @@ public List<Setting<?>> getSettings() { ) ); + /** + * TLS settings for aux transports. + */ + settings.add( + Setting.boolSetting( + SSLConfigConstants.SECURITY_SSL_AUX_ENABLE_OPENSSL_IF_AVAILABLE, + OPENSSL_SUPPORTED, + Property.NodeScope, + Property.Filtered + ) + ); + settings.add( + Setting.boolSetting( + SSLConfigConstants.SECURITY_SSL_AUX_ENABLED, + SSLConfigConstants.SECURITY_SSL_AUX_ENABLED_DEFAULT, + Property.NodeScope, + Property.Filtered + ) + ); + settings.add( + Setting.listSetting( + SSLConfigConstants.SECURITY_SSL_AUX_ENABLED_CIPHERS, + Collections.emptyList(), + Function.identity(), + Property.NodeScope + ) + ); + settings.add( + Setting.listSetting( + SSLConfigConstants.SECURITY_SSL_AUX_ENABLED_PROTOCOLS, + Collections.emptyList(), + Function.identity(), + Property.NodeScope + ) + ); + settings.add(Setting.simpleString(SSLConfigConstants.SECURITY_SSL_AUX_CLIENTAUTH_MODE, Property.NodeScope, Property.Filtered)); + settings.add(Setting.simpleString(SSLConfigConstants.SECURITY_SSL_AUX_KEYSTORE_ALIAS, Property.NodeScope, Property.Filtered)); + settings.add(Setting.simpleString(SSLConfigConstants.SECURITY_SSL_AUX_KEYSTORE_FILEPATH, Property.NodeScope, Property.Filtered)); + settings.add(Setting.simpleString(SSLConfigConstants.SECURITY_SSL_AUX_KEYSTORE_TYPE, Property.NodeScope, Property.Filtered)); + settings.add(Setting.simpleString(SSLConfigConstants.SECURITY_SSL_AUX_TRUSTSTORE_ALIAS, Property.NodeScope, Property.Filtered)); + settings.add(Setting.simpleString(SSLConfigConstants.SECURITY_SSL_AUX_TRUSTSTORE_FILEPATH, Property.NodeScope, Property.Filtered)); + settings.add(Setting.simpleString(SSLConfigConstants.SECURITY_SSL_AUX_TRUSTSTORE_TYPE, Property.NodeScope, Property.Filtered)); + settings.add(Setting.simpleString(SSLConfigConstants.SECURITY_SSL_AUX_PEMCERT_FILEPATH, Property.NodeScope, Property.Filtered)); + settings.add(Setting.simpleString(SSLConfigConstants.SECURITY_SSL_AUX_PEMKEY_FILEPATH, Property.NodeScope, Property.Filtered)); + settings.add( + Setting.simpleString(SSLConfigConstants.SECURITY_SSL_AUX_PEMTRUSTEDCAS_FILEPATH, Property.NodeScope, Property.Filtered) + ); + settings.add(Setting.simpleString(SSLConfigConstants.SECURITY_SSL_AUX_CRL_FILE, Property.NodeScope, Property.Filtered)); + settings.add(Setting.boolSetting(SSLConfigConstants.SECURITY_SSL_AUX_CRL_VALIDATE, false, Property.NodeScope, Property.Filtered)); + settings.add( + Setting.boolSetting( + SSLConfigConstants.SECURITY_SSL_AUX_CRL_PREFER_CRLFILE_OVER_OCSP, + false, + Property.NodeScope, + Property.Filtered + ) + ); + settings.add( + Setting.boolSetting( + SSLConfigConstants.SECURITY_SSL_AUX_CRL_CHECK_ONLY_END_ENTITIES, + true, + Property.NodeScope, + Property.Filtered + ) + ); + settings.add( + Setting.boolSetting(SSLConfigConstants.SECURITY_SSL_AUX_CRL_DISABLE_CRLDP, false, Property.NodeScope, Property.Filtered) + ); + settings.add( + Setting.boolSetting(SSLConfigConstants.SECURITY_SSL_AUX_CRL_DISABLE_OCSP, false, Property.NodeScope, Property.Filtered) + ); + settings.add( + Setting.longSetting(SSLConfigConstants.SECURITY_SSL_AUX_CRL_VALIDATION_DATE, -1, -1, Property.NodeScope, Property.Filtered) + ); + settings.add( + Setting.boolSetting( + SSLConfigConstants.SECURITY_SSL_AUX_ENFORCE_CERT_RELOAD_DN_VERIFICATION, + true, + Property.NodeScope, + Property.Filtered + ) + ); + return settings; } diff --git a/src/main/java/org/opensearch/security/ssl/SslSettingsManager.java b/src/main/java/org/opensearch/security/ssl/SslSettingsManager.java index ab6604d091..99621b9668 100644 --- a/src/main/java/org/opensearch/security/ssl/SslSettingsManager.java +++ b/src/main/java/org/opensearch/security/ssl/SslSettingsManager.java @@ -49,13 +49,10 @@ import static org.opensearch.security.ssl.util.SSLConfigConstants.PEM_CERT_FILEPATH; import static org.opensearch.security.ssl.util.SSLConfigConstants.PEM_KEY_FILEPATH; import static org.opensearch.security.ssl.util.SSLConfigConstants.PEM_TRUSTED_CAS_FILEPATH; +import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_AUX_ENABLED_DEFAULT; +import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_AUX_ENABLE_OPENSSL_IF_AVAILABLE; import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_HTTP_ENABLED_DEFAULT; import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_HTTP_ENABLE_OPENSSL_IF_AVAILABLE; -import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_HTTP_KEYSTORE_FILEPATH; -import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_HTTP_PEMCERT_FILEPATH; -import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_HTTP_PEMKEY_FILEPATH; -import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_HTTP_PEMTRUSTEDCAS_FILEPATH; -import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_HTTP_TRUSTSTORE_FILEPATH; import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_TRANSPORT_CLIENT_KEYSTORE_ALIAS; import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_TRANSPORT_CLIENT_PEMCERT_FILEPATH; import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_TRANSPORT_CLIENT_PEMKEY_FILEPATH; @@ -104,6 +101,11 @@ private Map<CertType, SslContextHandler> buildSslContexts(final Environment envi sslConfiguration -> contexts.put(CertType.HTTP, new SslContextHandler(sslConfiguration)), () -> LOGGER.warn("SSL Configuration for HTTP Layer hasn't been set") ); + Optional.ofNullable(configurations.get(CertType.AUX)) + .ifPresentOrElse( + sslConfiguration -> contexts.put(CertType.AUX, new SslContextHandler(sslConfiguration)), + () -> LOGGER.warn("SSL Configuration for optional auxiliary transport hasn't been set") + ); Optional.ofNullable(configurations.get(CertType.TRANSPORT)).ifPresentOrElse(sslConfiguration -> { contexts.put(CertType.TRANSPORT, new SslContextHandler(sslConfiguration)); final var transportClientConfiguration = Optional.ofNullable(configurations.get(CertType.TRANSPORT_CLIENT)) @@ -129,7 +131,9 @@ private Map<CertType, SslConfiguration> loadConfigurations(final Environment env final var settings = environment.settings(); final var httpSettings = settings.getByPrefix(CertType.HTTP.sslConfigPrefix()); final var transportSettings = settings.getByPrefix(CertType.TRANSPORT.sslConfigPrefix()); - if (httpSettings.isEmpty() && transportSettings.isEmpty()) { + final var auxTransportSettings = settings.getByPrefix(CertType.AUX.sslConfigPrefix()); + + if (httpSettings.isEmpty() && transportSettings.isEmpty() && auxTransportSettings.isEmpty()) { throw new OpenSearchException("No SSL configuration found"); } jceWarnings(); @@ -137,11 +141,13 @@ private Map<CertType, SslConfiguration> loadConfigurations(final Environment env final var httpEnabled = httpSettings.getAsBoolean(ENABLED, SECURITY_SSL_HTTP_ENABLED_DEFAULT); final var transportEnabled = transportSettings.getAsBoolean(ENABLED, SECURITY_SSL_TRANSPORT_ENABLED_DEFAULT); + final var auxEnabled = auxTransportSettings.getAsBoolean(ENABLED, SECURITY_SSL_AUX_ENABLED_DEFAULT); final var configurationBuilder = ImmutableMap.<CertType, SslConfiguration>builder(); + if (httpEnabled && !clientNode(settings)) { - validateHttpSettings(httpSettings); - final var httpSslParameters = SslParameters.loader(httpSettings).load(true); + validateHttpSettings(settings); + final var httpSslParameters = SslParameters.loader(httpSettings).load(CertType.HTTP); final var httpTrustAndKeyStore = new SslCertificatesLoader(CertType.HTTP.sslConfigPrefix()).loadConfiguration(environment); configurationBuilder.put( CertType.HTTP, @@ -150,7 +156,20 @@ private Map<CertType, SslConfiguration> loadConfigurations(final Environment env LOGGER.info("TLS HTTP Provider : {}", httpSslParameters.provider()); LOGGER.info("Enabled TLS protocols for HTTP layer : {}", httpSslParameters.allowedProtocols()); } - final var transportSslParameters = SslParameters.loader(transportSettings).load(false); + + if (auxEnabled && !clientNode(settings)) { + validateAuxSettings(settings); + final var auxSslParameters = SslParameters.loader(auxTransportSettings).load(CertType.AUX); + final var auxTrustAndKeyStore = new SslCertificatesLoader(CertType.AUX.sslConfigPrefix()).loadConfiguration(environment); + configurationBuilder.put( + CertType.AUX, + new SslConfiguration(auxSslParameters, auxTrustAndKeyStore.v1(), auxTrustAndKeyStore.v2()) + ); + LOGGER.info("TLS auxiliary transport Provider : {}", auxSslParameters.provider()); + LOGGER.info("Enabled TLS protocols for auxiliary transport layer : {}", auxSslParameters.allowedProtocols()); + } + + final var transportSslParameters = SslParameters.loader(transportSettings).load(CertType.TRANSPORT); if (transportEnabled) { if (hasExtendedKeyUsageEnabled(transportSettings)) { validateTransportSettings(transportSettings); @@ -235,34 +254,18 @@ private boolean clientNode(final Settings settings) { return !"node".equals(settings.get(OpenSearchSecuritySSLPlugin.CLIENT_TYPE)); } - private void validateHttpSettings(final Settings httpSettings) { - if (httpSettings == null) return; + /** + * {@link org.opensearch.OpenSearchException} thrown on invalid configuration of HTTP transport pem store/keystore. + * @param settings {@link org.opensearch.env.Environment} settings. + */ + private void validateHttpSettings(final Settings settings) { + final Settings httpSettings = settings.getByPrefix(CertType.HTTP.sslConfigPrefix()); + if (httpSettings.isEmpty()) return; if (!httpSettings.getAsBoolean(ENABLED, SECURITY_SSL_HTTP_ENABLED_DEFAULT)) return; - - final var clientAuth = ClientAuth.valueOf(httpSettings.get(CLIENT_AUTH_MODE, ClientAuth.OPTIONAL.name()).toUpperCase(Locale.ROOT)); - if (hasPemStoreSettings(httpSettings)) { - if (!httpSettings.hasValue(PEM_CERT_FILEPATH) || !httpSettings.hasValue(PEM_KEY_FILEPATH)) { - throw new OpenSearchException( - "Wrong HTTP SSL configuration. " - + String.join(", ", SECURITY_SSL_HTTP_PEMCERT_FILEPATH, SECURITY_SSL_HTTP_PEMKEY_FILEPATH) - + " must be set" - ); - } - if (clientAuth == ClientAuth.REQUIRE && !httpSettings.hasValue(PEM_TRUSTED_CAS_FILEPATH)) { - throw new OpenSearchException( - "Wrong HTTP SSL configuration. " + SECURITY_SSL_HTTP_PEMTRUSTEDCAS_FILEPATH + " must be set if client auth is required" - ); - } + validatePemStoreSettings(CertType.HTTP, settings); } else if (hasKeyOrTrustStoreSettings(httpSettings)) { - if (!httpSettings.hasValue(KEYSTORE_FILEPATH)) { - throw new OpenSearchException("Wrong HTTP SSL configuration. " + SECURITY_SSL_HTTP_KEYSTORE_FILEPATH + " must be set"); - } - if (clientAuth == ClientAuth.REQUIRE && !httpSettings.hasValue(TRUSTSTORE_FILEPATH)) { - throw new OpenSearchException( - "Wrong HTTP SSL configuration. " + SECURITY_SSL_HTTP_TRUSTSTORE_FILEPATH + " must be set if client auth is required" - ); - } + validateKeyStoreSettings(CertType.HTTP, settings); } else { throw new OpenSearchException( "Wrong HTTP SSL configuration. One of Keystore and Truststore files or X.509 PEM certificates and " @@ -271,6 +274,78 @@ private void validateHttpSettings(final Settings httpSettings) { } } + /** + * {@link org.opensearch.OpenSearchException} thrown on invalid configuration of aux transport pem store/keystore. + * @param settings {@link org.opensearch.env.Environment} settings. + */ + private void validateAuxSettings(final Settings settings) { + final Settings auxSettings = settings.getByPrefix(CertType.AUX.sslConfigPrefix()); + if (auxSettings.isEmpty()) return; + if (!auxSettings.getAsBoolean(ENABLED, SECURITY_SSL_AUX_ENABLED_DEFAULT)) return; + if (hasPemStoreSettings(auxSettings)) { + validatePemStoreSettings(CertType.AUX, settings); + } else if (hasKeyOrTrustStoreSettings(auxSettings)) { + validateKeyStoreSettings(CertType.AUX, settings); + } else { + throw new OpenSearchException( + "Wrong auxiliary transport SSL configuration. One of Keystore and Truststore files or X.509 PEM certificates and " + + "PKCS#8 keys groups should be set to configure auxiliary transport." + ); + } + } + + /** + * Validate pem store settings for transport of given type. + * Throws an {@link org.opensearch.OpenSearchException} if: + * - Either of the pem certificate or pem private key paths are not set. + * - Client auth is set to REQUIRE but pem trusted certificates filepath is not set. + * @param transportType transport type to validate + * @param settings {@link org.opensearch.env.Environment} settings. + */ + private void validatePemStoreSettings(CertType transportType, final Settings settings) throws OpenSearchException { + final var transportSettings = settings.getByPrefix(transportType.sslConfigPrefix()); + final var clientAuth = ClientAuth.valueOf(transportSettings.get(CLIENT_AUTH_MODE, ClientAuth.OPTIONAL.name()).toUpperCase(Locale.ROOT)); + if (!transportSettings.hasValue(PEM_CERT_FILEPATH) || !transportSettings.hasValue(PEM_KEY_FILEPATH)) { + throw new OpenSearchException( + "Wrong " + transportType.name().toLowerCase(Locale.ROOT) + " SSL configuration. " + + String.join(", ", transportSettings.get(PEM_CERT_FILEPATH), transportSettings.get(PEM_KEY_FILEPATH)) + + " must be set" + ); + } + if (clientAuth == ClientAuth.REQUIRE && !transportSettings.hasValue(PEM_TRUSTED_CAS_FILEPATH)) { + throw new OpenSearchException( + "Wrong " + transportType.name().toLowerCase(Locale.ROOT) + " SSL configuration. " + + PEM_TRUSTED_CAS_FILEPATH + " must be set if client auth is required" + ); + } + } + + /** + * Validate key store settings for transport of given type. + * Throws an {@link org.opensearch.OpenSearchException} if: + * - Keystore filepath is not set. + * - Client auth is set to REQUIRE but trust store filepath is not set. + * @param transportType transport type to validate + * @param settings {@link org.opensearch.env.Environment} settings. + */ + private void validateKeyStoreSettings(CertType transportType, final Settings settings) throws OpenSearchException { + final var transportSettings = settings.getByPrefix(transportType.sslConfigPrefix()); + final var clientAuth = ClientAuth.valueOf(transportSettings.get(CLIENT_AUTH_MODE, ClientAuth.OPTIONAL.name()).toUpperCase(Locale.ROOT)); + if (!transportSettings.hasValue(KEYSTORE_FILEPATH)) { + throw new OpenSearchException( + "Wrong " + transportType.name().toLowerCase(Locale.ROOT) + " SSL configuration. " + + transportSettings.get(KEYSTORE_FILEPATH) + + " must be set" + ); + } + if (clientAuth == ClientAuth.REQUIRE && !transportSettings.hasValue(TRUSTSTORE_FILEPATH)) { + throw new OpenSearchException( + "Wrong " + transportType.name().toLowerCase(Locale.ROOT) + " SSL configuration. " + + TRUSTSTORE_FILEPATH + " must be set if client auth is required" + ); + } + } + private void validateTransportSettings(final Settings transportSettings) { if (!hasExtendedKeyUsageEnabled(transportSettings)) { if (hasPemStoreSettings(transportSettings)) { @@ -397,6 +472,7 @@ void openSslWarnings(final Settings settings) { if (!OpenSearchSecuritySSLPlugin.OPENSSL_SUPPORTED && OpenSsl.isAvailable() && (settings.getAsBoolean(SECURITY_SSL_HTTP_ENABLE_OPENSSL_IF_AVAILABLE, true) + || settings.getAsBoolean(SECURITY_SSL_AUX_ENABLE_OPENSSL_IF_AVAILABLE, true) || settings.getAsBoolean(SECURITY_SSL_TRANSPORT_ENABLE_OPENSSL_IF_AVAILABLE, true))) { if (PlatformDependent.javaVersion() < 12) { LOGGER.warn( @@ -432,6 +508,10 @@ void openSslWarnings(final Settings settings) { openSslIsEnabled |= Booleans.parseBoolean(settings.get(SECURITY_SSL_HTTP_ENABLE_OPENSSL_IF_AVAILABLE)); } + if (settings.hasValue(SECURITY_SSL_AUX_ENABLE_OPENSSL_IF_AVAILABLE) == true) { + openSslIsEnabled |= Booleans.parseBoolean(settings.get(SECURITY_SSL_AUX_ENABLE_OPENSSL_IF_AVAILABLE)); + } + if (settings.hasValue(SECURITY_SSL_TRANSPORT_ENABLE_OPENSSL_IF_AVAILABLE) == true) { openSslIsEnabled |= Booleans.parseBoolean(settings.get(SECURITY_SSL_TRANSPORT_ENABLE_OPENSSL_IF_AVAILABLE)); } diff --git a/src/main/java/org/opensearch/security/ssl/config/CertType.java b/src/main/java/org/opensearch/security/ssl/config/CertType.java index 0c7a698ede..a624bd4c09 100644 --- a/src/main/java/org/opensearch/security/ssl/config/CertType.java +++ b/src/main/java/org/opensearch/security/ssl/config/CertType.java @@ -15,6 +15,7 @@ import java.util.Set; import java.util.stream.Collectors; +import static org.opensearch.security.ssl.util.SSLConfigConstants.SSL_AUX_PREFIX; import static org.opensearch.security.ssl.util.SSLConfigConstants.SSL_HTTP_PREFIX; import static org.opensearch.security.ssl.util.SSLConfigConstants.SSL_TRANSPORT_CLIENT_PREFIX; import static org.opensearch.security.ssl.util.SSLConfigConstants.SSL_TRANSPORT_PREFIX; @@ -22,7 +23,8 @@ public enum CertType { HTTP(SSL_HTTP_PREFIX), TRANSPORT(SSL_TRANSPORT_PREFIX), - TRANSPORT_CLIENT(SSL_TRANSPORT_CLIENT_PREFIX); + TRANSPORT_CLIENT(SSL_TRANSPORT_CLIENT_PREFIX), + AUX(SSL_AUX_PREFIX); public static Set<String> TYPES = Arrays.stream(CertType.values()) .map(CertType::name) diff --git a/src/main/java/org/opensearch/security/ssl/config/SslParameters.java b/src/main/java/org/opensearch/security/ssl/config/SslParameters.java index a31b14723b..01d1f25ec7 100644 --- a/src/main/java/org/opensearch/security/ssl/config/SslParameters.java +++ b/src/main/java/org/opensearch/security/ssl/config/SslParameters.java @@ -30,6 +30,8 @@ import io.netty.handler.ssl.OpenSsl; import io.netty.handler.ssl.SslProvider; +import static org.opensearch.security.ssl.util.SSLConfigConstants.ALLOWED_OPENSSL_AUX_PROTOCOLS; +import static org.opensearch.security.ssl.util.SSLConfigConstants.ALLOWED_OPENSSL_AUX_PROTOCOLS_PRIOR_OPENSSL_1_1_1_BETA_9; import static org.opensearch.security.ssl.util.SSLConfigConstants.ALLOWED_OPENSSL_HTTP_PROTOCOLS; import static org.opensearch.security.ssl.util.SSLConfigConstants.ALLOWED_OPENSSL_HTTP_PROTOCOLS_PRIOR_OPENSSL_1_1_1_BETA_9; import static org.opensearch.security.ssl.util.SSLConfigConstants.ALLOWED_OPENSSL_TRANSPORT_PROTOCOLS; @@ -130,16 +132,24 @@ private boolean validateCertDNsOnReload(final Settings settings) { return settings.getAsBoolean(ENFORCE_CERT_RELOAD_DN_VERIFICATION, true); } - private List<String> protocols(final SslProvider provider, final Settings settings, boolean http) { + private List<String> protocols(final SslProvider provider, final Settings settings, CertType certType) { final var allowedProtocols = settings.getAsList(ENABLED_PROTOCOLS, List.of(ALLOWED_SSL_PROTOCOLS)); if (provider == SslProvider.OPENSSL) { final String[] supportedProtocols; if (OpenSsl.version() > OPENSSL_1_1_1_BETA_9) { - supportedProtocols = http ? ALLOWED_OPENSSL_HTTP_PROTOCOLS : ALLOWED_OPENSSL_TRANSPORT_PROTOCOLS; + switch (certType) { + case HTTP -> supportedProtocols = ALLOWED_OPENSSL_HTTP_PROTOCOLS; + case AUX -> supportedProtocols = ALLOWED_OPENSSL_AUX_PROTOCOLS; + case TRANSPORT -> supportedProtocols = ALLOWED_OPENSSL_TRANSPORT_PROTOCOLS; + default -> throw new OpenSearchSecurityException("Unsupported certificate type: " + certType); + } } else { - supportedProtocols = http - ? ALLOWED_OPENSSL_HTTP_PROTOCOLS_PRIOR_OPENSSL_1_1_1_BETA_9 - : ALLOWED_OPENSSL_TRANSPORT_PROTOCOLS_PRIOR_OPENSSL_1_1_1_BETA_9; + switch (certType) { + case HTTP -> supportedProtocols = ALLOWED_OPENSSL_HTTP_PROTOCOLS_PRIOR_OPENSSL_1_1_1_BETA_9; + case AUX -> supportedProtocols = ALLOWED_OPENSSL_AUX_PROTOCOLS_PRIOR_OPENSSL_1_1_1_BETA_9; + case TRANSPORT -> supportedProtocols = ALLOWED_OPENSSL_TRANSPORT_PROTOCOLS_PRIOR_OPENSSL_1_1_1_BETA_9; + default -> throw new OpenSearchSecurityException("Unsupported certificate type: " + certType); + } } return openSslProtocols(allowedProtocols, supportedProtocols); } else { @@ -189,8 +199,8 @@ private List<String> ciphers(final SslProvider provider, final Settings settings return allowedCiphers.sorted(String::compareTo).collect(Collectors.toList()); } - public SslParameters load(final boolean http) { - final var clientAuth = http + public SslParameters load(final CertType certType) { + final var clientAuth = certType == CertType.HTTP || certType == CertType.AUX ? ClientAuth.valueOf(sslConfigSettings.get(CLIENT_AUTH_MODE, ClientAuth.OPTIONAL.name()).toUpperCase(Locale.ROOT)) : ClientAuth.REQUIRE; @@ -198,15 +208,15 @@ public SslParameters load(final boolean http) { final var sslParameters = new SslParameters( provider, clientAuth, - protocols(provider, sslConfigSettings, http), + protocols(provider, sslConfigSettings, certType), ciphers(provider, sslConfigSettings), validateCertDNsOnReload(sslConfigSettings) ); if (sslParameters.allowedProtocols().isEmpty()) { - throw new OpenSearchSecurityException("No ssl protocols for " + (http ? "HTTP" : "Transport") + " layer"); + throw new OpenSearchSecurityException("No ssl protocols for " + certType.name().toLowerCase(Locale.ROOT) + " layer"); } if (sslParameters.allowedCiphers().isEmpty()) { - throw new OpenSearchSecurityException("No valid cipher suites for " + (http ? "HTTP" : "Transport") + " layer"); + throw new OpenSearchSecurityException("No valid cipher suites for " + certType.name().toLowerCase(Locale.ROOT) + " layer"); } return sslParameters; } diff --git a/src/main/java/org/opensearch/security/ssl/util/SSLConfigConstants.java b/src/main/java/org/opensearch/security/ssl/util/SSLConfigConstants.java index 79ecf55575..f3b9ebe3ae 100644 --- a/src/main/java/org/opensearch/security/ssl/util/SSLConfigConstants.java +++ b/src/main/java/org/opensearch/security/ssl/util/SSLConfigConstants.java @@ -25,10 +25,11 @@ import org.opensearch.security.ssl.OpenSearchSecuritySSLPlugin; import io.netty.handler.ssl.OpenSsl; +import org.opensearch.security.ssl.config.CertType; public final class SSLConfigConstants { /** - * Global configurations + * Global configurations. */ public static final Long OPENSSL_1_1_1_BETA_9 = 0x10101009L; public static final boolean OPENSSL_AVAILABLE = OpenSearchSecuritySSLPlugin.OPENSSL_SUPPORTED && OpenSsl.isAvailable(); @@ -37,7 +38,7 @@ public final class SSLConfigConstants { public static final String[] ALLOWED_SSL_PROTOCOLS = { "TLSv1.3", "TLSv1.2", "TLSv1.1" }; /** - * Shared settings prefixes/postfixes + * Shared settings prefixes/postfixes. */ public static final String ENABLED = "enabled"; public static final String CLIENT_AUTH_MODE = "clientauth_mode"; @@ -67,7 +68,7 @@ public final class SSLConfigConstants { public static final String PEM_KEY_PASSWORD = "pemkey_password"; /** - * HTTP transport security settings + * HTTP transport security settings. */ public static final String HTTP_SETTINGS = "http"; public static final String SSL_HTTP_PREFIX = SSL_PREFIX + HTTP_SETTINGS + "."; @@ -109,6 +110,48 @@ public final class SSLConfigConstants { public static final String SECURITY_SSL_HTTP_CRL_DISABLE_CRLDP = SSL_HTTP_CRL_PREFIX + "disable_crldp"; public static final String SECURITY_SSL_HTTP_CRL_VALIDATION_DATE = SSL_HTTP_CRL_PREFIX + "validation_date"; + /** + * Auxiliary transport security settings. + */ + public static final String AUX_SETTINGS = "aux"; + public static final String SSL_AUX_PREFIX = SSL_PREFIX + AUX_SETTINGS + "."; + public static final String SSL_AUX_CRL_PREFIX = SSL_AUX_PREFIX + "crl."; + + // aux enable settings + public static final boolean SECURITY_SSL_AUX_ENABLED_DEFAULT = false; // aux transports are optional + public static final String SECURITY_SSL_AUX_ENABLE_OPENSSL_IF_AVAILABLE = SSL_AUX_PREFIX + ENABLE_OPENSSL_IF_AVAILABLE; + public static final String SECURITY_SSL_AUX_ENABLED = SSL_AUX_PREFIX + ENABLED; + public static final String SECURITY_SSL_AUX_ENABLED_CIPHERS = SSL_AUX_PREFIX + ENABLED_CIPHERS; + public static final String SECURITY_SSL_AUX_ENABLED_PROTOCOLS = SSL_AUX_PREFIX + ENABLED_PROTOCOLS; + + // aux allowed settings + public static final String[] ALLOWED_OPENSSL_AUX_PROTOCOLS = ALLOWED_SSL_PROTOCOLS; + public static final String[] ALLOWED_OPENSSL_AUX_PROTOCOLS_PRIOR_OPENSSL_1_1_1_BETA_9 = { "TLSv1.2", "TLSv1.1", "TLSv1" }; + + // aux keystore settings + public static final String SECURITY_SSL_AUX_KEYSTORE_TYPE = SSL_AUX_PREFIX + KEYSTORE_TYPE; + public static final String SECURITY_SSL_AUX_KEYSTORE_ALIAS = SSL_AUX_PREFIX + KEYSTORE_ALIAS; + public static final String SECURITY_SSL_AUX_KEYSTORE_FILEPATH = SSL_AUX_PREFIX + KEYSTORE_FILEPATH; + public static final String SECURITY_SSL_AUX_PEMKEY_FILEPATH = SSL_AUX_PREFIX + PEM_KEY_FILEPATH; + public static final String SECURITY_SSL_AUX_PEMCERT_FILEPATH = SSL_AUX_PREFIX + PEM_CERT_FILEPATH; + + // aux truststore settings + public static final String SECURITY_SSL_AUX_CLIENTAUTH_MODE = SSL_AUX_PREFIX + CLIENT_AUTH_MODE; + public static final String SECURITY_SSL_AUX_TRUSTSTORE_TYPE = SSL_AUX_PREFIX + TRUSTSTORE_TYPE; + public static final String SECURITY_SSL_AUX_TRUSTSTORE_ALIAS = SSL_AUX_PREFIX + TRUSTSTORE_ALIAS; + public static final String SECURITY_SSL_AUX_TRUSTSTORE_FILEPATH = SSL_AUX_PREFIX + TRUSTSTORE_FILEPATH; + public static final String SECURITY_SSL_AUX_ENFORCE_CERT_RELOAD_DN_VERIFICATION = SSL_AUX_PREFIX + ENFORCE_CERT_RELOAD_DN_VERIFICATION; + public static final String SECURITY_SSL_AUX_PEMTRUSTEDCAS_FILEPATH = SSL_AUX_PREFIX + PEM_TRUSTED_CAS_FILEPATH; + + // aux cert revocation list settings + public static final String SECURITY_SSL_AUX_CRL_FILE = SSL_AUX_CRL_PREFIX + "file_path"; + public static final String SECURITY_SSL_AUX_CRL_VALIDATE = SSL_AUX_CRL_PREFIX + "validate"; + public static final String SECURITY_SSL_AUX_CRL_PREFER_CRLFILE_OVER_OCSP = SSL_AUX_CRL_PREFIX + "prefer_crlfile_over_ocsp"; + public static final String SECURITY_SSL_AUX_CRL_CHECK_ONLY_END_ENTITIES = SSL_AUX_CRL_PREFIX + "check_only_end_entities"; + public static final String SECURITY_SSL_AUX_CRL_DISABLE_OCSP = SSL_AUX_CRL_PREFIX + "disable_ocsp"; + public static final String SECURITY_SSL_AUX_CRL_DISABLE_CRLDP = SSL_AUX_CRL_PREFIX + "disable_crldp"; + public static final String SECURITY_SSL_AUX_CRL_VALIDATION_DATE = SSL_AUX_CRL_PREFIX + "validation_date"; + /** * Transport layer (node-to-node) settings. * Transport layer acts both as client and server within the cluster. @@ -180,15 +223,14 @@ public final class SSLConfigConstants { + "resolve_hostname"; public static final String SECURITY_SSL_CLIENT_EXTERNAL_CONTEXT_ID = SSL_PREFIX + "client.external_context_id"; - public static String[] getSecureSSLProtocols(Settings settings, boolean http) { + public static String[] getSecureSSLProtocols(Settings settings, CertType certType) { List<String> configuredProtocols = null; - if (settings != null) { - if (http) { - configuredProtocols = settings.getAsList(SECURITY_SSL_HTTP_ENABLED_PROTOCOLS, Collections.emptyList()); - } else { - configuredProtocols = settings.getAsList(SECURITY_SSL_TRANSPORT_ENABLED_PROTOCOLS, Collections.emptyList()); - } + switch (certType){ + case HTTP -> configuredProtocols = settings.getAsList(SECURITY_SSL_HTTP_ENABLED_PROTOCOLS, Collections.emptyList()); + case AUX -> configuredProtocols = settings.getAsList(SECURITY_SSL_AUX_ENABLED_PROTOCOLS, Collections.emptyList()); + case TRANSPORT, TRANSPORT_CLIENT -> configuredProtocols = settings.getAsList(SECURITY_SSL_TRANSPORT_ENABLED_PROTOCOLS, Collections.emptyList()); + default -> throw new RuntimeException("Unsupported cert type: " + certType); } if (configuredProtocols != null && configuredProtocols.size() > 0) { @@ -198,6 +240,23 @@ public static String[] getSecureSSLProtocols(Settings settings, boolean http) { return ALLOWED_SSL_PROTOCOLS.clone(); } + public static List<String> getSecureSSLCiphers(Settings settings, CertType certType) { + List<String> configuredCiphers = null; + + switch (certType){ + case HTTP -> configuredCiphers = settings.getAsList(SECURITY_SSL_HTTP_ENABLED_CIPHERS, Collections.emptyList()); + case AUX -> configuredCiphers = settings.getAsList(SECURITY_SSL_AUX_ENABLED_CIPHERS, Collections.emptyList()); + case TRANSPORT, TRANSPORT_CLIENT -> configuredCiphers = settings.getAsList(SECURITY_SSL_TRANSPORT_ENABLED_CIPHERS, Collections.emptyList()); + default -> throw new RuntimeException("Unsupported cert type: " + certType); + } + + if (configuredCiphers != null && configuredCiphers.size() > 0) { + return configuredCiphers; + } + + return Collections.unmodifiableList(Arrays.asList(ALLOWED_SSL_CIPHERS)); + } + // @formatter:off public static final String[] ALLOWED_SSL_CIPHERS = { // TLS_<key exchange and authentication algorithms>_WITH_<bulk cipher and message authentication algorithms> @@ -312,27 +371,7 @@ public static String[] getSecureSSLProtocols(Settings settings, boolean http) { }; // @formatter:on - public static List<String> getSecureSSLCiphers(Settings settings, boolean http) { - - List<String> configuredCiphers = null; - - if (settings != null) { - if (http) { - configuredCiphers = settings.getAsList(SECURITY_SSL_HTTP_ENABLED_CIPHERS, Collections.emptyList()); - } else { - configuredCiphers = settings.getAsList(SECURITY_SSL_TRANSPORT_ENABLED_CIPHERS, Collections.emptyList()); - } - } - - if (configuredCiphers != null && configuredCiphers.size() > 0) { - return configuredCiphers; - } - - return Collections.unmodifiableList(Arrays.asList(ALLOWED_SSL_CIPHERS)); - } - private SSLConfigConstants() { } - } diff --git a/src/test/java/org/opensearch/security/ssl/OpenSSLTest.java b/src/test/java/org/opensearch/security/ssl/OpenSSLTest.java index 170d6cc410..6307aa0723 100644 --- a/src/test/java/org/opensearch/security/ssl/OpenSSLTest.java +++ b/src/test/java/org/opensearch/security/ssl/OpenSSLTest.java @@ -37,6 +37,7 @@ import org.opensearch.node.Node; import org.opensearch.node.PluginAwareNode; import org.opensearch.security.OpenSearchSecurityPlugin; +import org.opensearch.security.ssl.config.CertType; import org.opensearch.security.ssl.util.SSLConfigConstants; import org.opensearch.security.support.ConfigConstants; import org.opensearch.security.test.AbstractSecurityUnitTest; @@ -133,7 +134,7 @@ public void testAvailCiphersOpenSSL() throws Exception { // ADH-AES256-SHA256, ADH-CAMELLIA128-SHA final Set<String> openSSLSecureCiphers = new HashSet<>(); - for (final String secure : SSLConfigConstants.getSecureSSLCiphers(Settings.EMPTY, false)) { + for (final String secure : SSLConfigConstants.getSecureSSLCiphers(Settings.EMPTY, CertType.TRANSPORT)) { if (OpenSsl.isCipherSuiteAvailable(secure)) { openSSLSecureCiphers.add(secure); } diff --git a/src/test/java/org/opensearch/security/ssl/SSLTest.java b/src/test/java/org/opensearch/security/ssl/SSLTest.java index 4b35bcefd6..67acfdd17a 100644 --- a/src/test/java/org/opensearch/security/ssl/SSLTest.java +++ b/src/test/java/org/opensearch/security/ssl/SSLTest.java @@ -52,6 +52,7 @@ import org.opensearch.node.Node; import org.opensearch.node.PluginAwareNode; import org.opensearch.security.OpenSearchSecurityPlugin; +import org.opensearch.security.ssl.config.CertType; import org.opensearch.security.ssl.util.ExceptionUtils; import org.opensearch.security.ssl.util.SSLConfigConstants; import org.opensearch.security.support.ConfigConstants; @@ -776,7 +777,7 @@ public void testAvailCiphers() throws Exception { serverContext.init(null, null, null); final SSLEngine engine = serverContext.createSSLEngine(); final List<String> jdkSupportedCiphers = new ArrayList<>(Arrays.asList(engine.getSupportedCipherSuites())); - jdkSupportedCiphers.retainAll(SSLConfigConstants.getSecureSSLCiphers(Settings.EMPTY, false)); + jdkSupportedCiphers.retainAll(SSLConfigConstants.getSecureSSLCiphers(Settings.EMPTY, CertType.TRANSPORT)); engine.setEnabledCipherSuites(jdkSupportedCiphers.toArray(new String[0])); final List<String> jdkEnabledCiphers = Arrays.asList(engine.getEnabledCipherSuites()); @@ -788,11 +789,11 @@ public void testAvailCiphers() throws Exception { @Test public void testUnmodifieableCipherProtocolConfig() throws Exception { - SSLConfigConstants.getSecureSSLProtocols(Settings.EMPTY, false)[0] = "bogus"; - assertThat(SSLConfigConstants.getSecureSSLProtocols(Settings.EMPTY, false)[0], is("TLSv1.3")); + SSLConfigConstants.getSecureSSLProtocols(Settings.EMPTY, CertType.TRANSPORT)[0] = "bogus"; + assertThat(SSLConfigConstants.getSecureSSLProtocols(Settings.EMPTY, CertType.TRANSPORT)[0], is("TLSv1.3")); try { - SSLConfigConstants.getSecureSSLCiphers(Settings.EMPTY, false).set(0, "bogus"); + SSLConfigConstants.getSecureSSLCiphers(Settings.EMPTY, CertType.TRANSPORT).set(0, "bogus"); Assert.fail(); } catch (UnsupportedOperationException e) { // expected diff --git a/src/test/java/org/opensearch/security/ssl/SslContextHandlerTest.java b/src/test/java/org/opensearch/security/ssl/SslContextHandlerTest.java index 916b7b09a7..bd37b6a4e1 100644 --- a/src/test/java/org/opensearch/security/ssl/SslContextHandlerTest.java +++ b/src/test/java/org/opensearch/security/ssl/SslContextHandlerTest.java @@ -29,6 +29,7 @@ import org.bouncycastle.cert.X509CertificateHolder; import org.opensearch.common.settings.Settings; +import org.opensearch.security.ssl.config.CertType; import org.opensearch.security.ssl.config.KeyStoreConfiguration; import org.opensearch.security.ssl.config.SslParameters; import org.opensearch.security.ssl.config.TrustStoreConfiguration; @@ -278,7 +279,7 @@ List<ASN1Encodable> shuffledSans(Extension currentSans) { // CS-ENFORCE-SINGLE SslContextHandler sslContextHandler() { - final var sslParameters = SslParameters.loader(Settings.EMPTY).load(false); + final var sslParameters = SslParameters.loader(Settings.EMPTY).load(CertType.TRANSPORT); final var trustStoreConfiguration = new TrustStoreConfiguration.PemTrustStoreConfiguration(caCertificatePath); final var keyStoreConfiguration = new KeyStoreConfiguration.PemKeyStoreConfiguration( accessCertificatePath, diff --git a/src/test/java/org/opensearch/security/ssl/SslSettingsManagerReloadListenerTest.java b/src/test/java/org/opensearch/security/ssl/SslSettingsManagerReloadListenerTest.java index 64308d0abb..96b2dcd92a 100644 --- a/src/test/java/org/opensearch/security/ssl/SslSettingsManagerReloadListenerTest.java +++ b/src/test/java/org/opensearch/security/ssl/SslSettingsManagerReloadListenerTest.java @@ -18,6 +18,7 @@ import java.security.PrivateKey; import java.security.cert.X509Certificate; import java.time.temporal.ChronoUnit; +import java.util.Locale; import java.util.concurrent.TimeUnit; import com.carrotsearch.randomizedtesting.RandomizedTest; @@ -40,24 +41,15 @@ import static org.opensearch.security.ssl.CertificatesUtils.privateKeyToPemObject; import static org.opensearch.security.ssl.CertificatesUtils.writePemContent; -import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_HTTP_ENABLED; -import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_HTTP_KEYSTORE_FILEPATH; -import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_HTTP_KEYSTORE_TYPE; -import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_HTTP_PEMCERT_FILEPATH; -import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_HTTP_PEMKEY_FILEPATH; -import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_HTTP_PEMTRUSTEDCAS_FILEPATH; -import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_HTTP_TRUSTSTORE_FILEPATH; -import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_HTTP_TRUSTSTORE_TYPE; +import static org.opensearch.security.ssl.util.SSLConfigConstants.ENABLED; +import static org.opensearch.security.ssl.util.SSLConfigConstants.KEYSTORE_FILEPATH; +import static org.opensearch.security.ssl.util.SSLConfigConstants.KEYSTORE_TYPE; +import static org.opensearch.security.ssl.util.SSLConfigConstants.PEM_CERT_FILEPATH; +import static org.opensearch.security.ssl.util.SSLConfigConstants.PEM_KEY_FILEPATH; +import static org.opensearch.security.ssl.util.SSLConfigConstants.PEM_TRUSTED_CAS_FILEPATH; import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_TRANSPORT_ENABLED; -import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_TRANSPORT_KEYSTORE_FILEPATH; -import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_TRANSPORT_KEYSTORE_TYPE; -import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_TRANSPORT_PEMCERT_FILEPATH; -import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_TRANSPORT_PEMKEY_FILEPATH; -import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_TRANSPORT_PEMTRUSTEDCAS_FILEPATH; -import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_TRANSPORT_TRUSTSTORE_FILEPATH; -import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_TRANSPORT_TRUSTSTORE_TYPE; -import static org.opensearch.security.ssl.util.SSLConfigConstants.SSL_HTTP_PREFIX; -import static org.opensearch.security.ssl.util.SSLConfigConstants.SSL_TRANSPORT_PREFIX; +import static org.opensearch.security.ssl.util.SSLConfigConstants.TRUSTSTORE_FILEPATH; +import static org.opensearch.security.ssl.util.SSLConfigConstants.TRUSTSTORE_TYPE; public class SslSettingsManagerReloadListenerTest extends RandomizedTest { @@ -101,135 +93,140 @@ public void cleanUp() { } @Test - public void reloadsSslContextOnPemFilesChanged() throws Exception { - final var securitySettings = new MockSecureSettings(); - securitySettings.setString(SSL_HTTP_PREFIX + "pemkey_password_secure", certificatesRule.privateKeyPassword()); - securitySettings.setString(SSL_TRANSPORT_PREFIX + "pemkey_password_secure", certificatesRule.privateKeyPassword()); - reloadSslContextOnFilesChanged( - defaultSettingsBuilder().put(SECURITY_SSL_HTTP_ENABLED, true) - .put(SECURITY_SSL_HTTP_PEMTRUSTEDCAS_FILEPATH, path("http_ca_certificate.pem")) - .put(SECURITY_SSL_HTTP_PEMCERT_FILEPATH, path("http_access_certificate.pem")) - .put(SECURITY_SSL_HTTP_PEMKEY_FILEPATH, path("http_access_certificate_pk.pem")) - .put(SECURITY_SSL_TRANSPORT_ENABLED, true) - .put(SECURITY_SSL_TRANSPORT_PEMTRUSTEDCAS_FILEPATH, path("transport_ca_certificate.pem")) - .put(SECURITY_SSL_TRANSPORT_PEMCERT_FILEPATH, path("transport_access_certificate.pem")) - .put(SECURITY_SSL_TRANSPORT_PEMKEY_FILEPATH, path("transport_access_certificate_pk.pem")) - .setSecureSettings(securitySettings) - .build(), - (filePrefix, caCertificate, accessKeyAndCertificate) -> { - writePemContent(path(String.format("%s_ca_certificate.pem", filePrefix)), caCertificate); - writePemContent(path(String.format("%s_access_certificate.pem", filePrefix)), accessKeyAndCertificate.v2()); - writePemContent( - path(String.format("%s_access_certificate_pk.pem", filePrefix)), - privateKeyToPemObject(accessKeyAndCertificate.v1(), certificatesRule.privateKeyPassword()) - ); - } - ); + public void testReloadsSslContextOnPemStoreFilesChangedForHttp() throws Exception { + reloadSslContextOnPemFilesChangedForTransportType(CertType.HTTP); + } + + @Test + public void testReloadsSslContextOnPemStoreFilesChangedForAux() throws Exception { + reloadSslContextOnPemFilesChangedForTransportType(CertType.AUX); + } + + @Test + public void testReloadsSslContextOnPemStoreFilesChangedForTransport() throws Exception { + reloadSslContextOnPemFilesChangedForTransportType(CertType.TRANSPORT); + } + + @Test + public void testReloadsSslContextOnJdkStoreFilesChangedForHttp() throws Exception { + reloadSslContextOnJdkStoreFilesChangedForTransportType(CertType.HTTP); + } + + @Test + public void testReloadsSslContextOnJdkStoreFilesChangedForAux() throws Exception { + reloadSslContextOnJdkStoreFilesChangedForTransportType(CertType.AUX); } @Test - public void reloadsSslContextOnJdkStoreFilesChanged() throws Exception { + public void testReloadsSslContextOnJdkStoreFilesChangedForTransport() throws Exception { + reloadSslContextOnJdkStoreFilesChangedForTransportType(CertType.TRANSPORT); + } + + private void reloadSslContextOnJdkStoreFilesChangedForTransportType(CertType certType) throws Exception { + final String settingPrefix = certType.sslConfigPrefix(); + final String enabledSetting = settingPrefix + ENABLED; + final String trustStorePathSetting = settingPrefix + TRUSTSTORE_FILEPATH; + final String trustStoreTypeSetting = settingPrefix + TRUSTSTORE_TYPE; + final String keyStorePathSetting = settingPrefix + KEYSTORE_FILEPATH; + final String keyStoreTypeSetting = settingPrefix + KEYSTORE_TYPE; + final String certTypeFilePrefix = certType.name().toLowerCase(Locale.ROOT); final var keyStorePassword = randomAsciiAlphanumOfLength(10); final var secureSettings = new MockSecureSettings(); - secureSettings.setString(SSL_HTTP_PREFIX + "truststore_password_secure", keyStorePassword); - secureSettings.setString(SSL_HTTP_PREFIX + "keystore_password_secure", keyStorePassword); - secureSettings.setString(SSL_HTTP_PREFIX + "keystore_keypassword_secure", certificatesRule.privateKeyPassword()); - - secureSettings.setString(SSL_TRANSPORT_PREFIX + "truststore_password_secure", keyStorePassword); - secureSettings.setString(SSL_TRANSPORT_PREFIX + "keystore_password_secure", keyStorePassword); - secureSettings.setString(SSL_TRANSPORT_PREFIX + "keystore_keypassword_secure", certificatesRule.privateKeyPassword()); + secureSettings.setString(settingPrefix + "truststore_password_secure", keyStorePassword); + secureSettings.setString(settingPrefix + "keystore_password_secure", keyStorePassword); + secureSettings.setString(settingPrefix + "keystore_keypassword_secure", certificatesRule.privateKeyPassword()); reloadSslContextOnFilesChanged( - defaultSettingsBuilder().put(SECURITY_SSL_HTTP_ENABLED, true) - .put(SECURITY_SSL_HTTP_TRUSTSTORE_FILEPATH, path("http_truststore.jks")) - .put(SECURITY_SSL_HTTP_TRUSTSTORE_TYPE, "jks") - .put(SECURITY_SSL_HTTP_KEYSTORE_FILEPATH, path("http_keystore.p12")) - .put(SECURITY_SSL_HTTP_KEYSTORE_TYPE, "pkcs12") - .put(SECURITY_SSL_TRANSPORT_ENABLED, true) - .put(SECURITY_SSL_TRANSPORT_TRUSTSTORE_FILEPATH, path("transport_truststore.jks")) - .put(SECURITY_SSL_TRANSPORT_TRUSTSTORE_TYPE, "jks") - .put(SECURITY_SSL_TRANSPORT_KEYSTORE_FILEPATH, path("transport_keystore.p12")) - .put(SECURITY_SSL_TRANSPORT_KEYSTORE_TYPE, "pkcs12") - .setSecureSettings(secureSettings) - .build(), + certType, + defaultSettingsBuilder() + // Disable transport layer to test server transports independently. + // If certType is TRANSPORT the following line will re-enable it. + .put(SECURITY_SSL_TRANSPORT_ENABLED, false) + .put(enabledSetting, true) + .put(trustStorePathSetting, path(certTypeFilePrefix + "_truststore.jks")) + .put(trustStoreTypeSetting, "jks") + .put(keyStorePathSetting, path(certTypeFilePrefix + "_keystore.p12")) + .put(keyStoreTypeSetting, "pkcs12") + .setSecureSettings(secureSettings) + .build(), (filePrefix, caCertificate, accessKeyAndCertificate) -> { final var trustStore = KeyStore.getInstance("jks"); trustStore.load(null, null); trustStore.setCertificateEntry("ca", certificatesRule.toX509Certificate(caCertificate)); writeStore(trustStore, path(String.format("%s_truststore.jks", filePrefix)), keyStorePassword); - final var keyStore = KeyStore.getInstance("pkcs12"); keyStore.load(null, null); keyStore.setKeyEntry( - "pk", - accessKeyAndCertificate.v1(), - certificatesRule.privateKeyPassword().toCharArray(), - new X509Certificate[] { certificatesRule.toX509Certificate(accessKeyAndCertificate.v2()) } + "pk", + accessKeyAndCertificate.v1(), + certificatesRule.privateKeyPassword().toCharArray(), + new X509Certificate[] { certificatesRule.toX509Certificate(accessKeyAndCertificate.v2()) } ); writeStore(keyStore, path(String.format("%s_keystore.p12", filePrefix)), keyStorePassword); } ); } - void reloadSslContextOnFilesChanged(final Settings settings, final CertificatesWriter certificatesWriter) throws Exception { - final var defaultHttpCertificates = generateCertificates(); - final var defaultHttpKeyPair = defaultHttpCertificates.v1(); - final var httpCaCertificate = defaultHttpCertificates.v2().v1(); - final var httpAccessKeyAndCertificate = defaultHttpCertificates.v2().v2(); - - final var defaultTransportCertificates = generateCertificates(); - final var defaultTransportKeyPair = defaultTransportCertificates.v1(); - final var transportCaCertificate = defaultTransportCertificates.v2().v1(); - final var transportAccessKeyAndCertificate = defaultTransportCertificates.v2().v2(); - - final var reloadHttpCertificates = randomBoolean(); + private void reloadSslContextOnPemFilesChangedForTransportType(CertType certType) throws Exception { + final String settingPrefix = certType.sslConfigPrefix(); + final String enabledSetting = settingPrefix + ENABLED; + final String pemTrustCasPathSetting = settingPrefix + PEM_TRUSTED_CAS_FILEPATH; + final String pemCertPathSetting = settingPrefix + PEM_CERT_FILEPATH; + final String pemKeyPathSetting = settingPrefix + PEM_KEY_FILEPATH; + final String certTypeFilePrefix = certType.name().toLowerCase(Locale.ROOT); + final var secureSettings = new MockSecureSettings(); + secureSettings.setString(settingPrefix + "pemkey_password_secure", certificatesRule.privateKeyPassword()); + reloadSslContextOnFilesChanged( + certType, + defaultSettingsBuilder() + // Disable transport layer to test server transports independently. + // If certType is TRANSPORT the following line will re-enable it. + .put(SECURITY_SSL_TRANSPORT_ENABLED, false) + .put(enabledSetting, true) + .put(pemTrustCasPathSetting, path(certTypeFilePrefix + "_ca_certificate.pem")) + .put(pemCertPathSetting, path(certTypeFilePrefix + "_access_certificate.pem")) + .put(pemKeyPathSetting, path(certTypeFilePrefix + "_access_certificate_pk.pem")) + .setSecureSettings(secureSettings) + .build(), + (filePrefix, caCertificate, accessKeyAndCertificate) -> { + writePemContent(path(String.format("%s_ca_certificate.pem", filePrefix)), caCertificate); + writePemContent(path(String.format("%s_access_certificate.pem", filePrefix)), accessKeyAndCertificate.v2()); + writePemContent( + path(String.format("%s_access_certificate_pk.pem", filePrefix)), + privateKeyToPemObject(accessKeyAndCertificate.v1(), certificatesRule.privateKeyPassword()) + ); + } + ); + } - certificatesWriter.write("http", httpCaCertificate, httpAccessKeyAndCertificate); - certificatesWriter.write("transport", transportCaCertificate, transportAccessKeyAndCertificate); + private void reloadSslContextOnFilesChanged(CertType certType, final Settings settings, final CertificatesWriter certificatesWriter) throws Exception { + final String certNamePrefix = certType.name().toLowerCase(Locale.ROOT); + final var defaultCertificates = generateCertificates(); + var defaultKeyPair = defaultCertificates.v1(); + var caCertificate = defaultCertificates.v2().v1(); + var accessKeyAndCertificate = defaultCertificates.v2().v2(); + certificatesWriter.write(certNamePrefix, caCertificate, accessKeyAndCertificate); final var sslSettingsManager = new SslSettingsManager(TestEnvironment.newEnvironment(settings)); sslSettingsManager.addSslConfigurationsChangeListener(resourceWatcherService); - - final var httpSslContextBefore = sslSettingsManager.sslContextHandler(CertType.HTTP).orElseThrow().sslContext(); - final var transportSslContextBefore = sslSettingsManager.sslContextHandler(CertType.TRANSPORT).orElseThrow().sslContext(); - final var transportClientSslContextBefore = sslSettingsManager.sslContextHandler(CertType.TRANSPORT_CLIENT) - .orElseThrow() - .sslContext(); - - final var filePrefix = reloadHttpCertificates ? "http" : "transport"; - final var keyPair = reloadHttpCertificates ? defaultHttpKeyPair : defaultTransportKeyPair; - var caCertificate = reloadHttpCertificates ? httpCaCertificate : transportCaCertificate; - var keyAndCertificate = reloadHttpCertificates ? httpAccessKeyAndCertificate : transportAccessKeyAndCertificate; + final var sslContextBefore = sslSettingsManager.sslContextHandler(certType).orElseThrow().sslContext(); if (randomBoolean()) { caCertificate = certificatesRule.generateCaCertificate( - keyPair, - caCertificate.getNotBefore().toInstant(), - caCertificate.getNotAfter().toInstant().plus(365, ChronoUnit.DAYS) + defaultKeyPair, + caCertificate.getNotBefore().toInstant(), + caCertificate.getNotAfter().toInstant().plus(365, ChronoUnit.DAYS) ); } else { - keyAndCertificate = certificatesRule.generateAccessCertificate( - keyPair, - keyAndCertificate.v2().getNotBefore().toInstant(), - keyAndCertificate.v2().getNotAfter().toInstant().plus(365, ChronoUnit.DAYS) + accessKeyAndCertificate = certificatesRule.generateAccessCertificate( + defaultKeyPair, + accessKeyAndCertificate.v2().getNotBefore().toInstant(), + accessKeyAndCertificate.v2().getNotAfter().toInstant().plus(365, ChronoUnit.DAYS) ); } - certificatesWriter.write(filePrefix, caCertificate, keyAndCertificate); + certificatesWriter.write(certNamePrefix, caCertificate, accessKeyAndCertificate); Awaitility.await("Wait for reloading SSL context").until(() -> { - final var httpSslContextAfter = sslSettingsManager.sslContextHandler(CertType.HTTP).orElseThrow().sslContext(); - final var transportSslContextAfter = sslSettingsManager.sslContextHandler(CertType.TRANSPORT).orElseThrow().sslContext(); - final var transportClientSslContextAfter = sslSettingsManager.sslContextHandler(CertType.TRANSPORT_CLIENT) - .orElseThrow() - .sslContext(); - - if (reloadHttpCertificates) { - return !httpSslContextAfter.equals(httpSslContextBefore) - && transportSslContextBefore.equals(transportSslContextAfter) - && transportClientSslContextBefore.equals(transportClientSslContextAfter); - } else { - return httpSslContextAfter.equals(httpSslContextBefore) - && !transportSslContextBefore.equals(transportSslContextAfter) - && !transportClientSslContextBefore.equals(transportClientSslContextAfter); - } + final var sslContextAfter = sslSettingsManager.sslContextHandler(certType).orElseThrow().sslContext(); + return !sslContextAfter.equals(sslContextBefore); }); } diff --git a/src/test/java/org/opensearch/security/ssl/SslSettingsManagerTest.java b/src/test/java/org/opensearch/security/ssl/SslSettingsManagerTest.java index 1aa2c47eb3..cfcdef4096 100644 --- a/src/test/java/org/opensearch/security/ssl/SslSettingsManagerTest.java +++ b/src/test/java/org/opensearch/security/ssl/SslSettingsManagerTest.java @@ -33,6 +33,12 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.opensearch.security.ssl.CertificatesUtils.privateKeyToPemObject; import static org.opensearch.security.ssl.CertificatesUtils.writePemContent; +import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_AUX_CLIENTAUTH_MODE; +import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_AUX_ENABLED; +import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_AUX_KEYSTORE_FILEPATH; +import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_AUX_PEMCERT_FILEPATH; +import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_AUX_PEMKEY_FILEPATH; +import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_AUX_PEMTRUSTEDCAS_FILEPATH; import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_HTTP_CLIENTAUTH_MODE; import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_HTTP_ENABLED; import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_HTTP_KEYSTORE_FILEPATH; @@ -52,6 +58,7 @@ import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_TRANSPORT_SERVER_PEMKEY_FILEPATH; import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_TRANSPORT_SERVER_PEMTRUSTEDCAS_FILEPATH; import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_TRANSPORT_TRUSTSTORE_FILEPATH; +import static org.opensearch.security.ssl.util.SSLConfigConstants.SSL_AUX_PREFIX; import static org.opensearch.security.ssl.util.SSLConfigConstants.SSL_HTTP_PREFIX; import static org.opensearch.security.ssl.util.SSLConfigConstants.SSL_TRANSPORT_CLIENT_EXTENDED_PREFIX; import static org.opensearch.security.ssl.util.SSLConfigConstants.SSL_TRANSPORT_PREFIX; @@ -67,6 +74,7 @@ public class SslSettingsManagerTest extends RandomizedTest { @BeforeClass public static void setUp() throws Exception { writeCertificates("ca_http_certificate.pem", "access_http_certificate.pem", "access_http_certificate_pk.pem"); + writeCertificates("ca_aux_certificate.pem", "access_aux_certificate.pem", "access_aux_certificate_pk.pem"); writeCertificates("ca_transport_certificate.pem", "access_transport_certificate.pem", "access_transport_certificate_pk.pem"); } @@ -90,19 +98,16 @@ public void failsIfNoSslSet() throws Exception { assertThrows(OpenSearchException.class, () -> new SslSettingsManager(TestEnvironment.newEnvironment(settings))); } - @Test - public void transportFailsIfNoConfigDefine() throws Exception { - final var noTransportSettings = defaultSettingsBuilder().put(SECURITY_SSL_HTTP_ENABLED, true).build(); + private void transportFailsIfNoConfigDefine(String transportEnabledSetting) { + final var noTransportSettings = defaultSettingsBuilder().put(transportEnabledSetting, true).build(); assertThrows(OpenSearchException.class, () -> new SslSettingsManager(TestEnvironment.newEnvironment(noTransportSettings))); } @Test - public void transportFailsIfConfigEnabledButNotDefined() throws Exception { - final var noTransportSettingsButItEnabled = defaultSettingsBuilder().put(SECURITY_SSL_TRANSPORT_ENABLED, true).build(); - assertThrows( - OpenSearchException.class, - () -> new SslSettingsManager(TestEnvironment.newEnvironment(noTransportSettingsButItEnabled)) - ); + public void testFailsIfNoConfigDefine() { + transportFailsIfNoConfigDefine(SECURITY_SSL_HTTP_ENABLED); + transportFailsIfNoConfigDefine(SECURITY_SSL_AUX_ENABLED); + transportFailsIfNoConfigDefine(SECURITY_SSL_TRANSPORT_ENABLED); } @Test @@ -150,42 +155,90 @@ public void transportFailsIfConfigDisabled() throws Exception { assertThrows(OpenSearchException.class, () -> new SslSettingsManager(TestEnvironment.newEnvironment(settings))); } - @Test - public void httpConfigFailsIfBothPemAndJDKSettingsWereSet() throws Exception { - final var keyStoreSettings = randomFrom(List.of(SECURITY_SSL_HTTP_KEYSTORE_FILEPATH)); - final var pemKeyStoreSettings = randomFrom( - List.of(SECURITY_SSL_HTTP_PEMKEY_FILEPATH, SECURITY_SSL_HTTP_PEMCERT_FILEPATH, SECURITY_SSL_HTTP_PEMTRUSTEDCAS_FILEPATH) - ); - final var settings = defaultSettingsBuilder().put(SECURITY_SSL_HTTP_ENABLED, true) - .put(keyStoreSettings, "aaa") - .put(pemKeyStoreSettings, "bbb") - .build(); + /** + * Security plugin enforces common store type for a single transport configuration. + * Pem store and JKS (Java KeyStore) cannot both be used for transport. + */ + private void configFailsIfBothPemAndJDKSettingsWereSet( + String transportEnabledSetting, + List<String> transportJKSSettings, + List<String> transportPemStoreSettings + ){ + final var settings = defaultSettingsBuilder().put(transportEnabledSetting, true) + .put(randomFrom(transportJKSSettings), "aaa") + .put(randomFrom(transportPemStoreSettings), "bbb") + .build(); assertThrows(OpenSearchException.class, () -> new SslSettingsManager(TestEnvironment.newEnvironment(settings))); } @Test - public void httpConfigFailsIfHttpEnabledButButNotDefined() throws Exception { - final var settings = defaultSettingsBuilder().put(SECURITY_SSL_HTTP_ENABLED, true).build(); + public void configFailsIfBothPemAndJDKSettingsWereSet() throws Exception { + configFailsIfBothPemAndJDKSettingsWereSet( + SECURITY_SSL_HTTP_ENABLED, + List.of(SECURITY_SSL_HTTP_KEYSTORE_FILEPATH), + List.of(SECURITY_SSL_HTTP_PEMKEY_FILEPATH, SECURITY_SSL_HTTP_PEMCERT_FILEPATH, SECURITY_SSL_HTTP_PEMTRUSTEDCAS_FILEPATH)); + configFailsIfBothPemAndJDKSettingsWereSet( + SECURITY_SSL_AUX_ENABLED, + List.of(SECURITY_SSL_AUX_KEYSTORE_FILEPATH), + List.of(SECURITY_SSL_AUX_PEMKEY_FILEPATH, SECURITY_SSL_AUX_PEMCERT_FILEPATH, SECURITY_SSL_AUX_PEMTRUSTEDCAS_FILEPATH)); + configFailsIfBothPemAndJDKSettingsWereSet( + SECURITY_SSL_TRANSPORT_ENABLED, + List.of(SECURITY_SSL_TRANSPORT_KEYSTORE_FILEPATH), + List.of(SECURITY_SSL_TRANSPORT_PEMKEY_FILEPATH, SECURITY_SSL_TRANSPORT_PEMCERT_FILEPATH, SECURITY_SSL_TRANSPORT_PEMTRUSTEDCAS_FILEPATH)); + } + + private void configFailsIfClientAuthRequiredAndJdkTrustStoreNotSet( + String transportEnabledSetting, + String clientAuthEnabledSetting, + String keystorePathSetting + ) { + final var settings = defaultSettingsBuilder().put(transportEnabledSetting, true) + .put(clientAuthEnabledSetting, ClientAuth.REQUIRE.name().toLowerCase(Locale.ROOT)) + .put(keystorePathSetting, certificatesRule.configRootFolder().toString()) + .build(); assertThrows(OpenSearchException.class, () -> new SslSettingsManager(TestEnvironment.newEnvironment(settings))); } @Test - public void httpConfigFailsIfClientAuthRequiredAndJdkTrustStoreNotSet() throws Exception { - final var settings = defaultSettingsBuilder().put(SECURITY_SSL_HTTP_ENABLED, true) - .put(SECURITY_SSL_HTTP_CLIENTAUTH_MODE, ClientAuth.REQUIRE.name().toLowerCase(Locale.ROOT)) - .put(SECURITY_SSL_HTTP_KEYSTORE_FILEPATH, certificatesRule.configRootFolder().toString()) - .build(); + public void serverTransportConfigFailsIfClientAuthRequiredAndJdkTrustStoreNotSet() { + configFailsIfClientAuthRequiredAndJdkTrustStoreNotSet( + SECURITY_SSL_HTTP_ENABLED, + SECURITY_SSL_HTTP_CLIENTAUTH_MODE, + SECURITY_SSL_HTTP_KEYSTORE_FILEPATH); + configFailsIfClientAuthRequiredAndJdkTrustStoreNotSet( + SECURITY_SSL_AUX_ENABLED, + SECURITY_SSL_AUX_CLIENTAUTH_MODE, + SECURITY_SSL_AUX_KEYSTORE_FILEPATH); + } + + private void configFailsIfClientAuthRequiredAndPemTrustedCasNotSet( + String transportEnabledSetting, + String clientAuthEnabledSetting, + String pemkeyPathSetting, + String pemcertPathSetting + ) { + final var settings = defaultSettingsBuilder().put(transportEnabledSetting, true) + .put(clientAuthEnabledSetting, ClientAuth.REQUIRE.name().toLowerCase(Locale.ROOT)) + .put(pemkeyPathSetting, "aaa") + .put(pemcertPathSetting, "bbb") + .build(); assertThrows(OpenSearchException.class, () -> new SslSettingsManager(TestEnvironment.newEnvironment(settings))); } @Test - public void httpConfigFailsIfClientAuthRequiredAndPemTrustedCasNotSet() throws Exception { - final var settings = defaultSettingsBuilder().put(SECURITY_SSL_HTTP_ENABLED, true) - .put(SECURITY_SSL_HTTP_CLIENTAUTH_MODE, ClientAuth.REQUIRE.name().toLowerCase(Locale.ROOT)) - .put(SECURITY_SSL_HTTP_PEMKEY_FILEPATH, "aaa") - .put(SECURITY_SSL_HTTP_PEMCERT_FILEPATH, "bbb") - .build(); - assertThrows(OpenSearchException.class, () -> new SslSettingsManager(TestEnvironment.newEnvironment(settings))); + public void serverTransportConfigFailsIfClientAuthRequiredAndPemTrustedCasNotSet() { + configFailsIfClientAuthRequiredAndPemTrustedCasNotSet( + SECURITY_SSL_HTTP_ENABLED, + SECURITY_SSL_HTTP_CLIENTAUTH_MODE, + SECURITY_SSL_HTTP_PEMKEY_FILEPATH, + SECURITY_SSL_HTTP_PEMCERT_FILEPATH + ); + configFailsIfClientAuthRequiredAndPemTrustedCasNotSet( + SECURITY_SSL_AUX_ENABLED, + SECURITY_SSL_AUX_CLIENTAUTH_MODE, + SECURITY_SSL_AUX_PEMKEY_FILEPATH, + SECURITY_SSL_AUX_PEMCERT_FILEPATH + ); } @Test @@ -193,6 +246,8 @@ public void loadConfigurationAndBuildHSslContextForSslOnlyMode() throws Exceptio final var securitySettings = new MockSecureSettings(); securitySettings.setString(SSL_TRANSPORT_PREFIX + "pemkey_password_secure", certificatesRule.privateKeyPassword()); securitySettings.setString(SSL_HTTP_PREFIX + "pemkey_password_secure", certificatesRule.privateKeyPassword()); + securitySettings.setString(SSL_AUX_PREFIX + "pemkey_password_secure", certificatesRule.privateKeyPassword()); + final var settingsBuilder = defaultSettingsBuilder().setSecureSettings(securitySettings); withTransportSslSettings( settingsBuilder, @@ -201,6 +256,8 @@ public void loadConfigurationAndBuildHSslContextForSslOnlyMode() throws Exceptio "access_transport_certificate_pk.pem" ); withHttpSslSettings(settingsBuilder); + withAuxSslSettings(settingsBuilder); + final var transportEnabled = randomBoolean(); final var sslSettingsManager = new SslSettingsManager( TestEnvironment.newEnvironment( @@ -209,6 +266,8 @@ public void loadConfigurationAndBuildHSslContextForSslOnlyMode() throws Exceptio ); assertThat("Loaded HTTP configuration", sslSettingsManager.sslConfiguration(CertType.HTTP).isPresent()); + assertThat("Loaded AUX configuration", sslSettingsManager.sslConfiguration(CertType.AUX).isPresent()); + if (transportEnabled) { assertThat("Loaded Transport configuration", sslSettingsManager.sslConfiguration(CertType.TRANSPORT).isPresent()); assertThat("Loaded Transport Client configuration", sslSettingsManager.sslConfiguration(CertType.TRANSPORT_CLIENT).isPresent()); @@ -221,6 +280,8 @@ public void loadConfigurationAndBuildHSslContextForSslOnlyMode() throws Exceptio } assertThat("Built HTTP SSL Context", sslSettingsManager.sslContextHandler(CertType.HTTP).isPresent()); + assertThat("Built AUX SSL Context", sslSettingsManager.sslContextHandler(CertType.AUX).isPresent()); + if (transportEnabled) { assertThat("Built Transport SSL Context", sslSettingsManager.sslContextHandler(CertType.TRANSPORT).isPresent()); assertThat("Built Client SSL Context", sslSettingsManager.sslContextHandler(CertType.TRANSPORT_CLIENT).isPresent()); @@ -233,6 +294,10 @@ public void loadConfigurationAndBuildHSslContextForSslOnlyMode() throws Exceptio "Built Server SSL context for HTTP", sslSettingsManager.sslContextHandler(CertType.HTTP).map(SslContextHandler::sslContext).map(SslContext::isServer).orElse(false) ); + assertThat( + "Built Server SSL context for AUX", + sslSettingsManager.sslContextHandler(CertType.AUX).map(SslContextHandler::sslContext).map(SslContext::isServer).orElse(false) + ); } @Test @@ -284,6 +349,8 @@ public void loadConfigurationAndBuildSslContexts() throws Exception { final var securitySettings = new MockSecureSettings(); securitySettings.setString(SSL_TRANSPORT_PREFIX + "pemkey_password_secure", certificatesRule.privateKeyPassword()); securitySettings.setString(SSL_HTTP_PREFIX + "pemkey_password_secure", certificatesRule.privateKeyPassword()); + securitySettings.setString(SSL_AUX_PREFIX + "pemkey_password_secure", certificatesRule.privateKeyPassword()); + final var settingsBuilder = defaultSettingsBuilder().setSecureSettings(securitySettings); withTransportSslSettings( settingsBuilder, @@ -292,12 +359,16 @@ public void loadConfigurationAndBuildSslContexts() throws Exception { "access_transport_certificate_pk.pem" ); withHttpSslSettings(settingsBuilder); + withAuxSslSettings(settingsBuilder); + final var sslSettingsManager = new SslSettingsManager(TestEnvironment.newEnvironment(settingsBuilder.build())); assertThat("Loaded HTTP configuration", sslSettingsManager.sslConfiguration(CertType.HTTP).isPresent()); + assertThat("Loaded AUX configuration", sslSettingsManager.sslConfiguration(CertType.AUX).isPresent()); assertThat("Loaded Transport configuration", sslSettingsManager.sslConfiguration(CertType.TRANSPORT).isPresent()); assertThat("Loaded Transport Client configuration", sslSettingsManager.sslConfiguration(CertType.TRANSPORT_CLIENT).isPresent()); assertThat("Built HTTP SSL Context", sslSettingsManager.sslContextHandler(CertType.HTTP).isPresent()); + assertThat("Built AUX SSL Context", sslSettingsManager.sslContextHandler(CertType.AUX).isPresent()); assertThat("Built Transport SSL Context", sslSettingsManager.sslContextHandler(CertType.TRANSPORT).isPresent()); assertThat("Built Transport Client SSL Context", sslSettingsManager.sslContextHandler(CertType.TRANSPORT_CLIENT).isPresent()); @@ -305,6 +376,10 @@ public void loadConfigurationAndBuildSslContexts() throws Exception { "Built Server SSL context for HTTP", sslSettingsManager.sslContextHandler(CertType.HTTP).map(SslContextHandler::sslContext).map(SslContext::isServer).orElse(false) ); + assertThat( + "Built Server SSL context for AUX", + sslSettingsManager.sslContextHandler(CertType.AUX).map(SslContextHandler::sslContext).map(SslContext::isServer).orElse(false) + ); assertThat( "Built Server SSL context for Transport", sslSettingsManager.sslContextHandler(CertType.TRANSPORT) @@ -336,6 +411,7 @@ public void loadConfigurationAndBuildTransportSslContext() throws Exception { final var sslSettingsManager = new SslSettingsManager(TestEnvironment.newEnvironment(settingsBuilder.build())); assertThat("Didn't load HTTP configuration", sslSettingsManager.sslConfiguration(CertType.HTTP).isEmpty()); + assertThat("Didn't load AUX configuration", sslSettingsManager.sslConfiguration(CertType.AUX).isEmpty()); assertThat("Loaded Transport configuration", sslSettingsManager.sslConfiguration(CertType.TRANSPORT).isPresent()); assertThat("Loaded Transport Client configuration", sslSettingsManager.sslConfiguration(CertType.TRANSPORT_CLIENT).isPresent()); assertThat( @@ -346,6 +422,7 @@ public void loadConfigurationAndBuildTransportSslContext() throws Exception { ); assertThat("Built HTTP SSL Context", sslSettingsManager.sslContextHandler(CertType.HTTP).isEmpty()); + assertThat("Built AUX SSL Context", sslSettingsManager.sslContextHandler(CertType.AUX).isEmpty()); assertThat("Built Transport SSL Context", sslSettingsManager.sslContextHandler(CertType.TRANSPORT).isPresent()); assertThat("Built Transport Client SSL Context", sslSettingsManager.sslContextHandler(CertType.TRANSPORT_CLIENT).isPresent()); @@ -405,6 +482,7 @@ public void loadConfigurationAndBuildExtendedTransportSslContexts() throws Excep ); assertThat("Didn't load HTTP configuration", sslSettingsManager.sslConfiguration(CertType.HTTP).isEmpty()); + assertThat("Didn't load AUX configuration", sslSettingsManager.sslConfiguration(CertType.AUX).isEmpty()); assertThat("Loaded Transport configuration", sslSettingsManager.sslConfiguration(CertType.TRANSPORT).isPresent()); assertThat("Loaded Transport Client configuration", sslSettingsManager.sslConfiguration(CertType.TRANSPORT_CLIENT).isPresent()); assertThat( @@ -414,6 +492,7 @@ public void loadConfigurationAndBuildExtendedTransportSslContexts() throws Excep .orElse(true) ); assertThat("Built HTTP SSL Context", sslSettingsManager.sslContextHandler(CertType.HTTP).isEmpty()); + assertThat("Built AUX SSL Context", sslSettingsManager.sslContextHandler(CertType.AUX).isEmpty()); assertThat("Built Transport SSL Context", sslSettingsManager.sslContextHandler(CertType.TRANSPORT).isPresent()); assertThat("Built Transport Client SSL Context", sslSettingsManager.sslContextHandler(CertType.TRANSPORT_CLIENT).isPresent()); @@ -455,6 +534,14 @@ private void withHttpSslSettings(final Settings.Builder settingsBuilder) { .put(SECURITY_SSL_HTTP_PEMKEY_FILEPATH, path("access_http_certificate_pk.pem")); } + private void withAuxSslSettings(final Settings.Builder settingsBuilder) { + settingsBuilder.put(SECURITY_SSL_AUX_ENABLED, true) + .put(SECURITY_SSL_AUX_ENABLED, true) + .put(SECURITY_SSL_AUX_PEMTRUSTEDCAS_FILEPATH, path("ca_aux_certificate.pem")) + .put(SECURITY_SSL_AUX_PEMCERT_FILEPATH, path("access_aux_certificate.pem")) + .put(SECURITY_SSL_AUX_PEMKEY_FILEPATH, path("access_aux_certificate_pk.pem")); + } + Settings.Builder defaultSettingsBuilder() { return Settings.builder() .put(Environment.PATH_HOME_SETTING.getKey(), certificatesRule.configRootFolder().toString()) diff --git a/src/test/java/org/opensearch/security/ssl/config/JdkSslCertificatesLoaderTest.java b/src/test/java/org/opensearch/security/ssl/config/JdkSslCertificatesLoaderTest.java index 93df4ab7a2..0e6d5ec2fa 100644 --- a/src/test/java/org/opensearch/security/ssl/config/JdkSslCertificatesLoaderTest.java +++ b/src/test/java/org/opensearch/security/ssl/config/JdkSslCertificatesLoaderTest.java @@ -45,6 +45,7 @@ import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_TRANSPORT_SERVER_TRUSTSTORE_ALIAS; import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_TRANSPORT_TRUSTSTORE_FILEPATH; import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_TRANSPORT_TRUSTSTORE_TYPE; +import static org.opensearch.security.ssl.util.SSLConfigConstants.SSL_AUX_PREFIX; import static org.opensearch.security.ssl.util.SSLConfigConstants.SSL_HTTP_PREFIX; import static org.opensearch.security.ssl.util.SSLConfigConstants.SSL_TRANSPORT_CLIENT_EXTENDED_PREFIX; import static org.opensearch.security.ssl.util.SSLConfigConstants.SSL_TRANSPORT_PREFIX; @@ -70,6 +71,11 @@ public void loadHttpSslConfigurationFromKeyAndTrustStoreFiles() throws Exception testJdkBasedSslConfiguration(SSL_HTTP_PREFIX, randomBoolean()); } + @Test + public void loadAuxSslConfigurationFromKeyAndTrustStoreFiles() throws Exception { + testJdkBasedSslConfiguration(SSL_AUX_PREFIX, randomBoolean()); + } + @Test public void loadTransportJdkBasedSslConfiguration() throws Exception { testJdkBasedSslConfiguration(SSL_TRANSPORT_PREFIX, true); diff --git a/src/test/java/org/opensearch/security/ssl/config/PemSslCertificatesLoaderTest.java b/src/test/java/org/opensearch/security/ssl/config/PemSslCertificatesLoaderTest.java index d03bf9c59d..b4e88d678f 100644 --- a/src/test/java/org/opensearch/security/ssl/config/PemSslCertificatesLoaderTest.java +++ b/src/test/java/org/opensearch/security/ssl/config/PemSslCertificatesLoaderTest.java @@ -40,6 +40,7 @@ import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_TRANSPORT_SERVER_PEMCERT_FILEPATH; import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_TRANSPORT_SERVER_PEMKEY_FILEPATH; import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_TRANSPORT_SERVER_PEMTRUSTEDCAS_FILEPATH; +import static org.opensearch.security.ssl.util.SSLConfigConstants.SSL_AUX_PREFIX; import static org.opensearch.security.ssl.util.SSLConfigConstants.SSL_HTTP_PREFIX; import static org.opensearch.security.ssl.util.SSLConfigConstants.SSL_TRANSPORT_CLIENT_EXTENDED_PREFIX; import static org.opensearch.security.ssl.util.SSLConfigConstants.SSL_TRANSPORT_PREFIX; @@ -73,6 +74,11 @@ public void loadHttpSslConfigurationFromPemFiles() throws Exception { testLoadPemBasedConfiguration(SSL_HTTP_PREFIX, randomBoolean()); } + @Test + public void loadAuxSslConfigurationFromPemFiles() throws Exception { + testLoadPemBasedConfiguration(SSL_AUX_PREFIX, randomBoolean()); + } + @Test public void loadTransportSslConfigurationFromPemFiles() throws Exception { testLoadPemBasedConfiguration(SSL_HTTP_PREFIX, false); @@ -94,7 +100,7 @@ void testLoadPemBasedConfiguration(final String sslConfigPrefix, final boolean u } final var settings = settingsBuilder.build(); - final var configuration = new SslCertificatesLoader(SSL_HTTP_PREFIX).loadConfiguration(TestEnvironment.newEnvironment(settings)); + final var configuration = new SslCertificatesLoader(sslConfigPrefix).loadConfiguration(TestEnvironment.newEnvironment(settings)); if (useAuthorityCertificate) { assertTrustStoreConfiguration( configuration.v1(), diff --git a/src/test/java/org/opensearch/security/ssl/config/SslParametersTest.java b/src/test/java/org/opensearch/security/ssl/config/SslParametersTest.java index d95c336e15..c723c5ed83 100644 --- a/src/test/java/org/opensearch/security/ssl/config/SslParametersTest.java +++ b/src/test/java/org/opensearch/security/ssl/config/SslParametersTest.java @@ -11,12 +11,15 @@ package org.opensearch.security.ssl.config; +import java.security.NoSuchAlgorithmException; import java.util.List; import java.util.Locale; import java.util.stream.Collectors; import java.util.stream.Stream; import javax.net.ssl.SSLContext; +import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; import org.opensearch.common.settings.Settings; @@ -27,64 +30,111 @@ import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; import static org.opensearch.security.ssl.util.SSLConfigConstants.ALLOWED_SSL_CIPHERS; +import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_AUX_CLIENTAUTH_MODE; +import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_AUX_ENABLED_CIPHERS; +import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_AUX_ENABLED_PROTOCOLS; import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_HTTP_CLIENTAUTH_MODE; import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_HTTP_ENABLED_CIPHERS; import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_HTTP_ENABLED_PROTOCOLS; import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_TRANSPORT_ENABLED_CIPHERS; import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_TRANSPORT_ENABLED_PROTOCOLS; +import static org.opensearch.security.ssl.util.SSLConfigConstants.SSL_AUX_PREFIX; import static org.opensearch.security.ssl.util.SSLConfigConstants.SSL_HTTP_PREFIX; import static org.opensearch.security.ssl.util.SSLConfigConstants.SSL_TRANSPORT_PREFIX; public class SslParametersTest { - @Test - public void testDefaultSslParameters() throws Exception { - final var settings = Settings.EMPTY; - final var httpSslParameters = SslParameters.loader(settings).load(true); - final var transportSslParameters = SslParameters.loader(settings).load(false); + List<String> finalDefaultCiphers; + @Before + public void setup() throws NoSuchAlgorithmException { final var defaultCiphers = List.of(ALLOWED_SSL_CIPHERS); - final var finalDefaultCiphers = Stream.of(SSLContext.getDefault().getDefaultSSLParameters().getCipherSuites()) + finalDefaultCiphers = Stream.of(SSLContext.getDefault().getDefaultSSLParameters().getCipherSuites()) .filter(defaultCiphers::contains) .sorted(String::compareTo) .collect(Collectors.toList()); + } + @Test + public void testDefaultSslParametersForHttp() { + final var httpSslParameters = SslParameters.loader(Settings.EMPTY).load(CertType.HTTP); assertThat(httpSslParameters.provider(), is(SslProvider.JDK)); - assertThat(transportSslParameters.provider(), is(SslProvider.JDK)); - assertThat(httpSslParameters.allowedProtocols(), is(List.of("TLSv1.3", "TLSv1.2"))); assertThat(httpSslParameters.allowedCiphers(), is(finalDefaultCiphers)); + assertThat(httpSslParameters.clientAuth(), is(ClientAuth.OPTIONAL)); + } + + @Test + public void testDefaultSslParametersForAux() { + final var auxSslParameters = SslParameters.loader(Settings.EMPTY).load(CertType.AUX); + assertThat(auxSslParameters.provider(), is(SslProvider.JDK)); + assertThat(auxSslParameters.allowedProtocols(), is(List.of("TLSv1.3", "TLSv1.2"))); + assertThat(auxSslParameters.allowedCiphers(), is(finalDefaultCiphers)); + assertThat(auxSslParameters.clientAuth(), is(ClientAuth.OPTIONAL)); + } + @Test + public void testDefaultSslParametersForTransport() { + final var transportSslParameters = SslParameters.loader(Settings.EMPTY).load(CertType.TRANSPORT); + assertThat(transportSslParameters.provider(), is(SslProvider.JDK)); assertThat(transportSslParameters.allowedProtocols(), is(List.of("TLSv1.3", "TLSv1.2"))); assertThat(transportSslParameters.allowedCiphers(), is(finalDefaultCiphers)); - - assertThat(httpSslParameters.clientAuth(), is(ClientAuth.OPTIONAL)); assertThat(transportSslParameters.clientAuth(), is(ClientAuth.REQUIRE)); } @Test - public void testCustomSSlParameters() { + public void testCustomSSlParametersForHttpAndTransport() { final var settings = Settings.builder() - .put(SECURITY_SSL_HTTP_CLIENTAUTH_MODE, ClientAuth.REQUIRE.name().toLowerCase(Locale.ROOT)) - .putList(SECURITY_SSL_HTTP_ENABLED_PROTOCOLS, List.of("TLSv1.2", "TLSv1")) - .putList(SECURITY_SSL_HTTP_ENABLED_CIPHERS, List.of("TLS_AES_256_GCM_SHA384")) - .putList(SECURITY_SSL_TRANSPORT_ENABLED_PROTOCOLS, List.of("TLSv1.3", "TLSv1.2")) - .putList(SECURITY_SSL_TRANSPORT_ENABLED_CIPHERS, List.of("TLS_AES_128_GCM_SHA256", "TLS_AES_256_GCM_SHA384")) - .build(); - final var httpSslParameters = SslParameters.loader(settings.getByPrefix(SSL_HTTP_PREFIX)).load(true); - final var transportSslParameters = SslParameters.loader(settings.getByPrefix(SSL_TRANSPORT_PREFIX)).load(false); + .put(SECURITY_SSL_HTTP_CLIENTAUTH_MODE, ClientAuth.REQUIRE.name().toLowerCase(Locale.ROOT)) + .putList(SECURITY_SSL_HTTP_ENABLED_PROTOCOLS, List.of("TLSv1.2", "TLSv1")) + .putList(SECURITY_SSL_HTTP_ENABLED_CIPHERS, List.of("TLS_AES_256_GCM_SHA384")) + .putList(SECURITY_SSL_TRANSPORT_ENABLED_PROTOCOLS, List.of("TLSv1.3", "TLSv1.2")) + .putList(SECURITY_SSL_TRANSPORT_ENABLED_CIPHERS, List.of("TLS_AES_128_GCM_SHA256", "TLS_AES_256_GCM_SHA384")) + .build(); + final var httpSslParameters = SslParameters.loader(settings.getByPrefix(SSL_HTTP_PREFIX)).load(CertType.HTTP); + final var transportSslParameters = SslParameters.loader(settings.getByPrefix(SSL_TRANSPORT_PREFIX)).load(CertType.TRANSPORT); assertThat(httpSslParameters.provider(), is(SslProvider.JDK)); - assertThat(transportSslParameters.provider(), is(SslProvider.JDK)); - assertThat(httpSslParameters.allowedProtocols(), is(List.of("TLSv1.2"))); assertThat(httpSslParameters.allowedCiphers(), is(List.of("TLS_AES_256_GCM_SHA384"))); + assertThat(httpSslParameters.clientAuth(), is(ClientAuth.REQUIRE)); + assertThat(transportSslParameters.provider(), is(SslProvider.JDK)); assertThat(transportSslParameters.allowedProtocols(), is(List.of("TLSv1.3", "TLSv1.2"))); assertThat(transportSslParameters.allowedCiphers(), is(List.of("TLS_AES_128_GCM_SHA256", "TLS_AES_256_GCM_SHA384"))); + assertThat(transportSslParameters.clientAuth(), is(ClientAuth.REQUIRE)); + } + @Test + public void testCustomSSlParametersForHttpAndAuxAndTransport() { + final var settings = Settings.builder() + .put(SECURITY_SSL_HTTP_CLIENTAUTH_MODE, ClientAuth.REQUIRE.name().toLowerCase(Locale.ROOT)) + .putList(SECURITY_SSL_HTTP_ENABLED_PROTOCOLS, List.of("TLSv1.2", "TLSv1")) + .putList(SECURITY_SSL_HTTP_ENABLED_CIPHERS, List.of("TLS_AES_256_GCM_SHA384")) + .put(SECURITY_SSL_AUX_CLIENTAUTH_MODE, ClientAuth.REQUIRE.name().toLowerCase(Locale.ROOT)) + .putList(SECURITY_SSL_AUX_ENABLED_PROTOCOLS, List.of("TLSv1.2", "TLSv1")) + .putList(SECURITY_SSL_AUX_ENABLED_CIPHERS, List.of("TLS_AES_256_GCM_SHA384")) + .putList(SECURITY_SSL_TRANSPORT_ENABLED_PROTOCOLS, List.of("TLSv1.3", "TLSv1.2")) + .putList(SECURITY_SSL_TRANSPORT_ENABLED_CIPHERS, List.of("TLS_AES_128_GCM_SHA256", "TLS_AES_256_GCM_SHA384")) + .build(); + + final var httpSslParameters = SslParameters.loader(settings.getByPrefix(SSL_HTTP_PREFIX)).load(CertType.HTTP); + final var auxSslParameters = SslParameters.loader(settings.getByPrefix(SSL_AUX_PREFIX)).load(CertType.AUX); + final var transportSslParameters = SslParameters.loader(settings.getByPrefix(SSL_TRANSPORT_PREFIX)).load(CertType.TRANSPORT); + + assertThat(httpSslParameters.provider(), is(SslProvider.JDK)); + assertThat(httpSslParameters.allowedProtocols(), is(List.of("TLSv1.2"))); + assertThat(httpSslParameters.allowedCiphers(), is(List.of("TLS_AES_256_GCM_SHA384"))); assertThat(httpSslParameters.clientAuth(), is(ClientAuth.REQUIRE)); + + assertThat(auxSslParameters.provider(), is(SslProvider.JDK)); + assertThat(auxSslParameters.allowedProtocols(), is(List.of("TLSv1.2"))); + assertThat(auxSslParameters.allowedCiphers(), is(List.of("TLS_AES_256_GCM_SHA384"))); + assertThat(auxSslParameters.clientAuth(), is(ClientAuth.REQUIRE)); + + assertThat(transportSslParameters.provider(), is(SslProvider.JDK)); + assertThat(transportSslParameters.allowedProtocols(), is(List.of("TLSv1.3", "TLSv1.2"))); + assertThat(transportSslParameters.allowedCiphers(), is(List.of("TLS_AES_128_GCM_SHA256", "TLS_AES_256_GCM_SHA384"))); assertThat(transportSslParameters.clientAuth(), is(ClientAuth.REQUIRE)); } - } diff --git a/src/test/java/org/opensearch/security/ssl/util/SSLConfigConstantsTest.java b/src/test/java/org/opensearch/security/ssl/util/SSLConfigConstantsTest.java index b51efeda03..43d7dccb01 100644 --- a/src/test/java/org/opensearch/security/ssl/util/SSLConfigConstantsTest.java +++ b/src/test/java/org/opensearch/security/ssl/util/SSLConfigConstantsTest.java @@ -15,41 +15,47 @@ import org.junit.Test; import org.opensearch.common.settings.Settings; +import org.opensearch.security.ssl.config.CertType; +import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_AUX_ENABLED_PROTOCOLS; +import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_AUX_ENABLE_OPENSSL_IF_AVAILABLE; import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_HTTP_ENABLED_PROTOCOLS; import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_TRANSPORT_ENABLED_PROTOCOLS; import static org.junit.Assert.assertArrayEquals; public class SSLConfigConstantsTest { + private static final String[] TLSV1_123 = new String[] { "TLSv1.3", "TLSv1.2", "TLSv1.1" }; + private static final String[] TLSV1_01 = new String[] { "TLSv1", "TLSv1.1" }; @Test public void testDefaultTLSProtocols() { - final var tlsDefaultProtocols = SSLConfigConstants.getSecureSSLProtocols(Settings.EMPTY, false); - assertArrayEquals(new String[] { "TLSv1.3", "TLSv1.2", "TLSv1.1" }, tlsDefaultProtocols); - } - - @Test - public void testDefaultSSLProtocols() { - final var sslDefaultProtocols = SSLConfigConstants.getSecureSSLProtocols(Settings.EMPTY, true); - assertArrayEquals(new String[] { "TLSv1.3", "TLSv1.2", "TLSv1.1" }, sslDefaultProtocols); + assertArrayEquals(TLSV1_123, SSLConfigConstants.getSecureSSLProtocols(Settings.EMPTY, CertType.HTTP)); + assertArrayEquals(TLSV1_123, SSLConfigConstants.getSecureSSLProtocols(Settings.EMPTY, CertType.AUX)); + assertArrayEquals(TLSV1_123, SSLConfigConstants.getSecureSSLProtocols(Settings.EMPTY, CertType.TRANSPORT)); } @Test public void testCustomTLSProtocols() { - final var tlsDefaultProtocols = SSLConfigConstants.getSecureSSLProtocols( - Settings.builder().putList(SECURITY_SSL_TRANSPORT_ENABLED_PROTOCOLS, List.of("TLSv1", "TLSv1.1")).build(), - false - ); - assertArrayEquals(new String[] { "TLSv1", "TLSv1.1" }, tlsDefaultProtocols); + assertArrayEquals(TLSV1_01, SSLConfigConstants.getSecureSSLProtocols( + Settings.builder().putList(SECURITY_SSL_HTTP_ENABLED_PROTOCOLS, TLSV1_01).build(), + CertType.HTTP + )); + assertArrayEquals(TLSV1_01, SSLConfigConstants.getSecureSSLProtocols( + Settings.builder().putList(SECURITY_SSL_AUX_ENABLED_PROTOCOLS, TLSV1_01).build(), + CertType.AUX + )); + assertArrayEquals(TLSV1_01, SSLConfigConstants.getSecureSSLProtocols( + Settings.builder().putList(SECURITY_SSL_TRANSPORT_ENABLED_PROTOCOLS, TLSV1_01).build(), + CertType.TRANSPORT + )); } @Test public void testCustomSSLProtocols() { final var sslDefaultProtocols = SSLConfigConstants.getSecureSSLProtocols( - Settings.builder().putList(SECURITY_SSL_HTTP_ENABLED_PROTOCOLS, List.of("TLSv1", "TLSv1.1")).build(), - true + Settings.builder().putList(SECURITY_SSL_HTTP_ENABLED_PROTOCOLS, TLSV1_01).build(), + CertType.HTTP ); - assertArrayEquals(new String[] { "TLSv1", "TLSv1.1" }, sslDefaultProtocols); + assertArrayEquals(TLSV1_01, sslDefaultProtocols); } - }