diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/client/VertxRedisClientFactory.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/client/VertxRedisClientFactory.java index e21e438e239984..91f5573a2a8ed4 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/client/VertxRedisClientFactory.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/client/VertxRedisClientFactory.java @@ -10,6 +10,7 @@ import java.net.URI; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import java.util.Set; import io.quarkus.arc.Arc; @@ -22,10 +23,14 @@ import io.quarkus.redis.runtime.client.config.RedisClientConfig; import io.quarkus.redis.runtime.client.config.TlsConfig; import io.quarkus.runtime.configuration.ConfigurationException; +import io.quarkus.tls.TlsConfiguration; +import io.quarkus.tls.TlsConfigurationRegistry; import io.smallrye.common.annotation.Identifier; import io.vertx.core.Vertx; +import io.vertx.core.buffer.Buffer; import io.vertx.core.net.NetClientOptions; import io.vertx.core.net.ProxyOptions; +import io.vertx.core.net.SSLOptions; import io.vertx.redis.client.Redis; import io.vertx.redis.client.RedisClientType; import io.vertx.redis.client.RedisOptions; @@ -113,32 +118,14 @@ private static NetClientOptions toNetClientOptions(RedisClientConfig config) { TlsConfig tls = config.tls(); NetClientOptions net = new NetClientOptions(); - tcp.alpn().ifPresent(net::setUseAlpn); - tcp.applicationLayerProtocols().ifPresent(net::setApplicationLayerProtocols); - tcp.connectionTimeout().ifPresent(d -> net.setConnectTimeout((int) d.toMillis())); - String verificationAlgorithm = tls.hostnameVerificationAlgorithm(); - if ("NONE".equalsIgnoreCase(verificationAlgorithm)) { - net.setHostnameVerificationAlgorithm(""); - } else { - net.setHostnameVerificationAlgorithm(verificationAlgorithm); - } + tcp.applicationLayerProtocols().ifPresent(net::setApplicationLayerProtocols); + tcp.connectionTimeout().ifPresent(d -> net.setConnectTimeout((int) d.toMillis())); tcp.idleTimeout().ifPresent(d -> net.setIdleTimeout((int) d.toSeconds())); - tcp.keepAlive().ifPresent(b -> net.setTcpKeepAlive(true)); tcp.noDelay().ifPresent(b -> net.setTcpNoDelay(true)); - net.setSsl(tls.enabled()).setTrustAll(tls.trustAll()); - - configurePemTrustOptions(net, tls.trustCertificatePem()); - configureJksTrustOptions(net, tls.trustCertificateJks()); - configurePfxTrustOptions(net, tls.trustCertificatePfx()); - - configurePemKeyCertOptions(net, tls.keyCertificatePem()); - configureJksKeyCertOptions(net, tls.keyCertificateJks()); - configurePfxKeyCertOptions(net, tls.keyCertificatePfx()); - net.setReconnectAttempts(config.reconnectAttempts()); net.setReconnectInterval(config.reconnectInterval().toMillis()); @@ -191,4 +178,75 @@ public static RedisHostsProvider findProvider(String name) { return providers.get(); } + private void configureTLS(String name, RedisClientConfig config, TlsConfigurationRegistry tlsRegistry, NetClientOptions net) { + TlsConfiguration configuration = null; + + // Check if we have a named TLS configuration or a default configuration: + if (config.tlsConfigurationName().isPresent()) { + Optional maybeConfiguration = tlsRegistry.get(config.tlsConfigurationName().get()); + if (!maybeConfiguration.isPresent()) { + throw new IllegalStateException("Unable to find the TLS configuration " + + config.tlsConfigurationName().get() + " for the Redis client " + name + "."); + } + configuration = maybeConfiguration.get(); + } else if (tlsRegistry.getDefault().isPresent() && tlsRegistry.getDefault().get().isTlsEnabled()) { + configuration = tlsRegistry.getDefault().get(); + } + + // Apply the configuration + if (configuration != null) { + // This part is often the same (or close) for every Vert.x client: + net.setSsl(true); + + if (configuration.getTrustStoreOptions() != null) { + net.setTrustOptions(configuration.getTrustStoreOptions()); + } + + // For mTLS: + if (configuration.getKeyStoreOptions() != null) { + net.setKeyCertOptions(configuration.getKeyStoreOptions()); + } + + if (configuration.isTrustAll()) { + net.setTrustAll(true); + } + if (configuration.getHostnameVerificationAlgorithm().isPresent()) { + net.setHostnameVerificationAlgorithm(configuration.getHostnameVerificationAlgorithm().get()); + } + + SSLOptions sslOptions = configuration.getSSLOptions(); + if (sslOptions != null) { + net.setSslHandshakeTimeout(sslOptions.getSslHandshakeTimeout()); + net.setSslHandshakeTimeoutUnit(sslOptions.getSslHandshakeTimeoutUnit()); + for (String suite : sslOptions.getEnabledCipherSuites()) { + net.addEnabledCipherSuite(suite); + } + for (Buffer buffer : sslOptions.getCrlValues()) { + net.addCrlValue(buffer); + } + net.setEnabledSecureTransportProtocols(sslOptions.getEnabledSecureTransportProtocols()); + net.setUseAlpn(sslOptions.isUseAlpn()); + } + + } else { + config.tcp().alpn().ifPresent(net::setUseAlpn); + + String verificationAlgorithm = config.tls().hostnameVerificationAlgorithm(); + if ("NONE".equalsIgnoreCase(verificationAlgorithm)) { + net.setHostnameVerificationAlgorithm(""); + } else { + net.setHostnameVerificationAlgorithm(verificationAlgorithm); + } + net.setSsl(config.tls().enabled()).setTrustAll(config.tls().trustAll()); + + configurePemTrustOptions(net, config.tls().trustCertificatePem()); + configureJksTrustOptions(net, config.tls().trustCertificateJks()); + configurePfxTrustOptions(net, config.tls().trustCertificatePfx()); + + configurePemKeyCertOptions(net, config.tls().keyCertificatePem()); + configureJksKeyCertOptions(net, config.tls().keyCertificateJks()); + configurePfxKeyCertOptions(net, config.tls().keyCertificatePfx()); + } + } + } diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/client/config/RedisClientConfig.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/client/config/RedisClientConfig.java index f2413f87f3bdb6..976687ed874c5e 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/client/config/RedisClientConfig.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/client/config/RedisClientConfig.java @@ -8,6 +8,7 @@ import io.quarkus.runtime.annotations.ConfigDocDefault; import io.quarkus.runtime.annotations.ConfigDocSection; import io.quarkus.runtime.annotations.ConfigGroup; +import io.quarkus.runtime.annotations.ConfigItem; import io.smallrye.config.WithDefault; import io.vertx.redis.client.ProtocolVersion; import io.vertx.redis.client.RedisClientType; @@ -168,6 +169,20 @@ public interface RedisClientConfig { @ConfigDocSection TlsConfig tls(); + /** + * The name of the TLS configuration to use. + *

+ * If not set and the default TLS configuration is configured ({@code quarkus.tls.*}) then that will be used. + * If a name is configured, it uses the configuration from {@code quarkus.tls..*} + * If a name is configured, but no TLS configuration is found with that name then an error will be thrown. + *

+ * If no TLS configuration is set, and {@code quarkus.tls.*} is not configured, then, + * `quarkus.redis.$client-name.tls` will be used. + *

+ * Important: This is only supported when using the Quarkus (Vert.x-based) gRPC client. + */ + Optional tlsConfigurationName(); + default String toDebugString() { return "RedisClientConfig{" + "hosts=" + hosts() +