From b2b5573a61b7ae6f5b9cb2109ffc5ef82632c49c Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Mon, 11 Sep 2023 16:57:28 +0300 Subject: [PATCH 1/7] added ssl support for redis --- .../src/main/resources/thingsboard.yml | 8 ++++ .../cache/TBRedisCacheConfiguration.java | 41 +++++++++++++++++++ .../cache/TBRedisClusterConfiguration.java | 23 +++++++++-- .../cache/TBRedisSentinelConfiguration.java | 24 ++++++++--- .../cache/TBRedisStandaloneConfiguration.java | 34 ++++++++------- .../TbRedisSslCredentialsConfiguration.java | 36 ++++++++++++++++ 6 files changed, 142 insertions(+), 24 deletions(-) create mode 100644 common/cache/src/main/java/org/thingsboard/server/cache/TbRedisSslCredentialsConfiguration.java diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 3e1aa5a8e6..432caa4c27 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -548,6 +548,14 @@ redis: db: "${REDIS_DB:0}" # db password password: "${REDIS_PASSWORD:}" + # ssl config + ssl: + enabled: "${TB_REDIS_SSL_ENABLED:true}" + truststoreLocation: "${TB_REDIS_SSL_TRUSTSTORE_LOCATION:}" + truststorePassword: "${TB_REDIS_SSL_TRUSTSTORE_PASSWORD:}" + # client authentication could be optional and depends on redis server configuration + keystoreLocation: "${TB_REDIS_SSL_KEYSTORE_LOCATION:}" + keystorePassword: "${TB_REDIS_SSL_KEYSTORE_PASSWORD:}" # pool config pool_config: maxTotal: "${REDIS_POOL_CONFIG_MAX_TOTAL:128}" diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/TBRedisCacheConfiguration.java b/common/cache/src/main/java/org/thingsboard/server/cache/TBRedisCacheConfiguration.java index 36f3dddc3d..dc0b301ffc 100644 --- a/common/cache/src/main/java/org/thingsboard/server/cache/TBRedisCacheConfiguration.java +++ b/common/cache/src/main/java/org/thingsboard/server/cache/TBRedisCacheConfiguration.java @@ -16,6 +16,8 @@ package org.thingsboard.server.cache; import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.cache.CacheManager; @@ -35,6 +37,12 @@ import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.id.EntityId; import redis.clients.jedis.JedisPoolConfig; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManagerFactory; +import java.io.FileInputStream; +import java.security.KeyStore; import java.time.Duration; import java.util.ArrayList; import java.util.Collections; @@ -44,6 +52,7 @@ import java.util.List; @ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "redis") @EnableCaching @Data +@Slf4j public abstract class TBRedisCacheConfiguration { private static final String COMMA = ","; @@ -90,6 +99,9 @@ public abstract class TBRedisCacheConfiguration { return loadFactory(); } + @Autowired + private TbRedisSslCredentialsConfiguration redisSslCredentials; + protected abstract JedisConnectionFactory loadFactory(); /** @@ -149,4 +161,33 @@ public abstract class TBRedisCacheConfiguration { } return result; } + + protected SSLSocketFactory createSslSocketFactory() { + try { + KeyStore trustStore = KeyStore.getInstance("jks"); + trustStore.load(new FileInputStream(redisSslCredentials.getTruststoreLocation()), redisSslCredentials.getTruststorePassword().toCharArray()); + + TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("X509"); + trustManagerFactory.init(trustStore); + + SSLContext sslContext = SSLContext.getInstance("TLS"); + + // client authentication is optional + if (redisSslCredentials.getKeystoreLocation() != null && redisSslCredentials.getKeystorePassword() != null) { + KeyStore keyStore = KeyStore.getInstance("pkcs12"); + keyStore.load(new FileInputStream(redisSslCredentials.getKeystoreLocation()), redisSslCredentials.getKeystorePassword().toCharArray()); + + KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("PKIX"); + keyManagerFactory.init(keyStore, redisSslCredentials.getKeystorePassword().toCharArray()); + + sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null); + } else { + sslContext.init(null, trustManagerFactory.getTrustManagers(), null); + } + return sslContext.getSocketFactory(); + + } catch (Exception e) { + throw new RuntimeException(e); + } + } } diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/TBRedisClusterConfiguration.java b/common/cache/src/main/java/org/thingsboard/server/cache/TBRedisClusterConfiguration.java index 0a378103b0..63517a98ac 100644 --- a/common/cache/src/main/java/org/thingsboard/server/cache/TBRedisClusterConfiguration.java +++ b/common/cache/src/main/java/org/thingsboard/server/cache/TBRedisClusterConfiguration.java @@ -20,6 +20,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisClusterConfiguration; +import org.springframework.data.redis.connection.jedis.JedisClientConfiguration; import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; @Configuration @@ -39,15 +40,29 @@ public class TBRedisClusterConfiguration extends TBRedisCacheConfiguration { @Value("${redis.password:}") private String password; + @Value("${redis.ssl.enabled:}") + private boolean useSsl; + public JedisConnectionFactory loadFactory() { RedisClusterConfiguration clusterConfiguration = new RedisClusterConfiguration(); clusterConfiguration.setClusterNodes(getNodes(clusterNodes)); clusterConfiguration.setMaxRedirects(maxRedirects); clusterConfiguration.setPassword(password); - if (useDefaultPoolConfig) { - return new JedisConnectionFactory(clusterConfiguration); - } else { - return new JedisConnectionFactory(clusterConfiguration, buildPoolConfig()); + return new JedisConnectionFactory(clusterConfiguration, buildClientConfig()); + } + + private JedisClientConfiguration buildClientConfig() { + JedisClientConfiguration.JedisClientConfigurationBuilder jedisClientConfigurationBuilder = JedisClientConfiguration.builder(); + if (!useDefaultPoolConfig) { + jedisClientConfigurationBuilder + .usePooling() + .poolConfig(buildPoolConfig()); + } + if (useSsl) { + jedisClientConfigurationBuilder + .useSsl() + .sslSocketFactory(createSslSocketFactory()); } + return jedisClientConfigurationBuilder.build(); } } diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/TBRedisSentinelConfiguration.java b/common/cache/src/main/java/org/thingsboard/server/cache/TBRedisSentinelConfiguration.java index 78cb445d82..dbfb3bce73 100644 --- a/common/cache/src/main/java/org/thingsboard/server/cache/TBRedisSentinelConfiguration.java +++ b/common/cache/src/main/java/org/thingsboard/server/cache/TBRedisSentinelConfiguration.java @@ -20,6 +20,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisSentinelConfiguration; +import org.springframework.data.redis.connection.jedis.JedisClientConfiguration; import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; @Configuration @@ -42,6 +43,9 @@ public class TBRedisSentinelConfiguration extends TBRedisCacheConfiguration { @Value("${redis.db:}") private Integer database; + @Value("${redis.ssl.enabled:}") + private boolean useSsl; + @Value("${redis.password:}") private String password; @@ -52,11 +56,21 @@ public class TBRedisSentinelConfiguration extends TBRedisCacheConfiguration { redisSentinelConfiguration.setSentinelPassword(sentinelPassword); redisSentinelConfiguration.setPassword(password); redisSentinelConfiguration.setDatabase(database); - if (useDefaultPoolConfig) { - return new JedisConnectionFactory(redisSentinelConfiguration); - } else { - return new JedisConnectionFactory(redisSentinelConfiguration, buildPoolConfig()); - } + return new JedisConnectionFactory(redisSentinelConfiguration, buildClientConfig()); } + private JedisClientConfiguration buildClientConfig() { + JedisClientConfiguration.JedisClientConfigurationBuilder jedisClientConfigurationBuilder = JedisClientConfiguration.builder(); + if (!useDefaultPoolConfig) { + jedisClientConfigurationBuilder + .usePooling() + .poolConfig(buildPoolConfig()); + } + if (useSsl) { + jedisClientConfigurationBuilder + .useSsl() + .sslSocketFactory(createSslSocketFactory()); + } + return jedisClientConfigurationBuilder.build(); + } } diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/TBRedisStandaloneConfiguration.java b/common/cache/src/main/java/org/thingsboard/server/cache/TBRedisStandaloneConfiguration.java index aae6ecd2a3..55065e443f 100644 --- a/common/cache/src/main/java/org/thingsboard/server/cache/TBRedisStandaloneConfiguration.java +++ b/common/cache/src/main/java/org/thingsboard/server/cache/TBRedisStandaloneConfiguration.java @@ -57,32 +57,36 @@ public class TBRedisStandaloneConfiguration extends TBRedisCacheConfiguration { @Value("${redis.password:}") private String password; + @Value("${redis.ssl.enabled:}") + private boolean useSsl; + public JedisConnectionFactory loadFactory() { RedisStandaloneConfiguration standaloneConfiguration = new RedisStandaloneConfiguration(); standaloneConfiguration.setHostName(host); standaloneConfiguration.setPort(port); standaloneConfiguration.setDatabase(db); standaloneConfiguration.setPassword(password); - if (useDefaultClientConfig) { - return new JedisConnectionFactory(standaloneConfiguration); - } else { - return new JedisConnectionFactory(standaloneConfiguration, buildClientConfig()); - } + return new JedisConnectionFactory(standaloneConfiguration, buildClientConfig()); } private JedisClientConfiguration buildClientConfig() { - if (usePoolConfig) { - return JedisClientConfiguration.builder() - .clientName(clientName) - .connectTimeout(Duration.ofMillis(connectTimeout)) - .readTimeout(Duration.ofMillis(readTimeout)) - .usePooling().poolConfig(buildPoolConfig()) - .build(); - } else { - return JedisClientConfiguration.builder() + JedisClientConfiguration.JedisClientConfigurationBuilder jedisClientConfigurationBuilder = JedisClientConfiguration.builder(); + if (!useDefaultClientConfig) { + jedisClientConfigurationBuilder .clientName(clientName) .connectTimeout(Duration.ofMillis(connectTimeout)) - .readTimeout(Duration.ofMillis(readTimeout)).build(); + .readTimeout(Duration.ofMillis(readTimeout)); + } + if (useSsl) { + jedisClientConfigurationBuilder + .useSsl() + .sslSocketFactory(createSslSocketFactory()); + } + if (usePoolConfig) { + jedisClientConfigurationBuilder + .usePooling() + .poolConfig(buildPoolConfig()); } + return jedisClientConfigurationBuilder.build(); } } \ No newline at end of file diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/TbRedisSslCredentialsConfiguration.java b/common/cache/src/main/java/org/thingsboard/server/cache/TbRedisSslCredentialsConfiguration.java new file mode 100644 index 0000000000..fa0c09043d --- /dev/null +++ b/common/cache/src/main/java/org/thingsboard/server/cache/TbRedisSslCredentialsConfiguration.java @@ -0,0 +1,36 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.cache; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ConfigurationProperties(prefix = "redis.ssl") +@Data +public class TbRedisSslCredentialsConfiguration { + + private boolean enabled; + + private String truststoreLocation; + + private String truststorePassword; + + private String keystoreLocation; + + private String keystorePassword; +} From b92f5438330daafab999bd3e8adc85f741d756c3 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Tue, 19 Sep 2023 12:03:44 +0300 Subject: [PATCH 2/7] updated default value for redis ssl config --- application/src/main/resources/thingsboard.yml | 2 +- .../thingsboard/server/cache/TBRedisClusterConfiguration.java | 2 +- .../thingsboard/server/cache/TBRedisSentinelConfiguration.java | 2 +- .../server/cache/TBRedisStandaloneConfiguration.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 432caa4c27..afda163549 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -550,7 +550,7 @@ redis: password: "${REDIS_PASSWORD:}" # ssl config ssl: - enabled: "${TB_REDIS_SSL_ENABLED:true}" + enabled: "${TB_REDIS_SSL_ENABLED:false}" truststoreLocation: "${TB_REDIS_SSL_TRUSTSTORE_LOCATION:}" truststorePassword: "${TB_REDIS_SSL_TRUSTSTORE_PASSWORD:}" # client authentication could be optional and depends on redis server configuration diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/TBRedisClusterConfiguration.java b/common/cache/src/main/java/org/thingsboard/server/cache/TBRedisClusterConfiguration.java index 63517a98ac..14ffbedced 100644 --- a/common/cache/src/main/java/org/thingsboard/server/cache/TBRedisClusterConfiguration.java +++ b/common/cache/src/main/java/org/thingsboard/server/cache/TBRedisClusterConfiguration.java @@ -40,7 +40,7 @@ public class TBRedisClusterConfiguration extends TBRedisCacheConfiguration { @Value("${redis.password:}") private String password; - @Value("${redis.ssl.enabled:}") + @Value("${redis.ssl.enabled:false}") private boolean useSsl; public JedisConnectionFactory loadFactory() { diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/TBRedisSentinelConfiguration.java b/common/cache/src/main/java/org/thingsboard/server/cache/TBRedisSentinelConfiguration.java index dbfb3bce73..18aa315b1c 100644 --- a/common/cache/src/main/java/org/thingsboard/server/cache/TBRedisSentinelConfiguration.java +++ b/common/cache/src/main/java/org/thingsboard/server/cache/TBRedisSentinelConfiguration.java @@ -43,7 +43,7 @@ public class TBRedisSentinelConfiguration extends TBRedisCacheConfiguration { @Value("${redis.db:}") private Integer database; - @Value("${redis.ssl.enabled:}") + @Value("${redis.ssl.enabled:false}") private boolean useSsl; @Value("${redis.password:}") diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/TBRedisStandaloneConfiguration.java b/common/cache/src/main/java/org/thingsboard/server/cache/TBRedisStandaloneConfiguration.java index 55065e443f..b3bfda59cb 100644 --- a/common/cache/src/main/java/org/thingsboard/server/cache/TBRedisStandaloneConfiguration.java +++ b/common/cache/src/main/java/org/thingsboard/server/cache/TBRedisStandaloneConfiguration.java @@ -57,7 +57,7 @@ public class TBRedisStandaloneConfiguration extends TBRedisCacheConfiguration { @Value("${redis.password:}") private String password; - @Value("${redis.ssl.enabled:}") + @Value("${redis.ssl.enabled:false}") private boolean useSsl; public JedisConnectionFactory loadFactory() { From 9af96ad5bef483f3b129b1f2b8a8dd96169e5140 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Thu, 18 Jan 2024 14:39:14 +0200 Subject: [PATCH 3/7] resolved conflicts after merge --- .../src/main/resources/thingsboard.yml | 34 +++++- ...va => RedisKeystoreCredentialsConfig.java} | 14 +-- .../cache/RedisPemCredentialsConfig.java | 28 +++++ .../RedisSslCredentialsConfiguration.java | 33 ++++++ .../cache/TBRedisCacheConfiguration.java | 103 +++++++++++++++--- .../org/thingsboard/common/util/SslUtil.java | 71 ++++++++---- .../src/main/resources/tb-coap-transport.yml | 29 +++++ .../src/main/resources/tb-http-transport.yml | 29 +++++ .../src/main/resources/tb-lwm2m-transport.yml | 29 +++++ .../src/main/resources/tb-mqtt-transport.yml | 29 +++++ .../src/main/resources/tb-snmp-transport.yml | 29 +++++ 11 files changed, 376 insertions(+), 52 deletions(-) rename common/cache/src/main/java/org/thingsboard/server/cache/{TbRedisSslCredentialsConfiguration.java => RedisKeystoreCredentialsConfig.java} (70%) create mode 100644 common/cache/src/main/java/org/thingsboard/server/cache/RedisPemCredentialsConfig.java create mode 100644 common/cache/src/main/java/org/thingsboard/server/cache/RedisSslCredentialsConfiguration.java diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 8387f1d424..e2f1a80d42 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -641,12 +641,34 @@ redis: password: "${REDIS_PASSWORD:}" # ssl config ssl: - enabled: "${TB_REDIS_SSL_ENABLED:false}" - truststoreLocation: "${TB_REDIS_SSL_TRUSTSTORE_LOCATION:}" - truststorePassword: "${TB_REDIS_SSL_TRUSTSTORE_PASSWORD:}" - # client authentication could be optional and depends on redis server configuration - keystoreLocation: "${TB_REDIS_SSL_KEYSTORE_LOCATION:}" - keystorePassword: "${TB_REDIS_SSL_KEYSTORE_PASSWORD:}" + # Enable/disable secure connection + enabled: "${REDIS_SSL_ENABLED:false}" + # Server SSL credentials + credentials: + # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore) + type: "${TB_REDIS_SSL_CREDENTIALS_TYPE:pem}" + # PEM server credentials + pem: + # Path redis server (CA) certificate + cert_file: "${TB_REDIS_SSL_PEM_CERT:}" + # Path to user certificate file (optional) + user_cert_file: "${TB_REDIS_SSL_PEM_KEY:}" + # Path to user private key file (optional) + user_key_file: "${TB_REDIS_SSL_PEM_KEY_PASSWORD:}" + # Keystore server credentials + keystore: + # Type of the trust store (JKS or PKCS12) + truststore_type: "${TB_REDIS_SSL_KEY_STORE_TYPE:JKS}" + # The location of the trust store file + truststore_location: "${TB_REDIS_SSL_TRUSTSTORE_LOCATION:}" + # The password of trust store file if specified + truststore_password: "${TB_REDIS_SSL_TRUSTSTORE_PASSWORD:}" + # Type of the key store (JKS or PKCS12) + keystore_type: "${TB_REDIS_SSL_KEY_STORE_TYPE:JKS}" + # The location of the key store file. This is optional for the client and can be used for two-way authentication for the client + keystore_location: "${TB_REDIS_SSL_KEYSTORE_LOCATION:}" + # The store password for the key store file. This is optional for the client and only needed if ‘ssl.keystore.location’ is configured. Key store password is not supported for PEM format + keystore_password: "${TB_REDIS_SSL_KEYSTORE_PASSWORD:}" # pool config pool_config: # Maximum number of connections that can be allocated by the connection pool diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/TbRedisSslCredentialsConfiguration.java b/common/cache/src/main/java/org/thingsboard/server/cache/RedisKeystoreCredentialsConfig.java similarity index 70% rename from common/cache/src/main/java/org/thingsboard/server/cache/TbRedisSslCredentialsConfiguration.java rename to common/cache/src/main/java/org/thingsboard/server/cache/RedisKeystoreCredentialsConfig.java index fa0c09043d..1d2a08e6d4 100644 --- a/common/cache/src/main/java/org/thingsboard/server/cache/TbRedisSslCredentialsConfiguration.java +++ b/common/cache/src/main/java/org/thingsboard/server/cache/RedisKeystoreCredentialsConfig.java @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2023 The Thingsboard Authors + * Copyright © 2016-2024 The Thingsboard Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,20 +16,20 @@ package org.thingsboard.server.cache; import lombok.Data; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Configuration; -@Configuration -@ConfigurationProperties(prefix = "redis.ssl") @Data -public class TbRedisSslCredentialsConfiguration { +public class RedisKeystoreCredentialsConfig { - private boolean enabled; + private String type; + + private String truststoreType; private String truststoreLocation; private String truststorePassword; + private String keystoreType; + private String keystoreLocation; private String keystorePassword; diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/RedisPemCredentialsConfig.java b/common/cache/src/main/java/org/thingsboard/server/cache/RedisPemCredentialsConfig.java new file mode 100644 index 0000000000..50e2c71966 --- /dev/null +++ b/common/cache/src/main/java/org/thingsboard/server/cache/RedisPemCredentialsConfig.java @@ -0,0 +1,28 @@ +/** + * Copyright © 2016-2024 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.cache; + +import lombok.Data; + +@Data +public class RedisPemCredentialsConfig { + + private String certFile; + + private String userCertFile; + + private String userKeyFile; +} diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/RedisSslCredentialsConfiguration.java b/common/cache/src/main/java/org/thingsboard/server/cache/RedisSslCredentialsConfiguration.java new file mode 100644 index 0000000000..6bd46baf1b --- /dev/null +++ b/common/cache/src/main/java/org/thingsboard/server/cache/RedisSslCredentialsConfiguration.java @@ -0,0 +1,33 @@ +/** + * Copyright © 2016-2024 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.cache; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ConfigurationProperties(prefix = "redis.ssl.credentials") +@Data +public class RedisSslCredentialsConfiguration { + + private String type; + + private RedisKeystoreCredentialsConfig keystore; + + private RedisPemCredentialsConfig pem; + +} diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/TBRedisCacheConfiguration.java b/common/cache/src/main/java/org/thingsboard/server/cache/TBRedisCacheConfiguration.java index b313e8c6f5..d8805044f3 100644 --- a/common/cache/src/main/java/org/thingsboard/server/cache/TBRedisCacheConfiguration.java +++ b/common/cache/src/main/java/org/thingsboard/server/cache/TBRedisCacheConfiguration.java @@ -33,6 +33,7 @@ import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.format.support.DefaultFormattingConversionService; import org.springframework.util.Assert; +import org.thingsboard.common.util.SslUtil; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.id.EntityId; import redis.clients.jedis.JedisPoolConfig; @@ -43,6 +44,11 @@ import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManagerFactory; import java.io.FileInputStream; import java.security.KeyStore; +import java.security.PrivateKey; +import java.security.cert.CertPath; +import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; import java.time.Duration; import java.util.ArrayList; import java.util.Collections; @@ -100,7 +106,7 @@ public abstract class TBRedisCacheConfiguration { } @Autowired - private TbRedisSslCredentialsConfiguration redisSslCredentials; + private RedisSslCredentialsConfiguration redisSslCredentials; protected abstract JedisConnectionFactory loadFactory(); @@ -164,30 +170,93 @@ public abstract class TBRedisCacheConfiguration { protected SSLSocketFactory createSslSocketFactory() { try { - KeyStore trustStore = KeyStore.getInstance("jks"); - trustStore.load(new FileInputStream(redisSslCredentials.getTruststoreLocation()), redisSslCredentials.getTruststorePassword().toCharArray()); + SSLContext sslContext = SSLContext.getInstance("TLS"); + KeyManagerFactory keyManagerFactory = createAndInitKeyManagerFactory(); + TrustManagerFactory trustManagerFactory = createAndInitTrustManagerFactory(); + sslContext.init(keyManagerFactory == null ? null : keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null); + return sslContext.getSocketFactory(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private TrustManagerFactory createAndInitTrustManagerFactory() throws Exception { + String type = redisSslCredentials.getType(); + if ("pem".equals(type)) { + RedisPemCredentialsConfig pemCredentials = redisSslCredentials.getPem(); + List caCerts = SslUtil.readCertFileByPath(pemCredentials.getCertFile()); + + KeyStore caKeyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + caKeyStore.load(null, null); + for (X509Certificate caCert : caCerts) { + caKeyStore.setCertificateEntry("redis-caCert-cert-" + caCert.getSubjectX500Principal().getName(), caCert); + } + + TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("X509"); + trustManagerFactory.init(caKeyStore); + return trustManagerFactory; + } else if ("keystore".equals(type)) { + RedisKeystoreCredentialsConfig keystore = redisSslCredentials.getKeystore(); + KeyStore trustStore = KeyStore.getInstance(keystore.getKeystoreType()); + trustStore.load(new FileInputStream(keystore.getTruststoreLocation()), keystore.getTruststorePassword().toCharArray()); TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("X509"); trustManagerFactory.init(trustStore); + return trustManagerFactory; + } else { + throw new RuntimeException(type + ": Invalid SSL credentials configuration. None of the PEM or KEYSTORE configurations can be used!"); + } + } - SSLContext sslContext = SSLContext.getInstance("TLS"); + private KeyManagerFactory createAndInitKeyManagerFactory() throws Exception { + String type = redisSslCredentials.getType(); + if ("pem".equals(type)) { + RedisPemCredentialsConfig pemCredentials = redisSslCredentials.getPem(); + return getKeyManagerFactory(pemCredentials); + } else if ("keystore".equals(type)) { + RedisKeystoreCredentialsConfig keystore = redisSslCredentials.getKeystore(); + return getKeyManagerFactory(keystore); + } else { + throw new RuntimeException(type + ": Invalid SSL credentials configuration. None of the PEM or KEYSTORE configurations can be used!"); + } + } - // client authentication is optional - if (redisSslCredentials.getKeystoreLocation() != null && redisSslCredentials.getKeystorePassword() != null) { - KeyStore keyStore = KeyStore.getInstance("pkcs12"); - keyStore.load(new FileInputStream(redisSslCredentials.getKeystoreLocation()), redisSslCredentials.getKeystorePassword().toCharArray()); + private KeyManagerFactory getKeyManagerFactory(RedisPemCredentialsConfig pemCredentials) throws Exception { + if (pemCredentials.getUserCertFile().isBlank() || pemCredentials.getUserKeyFile().isBlank()) { + return null; + } + List certificates = SslUtil.readCertFileByPath(pemCredentials.getCertFile()); + PrivateKey privateKey = SslUtil.readPrivateKeyByFilePath(pemCredentials.getUserKeyFile(), null); - KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("PKIX"); - keyManagerFactory.init(keyStore, redisSslCredentials.getKeystorePassword().toCharArray()); + KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + keyStore.load(null); + List unique = certificates.stream().distinct().toList(); + for (X509Certificate cert : unique) { + keyStore.setCertificateEntry("redis-cert" + cert.getSubjectX500Principal().getName(), cert); + } - sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null); - } else { - sslContext.init(null, trustManagerFactory.getTrustManagers(), null); - } - return sslContext.getSocketFactory(); + if (privateKey != null) { + CertificateFactory factory = CertificateFactory.getInstance("X.509"); + CertPath certPath = factory.generateCertPath(certificates); + List path = certPath.getCertificates(); + Certificate[] x509Certificates = path.toArray(new Certificate[0]); + keyStore.setKeyEntry("redis-private-key", privateKey, null, x509Certificates); + } - } catch (Exception e) { - throw new RuntimeException(e); + KeyManagerFactory kmf = KeyManagerFactory.getInstance("PKIX"); + kmf.init(keyStore, null); + return kmf; + } + + private KeyManagerFactory getKeyManagerFactory(RedisKeystoreCredentialsConfig keystore) throws Exception { + if (keystore.getKeystoreLocation().isBlank() || keystore.getKeystoreLocation().isBlank()) { + return null; } + KeyStore keyStore = KeyStore.getInstance(keystore.getKeystoreType()); + keyStore.load(new FileInputStream(keystore.getKeystoreLocation()), keystore.getKeystorePassword().toCharArray()); + + KeyManagerFactory kmf = KeyManagerFactory.getInstance("PKIX"); + kmf.init(keyStore, keystore.getKeystorePassword().toCharArray()); + return kmf; } } diff --git a/common/util/src/main/java/org/thingsboard/common/util/SslUtil.java b/common/util/src/main/java/org/thingsboard/common/util/SslUtil.java index d58f203956..e520e946ec 100644 --- a/common/util/src/main/java/org/thingsboard/common/util/SslUtil.java +++ b/common/util/src/main/java/org/thingsboard/common/util/SslUtil.java @@ -29,12 +29,17 @@ import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder; import org.bouncycastle.operator.InputDecryptorProvider; import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo; +import org.bouncycastle.pkcs.PKCSException; import org.bouncycastle.pkcs.jcajce.JcePKCSPBEInputDecryptorProviderBuilder; import org.thingsboard.server.common.data.StringUtils; +import java.io.FileReader; +import java.io.IOException; +import java.io.Reader; import java.io.StringReader; import java.security.PrivateKey; import java.security.Security; +import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.List; @@ -57,9 +62,18 @@ public class SslUtil { @SneakyThrows public static List readCertFile(String fileContent) { + return readCertFile(new StringReader(fileContent)); + } + + @SneakyThrows + public static List readCertFileByPath(String filePath) { + return readCertFile( new FileReader(filePath)); + } + + private static List readCertFile(Reader reader) throws IOException, CertificateException { List certificates = new ArrayList<>(); JcaX509CertificateConverter certConverter = new JcaX509CertificateConverter(); - try (PEMParser pemParser = new PEMParser(new StringReader(fileContent))) { + try (PEMParser pemParser = new PEMParser(reader)) { Object object; while ((object = pemParser.readObject()) != null) { if (object instanceof X509CertificateHolder) { @@ -73,33 +87,46 @@ public class SslUtil { @SneakyThrows public static PrivateKey readPrivateKey(String fileContent, String passStr) { - char[] password = StringUtils.isEmpty(passStr) ? EMPTY_PASS : passStr.toCharArray(); + if (StringUtils.isNotEmpty(fileContent)) { + StringReader reader = new StringReader(fileContent); + return readPrivateKey(reader, passStr); + } + return null; + } + @SneakyThrows + public static PrivateKey readPrivateKeyByFilePath(String filePath, String passStr) { + if (StringUtils.isNotEmpty(filePath)) { + FileReader fileReader = new FileReader(filePath); + return readPrivateKey(fileReader, passStr); + } + return null; + } + + private static PrivateKey readPrivateKey(Reader reader, String passStr) throws IOException, PKCSException { + char[] password = StringUtils.isEmpty(passStr) ? EMPTY_PASS : passStr.toCharArray(); PrivateKey privateKey = null; JcaPEMKeyConverter keyConverter = new JcaPEMKeyConverter(); - if (StringUtils.isNotEmpty(fileContent)) { - try (PEMParser pemParser = new PEMParser(new StringReader(fileContent))) { - Object object; - while ((object = pemParser.readObject()) != null) { - if (object instanceof PEMEncryptedKeyPair) { - PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder().build(password); - privateKey = keyConverter.getKeyPair(((PEMEncryptedKeyPair) object).decryptKeyPair(decProv)).getPrivate(); - break; - } else if (object instanceof PKCS8EncryptedPrivateKeyInfo) { - InputDecryptorProvider decProv = - new JcePKCSPBEInputDecryptorProviderBuilder().setProvider(DEFAULT_PROVIDER).build(password); - privateKey = keyConverter.getPrivateKey(((PKCS8EncryptedPrivateKeyInfo) object).decryptPrivateKeyInfo(decProv)); - break; - } else if (object instanceof PEMKeyPair) { - privateKey = keyConverter.getKeyPair((PEMKeyPair) object).getPrivate(); - break; - } else if (object instanceof PrivateKeyInfo) { - privateKey = keyConverter.getPrivateKey((PrivateKeyInfo) object); - } + try (PEMParser pemParser = new PEMParser(reader)) { + Object object; + while ((object = pemParser.readObject()) != null) { + if (object instanceof PEMEncryptedKeyPair) { + PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder().build(password); + privateKey = keyConverter.getKeyPair(((PEMEncryptedKeyPair) object).decryptKeyPair(decProv)).getPrivate(); + break; + } else if (object instanceof PKCS8EncryptedPrivateKeyInfo) { + InputDecryptorProvider decProv = + new JcePKCSPBEInputDecryptorProviderBuilder().setProvider(DEFAULT_PROVIDER).build(password); + privateKey = keyConverter.getPrivateKey(((PKCS8EncryptedPrivateKeyInfo) object).decryptPrivateKeyInfo(decProv)); + break; + } else if (object instanceof PEMKeyPair) { + privateKey = keyConverter.getKeyPair((PEMKeyPair) object).getPrivate(); + break; + } else if (object instanceof PrivateKeyInfo) { + privateKey = keyConverter.getPrivateKey((PrivateKeyInfo) object); } } } return privateKey; } - } diff --git a/transport/coap/src/main/resources/tb-coap-transport.yml b/transport/coap/src/main/resources/tb-coap-transport.yml index ff4c0ea534..87e3cf870d 100644 --- a/transport/coap/src/main/resources/tb-coap-transport.yml +++ b/transport/coap/src/main/resources/tb-coap-transport.yml @@ -94,6 +94,35 @@ redis: db: "${REDIS_DB:0}" # db password password: "${REDIS_PASSWORD:}" + ssl: + # Enable/disable secure connection + enabled: "${REDIS_SSL_ENABLED:false}" + # Server SSL credentials + credentials: + # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore) + type: "${TB_REDIS_SSL_CREDENTIALS_TYPE:pem}" + # PEM server credentials + pem: + # Path redis server (CA) certificate + cert_file: "${TB_REDIS_SSL_PEM_CERT:}" + # Path to user certificate file + user_cert_file: "${TB_REDIS_SSL_PEM_KEY:}" + # Path to user private key file + user_key_file: "${TB_REDIS_SSL_PEM_KEY_PASSWORD:}" + # Keystore server credentials + keystore: + # Type of the trust store (JKS or PKCS12) + truststore_type: "${TB_REDIS_SSL_KEY_STORE_TYPE:JKS}" + # The location of the trust store file + truststore_location: "${TB_REDIS_SSL_TRUSTSTORE_LOCATION:}" + # The password of trust store file if specified + truststore_password: "${TB_REDIS_SSL_TRUSTSTORE_PASSWORD:}" + # Type of the key store (JKS or PKCS12) + keystore_type: "${TB_REDIS_SSL_KEY_STORE_TYPE:JKS}" + # The location of the key store file. This is optional for the client and can be used for two-way authentication for the client + keystore_location: "${TB_REDIS_SSL_KEYSTORE_LOCATION:}" + # The store password for the key store file. This is optional for the client and only needed if ‘ssl.keystore.location’ is configured. Key store password is not supported for PEM format + keystore_password: "${TB_REDIS_SSL_KEYSTORE_PASSWORD:}" # pool config pool_config: # Maximum number of connections that can be allocated by the connection pool diff --git a/transport/http/src/main/resources/tb-http-transport.yml b/transport/http/src/main/resources/tb-http-transport.yml index 83b0828386..3f8af8bb91 100644 --- a/transport/http/src/main/resources/tb-http-transport.yml +++ b/transport/http/src/main/resources/tb-http-transport.yml @@ -127,6 +127,35 @@ redis: db: "${REDIS_DB:0}" # db password password: "${REDIS_PASSWORD:}" + ssl: + # Enable/disable secure connection + enabled: "${REDIS_SSL_ENABLED:false}" + # Server SSL credentials + credentials: + # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore) + type: "${TB_REDIS_SSL_CREDENTIALS_TYPE:pem}" + # PEM server credentials + pem: + # Path redis server (CA) certificate + cert_file: "${TB_REDIS_SSL_PEM_CERT:}" + # Path to user certificate file + user_cert_file: "${TB_REDIS_SSL_PEM_KEY:}" + # Path to user private key file + user_key_file: "${TB_REDIS_SSL_PEM_KEY_PASSWORD:}" + # Keystore server credentials + keystore: + # Type of the trust store (JKS or PKCS12) + truststore_type: "${TB_REDIS_SSL_KEY_STORE_TYPE:JKS}" + # The location of the trust store file + truststore_location: "${TB_REDIS_SSL_TRUSTSTORE_LOCATION:}" + # The password of trust store file if specified + truststore_password: "${TB_REDIS_SSL_TRUSTSTORE_PASSWORD:}" + # Type of the key store (JKS or PKCS12) + keystore_type: "${TB_REDIS_SSL_KEY_STORE_TYPE:JKS}" + # The location of the key store file. This is optional for the client and can be used for two-way authentication for the client + keystore_location: "${TB_REDIS_SSL_KEYSTORE_LOCATION:}" + # The store password for the key store file. This is optional for the client and only needed if ‘ssl.keystore.location’ is configured. Key store password is not supported for PEM format + keystore_password: "${TB_REDIS_SSL_KEYSTORE_PASSWORD:}" # pool config pool_config: # Maximum number of connections that can be allocated by the connection pool diff --git a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml index bfd490aa66..345f2eab5e 100644 --- a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml +++ b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml @@ -94,6 +94,35 @@ redis: db: "${REDIS_DB:0}" # db password password: "${REDIS_PASSWORD:}" + ssl: + # Enable/disable secure connection + enabled: "${REDIS_SSL_ENABLED:false}" + # Server SSL credentials + credentials: + # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore) + type: "${TB_REDIS_SSL_CREDENTIALS_TYPE:pem}" + # PEM server credentials + pem: + # Path redis server (CA) certificate + cert_file: "${TB_REDIS_SSL_PEM_CERT:}" + # Path to user certificate file + user_cert_file: "${TB_REDIS_SSL_PEM_KEY:}" + # Path to user private key file + user_key_file: "${TB_REDIS_SSL_PEM_KEY_PASSWORD:}" + # Keystore server credentials + keystore: + # Type of the trust store (JKS or PKCS12) + truststore_type: "${TB_REDIS_SSL_KEY_STORE_TYPE:JKS}" + # The location of the trust store file + truststore_location: "${TB_REDIS_SSL_TRUSTSTORE_LOCATION:}" + # The password of trust store file if specified + truststore_password: "${TB_REDIS_SSL_TRUSTSTORE_PASSWORD:}" + # Type of the key store (JKS or PKCS12) + keystore_type: "${TB_REDIS_SSL_KEY_STORE_TYPE:JKS}" + # The location of the key store file. This is optional for the client and can be used for two-way authentication for the client + keystore_location: "${TB_REDIS_SSL_KEYSTORE_LOCATION:}" + # The store password for the key store file. This is optional for the client and only needed if ‘ssl.keystore.location’ is configured. Key store password is not supported for PEM format + keystore_password: "${TB_REDIS_SSL_KEYSTORE_PASSWORD:}" # pool config pool_config: # Maximum number of connections that can be allocated by the connection pool diff --git a/transport/mqtt/src/main/resources/tb-mqtt-transport.yml b/transport/mqtt/src/main/resources/tb-mqtt-transport.yml index a2ffda28d9..f04c06dc81 100644 --- a/transport/mqtt/src/main/resources/tb-mqtt-transport.yml +++ b/transport/mqtt/src/main/resources/tb-mqtt-transport.yml @@ -95,6 +95,35 @@ redis: db: "${REDIS_DB:0}" # db password password: "${REDIS_PASSWORD:}" + ssl: + # Enable/disable secure connection + enabled: "${REDIS_SSL_ENABLED:false}" + # Server SSL credentials + credentials: + # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore) + type: "${TB_REDIS_SSL_CREDENTIALS_TYPE:pem}" + # PEM server credentials + pem: + # Path redis server (CA) certificate + cert_file: "${TB_REDIS_SSL_PEM_CERT:}" + # Path to user certificate file + user_cert_file: "${TB_REDIS_SSL_PEM_KEY:}" + # Path to user private key file + user_key_file: "${TB_REDIS_SSL_PEM_KEY_PASSWORD:}" + # Keystore server credentials + keystore: + # Type of the trust store (JKS or PKCS12) + truststore_type: "${TB_REDIS_SSL_KEY_STORE_TYPE:JKS}" + # The location of the trust store file + truststore_location: "${TB_REDIS_SSL_TRUSTSTORE_LOCATION:}" + # The password of trust store file if specified + truststore_password: "${TB_REDIS_SSL_TRUSTSTORE_PASSWORD:}" + # Type of the key store (JKS or PKCS12) + keystore_type: "${TB_REDIS_SSL_KEY_STORE_TYPE:JKS}" + # The location of the key store file. This is optional for the client and can be used for two-way authentication for the client + keystore_location: "${TB_REDIS_SSL_KEYSTORE_LOCATION:}" + # The store password for the key store file. This is optional for the client and only needed if ‘ssl.keystore.location’ is configured. Key store password is not supported for PEM format + keystore_password: "${TB_REDIS_SSL_KEYSTORE_PASSWORD:}" # pool config pool_config: # Maximum number of connections that can be allocated by the connection pool diff --git a/transport/snmp/src/main/resources/tb-snmp-transport.yml b/transport/snmp/src/main/resources/tb-snmp-transport.yml index 6a055f83a4..a4e65a67c3 100644 --- a/transport/snmp/src/main/resources/tb-snmp-transport.yml +++ b/transport/snmp/src/main/resources/tb-snmp-transport.yml @@ -94,6 +94,35 @@ redis: db: "${REDIS_DB:0}" # db password password: "${REDIS_PASSWORD:}" + ssl: + # Enable/disable secure connection + enabled: "${REDIS_SSL_ENABLED:false}" + # Server SSL credentials + credentials: + # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore) + type: "${TB_REDIS_SSL_CREDENTIALS_TYPE:pem}" + # PEM server credentials + pem: + # Path redis server (CA) certificate + cert_file: "${TB_REDIS_SSL_PEM_CERT:}" + # Path to user certificate file + user_cert_file: "${TB_REDIS_SSL_PEM_KEY:}" + # Path to user private key file + user_key_file: "${TB_REDIS_SSL_PEM_KEY_PASSWORD:}" + # Keystore server credentials + keystore: + # Type of the trust store (JKS or PKCS12) + truststore_type: "${TB_REDIS_SSL_KEY_STORE_TYPE:JKS}" + # The location of the trust store file + truststore_location: "${TB_REDIS_SSL_TRUSTSTORE_LOCATION:}" + # The password of trust store file if specified + truststore_password: "${TB_REDIS_SSL_TRUSTSTORE_PASSWORD:}" + # Type of the key store (JKS or PKCS12) + keystore_type: "${TB_REDIS_SSL_KEY_STORE_TYPE:JKS}" + # The location of the key store file. This is optional for the client and can be used for two-way authentication for the client + keystore_location: "${TB_REDIS_SSL_KEYSTORE_LOCATION:}" + # The store password for the key store file. This is optional for the client and only needed if ‘ssl.keystore.location’ is configured. Key store password is not supported for PEM format + keystore_password: "${TB_REDIS_SSL_KEYSTORE_PASSWORD:}" # pool config pool_config: # Maximum number of connections that can be allocated by the connection pool From 05f0dd4137e3f005147a1197348cf44abc3b82d2 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Fri, 19 Jan 2024 14:06:00 +0200 Subject: [PATCH 4/7] TLS for redis: updated black-box tests to run with ssl redis --- .../server/msa/ContainerTestSuite.java | 23 ++++ .../docker-compose.redis-ssl.volumes.yml | 27 ++++ .../resources/docker-compose.redis-ssl.yml | 129 ++++++++++++++++++ .../src/test/resources/redis-certs/redis.crt | 28 ++++ .../src/test/resources/redis-certs/redis.key | 28 ++++ .../test/resources/redis-certs/redisCA.crt | 32 +++++ 6 files changed, 267 insertions(+) create mode 100644 msa/black-box-tests/src/test/resources/docker-compose.redis-ssl.volumes.yml create mode 100644 msa/black-box-tests/src/test/resources/docker-compose.redis-ssl.yml create mode 100755 msa/black-box-tests/src/test/resources/redis-certs/redis.crt create mode 100755 msa/black-box-tests/src/test/resources/redis-certs/redis.key create mode 100644 msa/black-box-tests/src/test/resources/redis-certs/redisCA.crt diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ContainerTestSuite.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ContainerTestSuite.java index 15c3ccbbba..6df75fdac4 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ContainerTestSuite.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ContainerTestSuite.java @@ -44,6 +44,7 @@ import static org.testng.Assert.fail; public class ContainerTestSuite { final static boolean IS_REDIS_CLUSTER = Boolean.parseBoolean(System.getProperty("blackBoxTests.redisCluster")); final static boolean IS_REDIS_SENTINEL = Boolean.parseBoolean(System.getProperty("blackBoxTests.redisSentinel")); + final static boolean IS_REDIS_SSL = Boolean.parseBoolean(System.getProperty("blackBoxTests.redisSsl")); final static boolean IS_HYBRID_MODE = Boolean.parseBoolean(System.getProperty("blackBoxTests.hybridMode")); final static String QUEUE_TYPE = System.getProperty("blackBoxTests.queue", "kafka"); private static final String SOURCE_DIR = "./../../docker/"; @@ -82,6 +83,7 @@ public class ContainerTestSuite { installTb.createVolumes(); log.info("System property of blackBoxTests.redisCluster is {}", IS_REDIS_CLUSTER); log.info("System property of blackBoxTests.redisSentinel is {}", IS_REDIS_SENTINEL); + log.info("System property of blackBoxTests.redisSsl is {}", IS_REDIS_SSL); log.info("System property of blackBoxTests.hybridMode is {}", IS_HYBRID_MODE); boolean skipTailChildContainers = Boolean.parseBoolean(System.getProperty("blackBoxTests.skipTailChildContainers")); try { @@ -104,6 +106,12 @@ public class ContainerTestSuite { } } + if (IS_REDIS_SSL) { + addToFile(targetDir, "cache-redis.env", + Map.of("REDIS_SSL_ENABLED", "true", + "TB_REDIS_SSL_PEM_CERT", "/redis/certs/redisCA.crt")); + } + List composeFiles = new ArrayList<>(Arrays.asList( new File(targetDir + "docker-compose.yml"), new File(targetDir + "docker-compose.volumes.yml"), @@ -188,6 +196,9 @@ public class ContainerTestSuite { if (IS_REDIS_SENTINEL) { return "docker-compose.redis-sentinel.yml"; } + if (IS_REDIS_SSL) { + return "docker-compose.redis-ssl.yml"; + } return "docker-compose.redis.yml"; } @@ -198,6 +209,9 @@ public class ContainerTestSuite { if (IS_REDIS_SENTINEL) { return "docker-compose.redis-sentinel.volumes.yml"; } + if (IS_REDIS_SSL) { + return "docker-compose.redis-ssl.volumes.yml"; + } return "docker-compose.redis.volumes.yml"; } @@ -218,6 +232,15 @@ public class ContainerTestSuite { Files.write(envFilePath, data.getBytes(StandardCharsets.UTF_8)); } + private static void addToFile(String targetDir, String fileName, Map properties) throws IOException { + Path envFilePath = Path.of(targetDir, fileName); + StringBuilder data = new StringBuilder(Files.readString(envFilePath)); + for (var entry : properties.entrySet()) { + data.append("\n").append(entry.getKey()).append("=").append(entry.getValue()); + } + Files.write(envFilePath, data.toString().getBytes(StandardCharsets.UTF_8)); + } + private static String getSysProp(String propertyName) { var value = System.getProperty(propertyName); if (StringUtils.isEmpty(value)) { diff --git a/msa/black-box-tests/src/test/resources/docker-compose.redis-ssl.volumes.yml b/msa/black-box-tests/src/test/resources/docker-compose.redis-ssl.volumes.yml new file mode 100644 index 0000000000..2042fa5919 --- /dev/null +++ b/msa/black-box-tests/src/test/resources/docker-compose.redis-ssl.volumes.yml @@ -0,0 +1,27 @@ +# +# Copyright © 2016-2024 The Thingsboard Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +version: '3.0' + +services: + redis: + volumes: + - redis-data:/bitnami/redis/data + +volumes: + redis-data: + external: + name: ${REDIS_DATA_VOLUME} diff --git a/msa/black-box-tests/src/test/resources/docker-compose.redis-ssl.yml b/msa/black-box-tests/src/test/resources/docker-compose.redis-ssl.yml new file mode 100644 index 0000000000..e5444db329 --- /dev/null +++ b/msa/black-box-tests/src/test/resources/docker-compose.redis-ssl.yml @@ -0,0 +1,129 @@ +# +# Copyright © 2016-2024 The Thingsboard Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +version: '3.0' + +services: +# Redis standalone + redis: + restart: always + image: bitnami/redis:7.0 + environment: + # ALLOW_EMPTY_PASSWORD is recommended only for development. + - 'ALLOW_EMPTY_PASSWORD=yes' + - 'REDIS_TLS_ENABLED=yes' + - 'REDIS_TLS_CERT_FILE=/redis/certs/redis.crt' + - 'REDIS_TLS_KEY_FILE=/redis/certs/redis.key' + - 'REDIS_TLS_CA_FILE=/redis/certs/redisCA.crt' + - 'REDIS_TLS_AUTH_CLIENTS=no' + ports: + - '6379:6379' + volumes: + - ./tb-node/redis-data:/bitnami/redis/data + - ./redis-certs:/redis/certs + +# ThingsBoard setup to use redis-standalone + tb-core1: + env_file: + - cache-redis.env + volumes: + - ./redis-certs:/redis/certs + depends_on: + - redis + tb-core2: + env_file: + - cache-redis.env + volumes: + - ./redis-certs:/redis/certs + depends_on: + - redis + tb-rule-engine1: + env_file: + - cache-redis.env + volumes: + - ./redis-certs:/redis/certs + depends_on: + - redis + tb-rule-engine2: + env_file: + - cache-redis.env + volumes: + - ./redis-certs:/redis/certs + depends_on: + - redis + tb-mqtt-transport1: + env_file: + - cache-redis.env + volumes: + - ./redis-certs:/redis/certs + depends_on: + - redis + tb-mqtt-transport2: + env_file: + - cache-redis.env + volumes: + - ./redis-certs:/redis/certs + depends_on: + - redis + tb-http-transport1: + env_file: + - cache-redis.env + volumes: + - ./redis-certs:/redis/certs + depends_on: + - redis + tb-http-transport2: + env_file: + - cache-redis.env + volumes: + - ./redis-certs:/redis/certs + depends_on: + - redis + tb-coap-transport: + env_file: + - cache-redis.env + volumes: + - ./redis-certs:/redis/certs + depends_on: + - redis + tb-lwm2m-transport: + env_file: + - cache-redis.env + volumes: + - ./redis-certs:/redis/certs + depends_on: + - redis + tb-snmp-transport: + env_file: + - cache-redis.env + volumes: + - ./redis-certs:/redis/certs + depends_on: + - redis + tb-vc-executor1: + env_file: + - cache-redis.env + volumes: + - ./redis-certs:/redis/certs + depends_on: + - redis + tb-vc-executor2: + env_file: + - cache-redis.env + volumes: + - ./redis-certs:/redis/certs + depends_on: + - redis diff --git a/msa/black-box-tests/src/test/resources/redis-certs/redis.crt b/msa/black-box-tests/src/test/resources/redis-certs/redis.crt new file mode 100755 index 0000000000..8fce48c0a1 --- /dev/null +++ b/msa/black-box-tests/src/test/resources/redis-certs/redis.crt @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIE1TCCAr2gAwIBAgIUFdFLz/q0EosJc39HhIac9+XpyRkwDQYJKoZIhvcNAQEL +BQAwWTELMAkGA1UEBhMCdWExDTALBgNVBAgMBGt5aXYxDTALBgNVBAcMBGt5aXYx +CzAJBgNVBAoMAnRiMQswCQYDVQQLDAJ0YjESMBAGA1UEAwwJbG9jYWxob3N0MB4X +DTIzMDkwNDE1NTA0MVoXDTI0MDkwMzE1NTA0MVowYjELMAkGA1UEBhMCQ1IxEzAR +BgNVBAgMCkNoYW5kcmlsbGExEzARBgNVBAcMCkNoYW5kcmlsbGExEjAQBgNVBAMM +CUhPU1RfTkFNRTEVMBMGA1UECgwMTmV3IFJlcHVibGljMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEA+ICaK/aSklkUIih3cl4k4RYJL8rLS68d5JVSxpCQ +8MwuAakdU+ptD0b6X4+CcNtR96UlcO3cR15GLLT6s29Kw4Ta5SME+yhuFLUIrWxA +/gJ/pkJGkq1vXYZzdUFjtMlF+VbIw+r2hhSkbTR1hV08iRlvflafS8JB/tznqTFy +QIXu08heRtxVaC6SMHLeHmZdgdJrSOulwg/ctcP6tki+ZU9v+TH71M3mTIOLzuSz +7sqnFMPgW7ER0Utc4fndRfz17LA1NZdSrN0Ch5IO+EZ9gf/25w8makbx7lZoZASm +sAd0Uyq9ZPC0ok+oJjeDwanl/Bo7CGEgdxaFYNKpnizyUQIDAQABo4GLMIGIMAsG +A1UdDwQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwGgYDVR0R +BBMwEYIJbG9jYWxob3N0hwR/AAABMB0GA1UdDgQWBBRAIkMMxT30wZYoNQuDM7uT +qwb+VzAfBgNVHSMEGDAWgBSfpEhvBqWx6usjDlGx7lEx8Fl21DANBgkqhkiG9w0B +AQsFAAOCAgEAMeaZ5K0w2kPSqcZbzV4WwGShrhnSYdsA4dlZhAUNNxsoXX590Ppe +lla+vhFSdk/IwjFxLzmiau5+JlCySeOJv2AaG56JvBBU1Wl8LOk01a7qRctiKRth +AGFGKZoJ50h5W1A0NV7KwcGIkQdebAFPdMmkOd6Do98ZhkzYLRuAK3U0K4wNQJuf +gPt9XtIugRNQOwxolXAj81FfhjZ5CnoaCQYJBFyIenwg4uGjg+D0F9WtAlRq8ww+ +XpWpVw8QgPDk+SVoGXUsBs+wMCDlGu4ozN2lIvG1N5n1q0qn39SUYOSBkEsdM+AS +Yu6LMP4J1SPOwT5UJN2jK7fAYBdChF39nV/xiatfUSy8rWUFQSwGv6JD3X0MAYfT +DyOiYdX8o+AnetjfBHHwVXDobh5d1GiC2DwoUNW7KoEdj5mmhDZKiB2S47/5J7El +UA9CevmmDvf/tN9itPrutSwcb7uwLYRsf7Gx3D3P/2+nQHUKyNcyQCNtgR7RKHBS +EjeedMgtKvrqsdPnk6Ygwj8EMh4owDIDcieqnPZAxhqJOJT2ZORdzyelmpv5aDGc +0XnnRHRInSUgQStfPa9ghOBpSXlhxL1EJFFik+yFOjH4GivhoynCb7zjW+MjlPDV +LAsnmMukBR95ZkpxMnRUEoLTEvTaxmg4Vr/mqXeQUKdU8A812Wrk2hc= +-----END CERTIFICATE----- diff --git a/msa/black-box-tests/src/test/resources/redis-certs/redis.key b/msa/black-box-tests/src/test/resources/redis-certs/redis.key new file mode 100755 index 0000000000..cbbf83ca2b --- /dev/null +++ b/msa/black-box-tests/src/test/resources/redis-certs/redis.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQD4gJor9pKSWRQi +KHdyXiThFgkvystLrx3klVLGkJDwzC4BqR1T6m0PRvpfj4Jw21H3pSVw7dxHXkYs +tPqzb0rDhNrlIwT7KG4UtQitbED+An+mQkaSrW9dhnN1QWO0yUX5VsjD6vaGFKRt +NHWFXTyJGW9+Vp9LwkH+3OepMXJAhe7TyF5G3FVoLpIwct4eZl2B0mtI66XCD9y1 +w/q2SL5lT2/5MfvUzeZMg4vO5LPuyqcUw+BbsRHRS1zh+d1F/PXssDU1l1Ks3QKH +kg74Rn2B//bnDyZqRvHuVmhkBKawB3RTKr1k8LSiT6gmN4PBqeX8GjsIYSB3FoVg +0qmeLPJRAgMBAAECggEAE6sCCMa8NQ8N0+JGCew/mP0Ifxra2kOi5wuWgJbCkfxn +C8SZyKF+Pj5M5LFUDqCdLS+J9hUtYQyqGzG7weXmEfF67bXG2CYMCGGHrUorHq+N +8NfABC3r6YgRrU8emBlyC1j+DNuU5WnO1cHYJ1UIzIUR2Pr8Ip/eX1CWmUKLm2WW +YvUGzvTG0mM0l9/Q8pcTndAxDuL90GG6TrxtQoy7Ir6dYxTVKHgOwa6RX86VrCkm +jl6Wu7Bvo2fnPvPVx8p1mgWNgtBbnc/VAYjeF7Yi7CETWHTxGM4iGtZNL8/xxlW7 +sm2SmWEu72EupLYgytA9w+EptjbwWfcTaWbWUXTFHQKBgQD5nmYLVvZUR1oc9g2a +Q7XpFQ/jVvwedeKGolMbWTFrEhl1+D8lKN/S3SoRCOALOUJFUCU+L1snN3MsJ5Es +Gb0FLSH1LBBfuHqP+aHn/uGLMW8e7P9thh4DQ1tIzKE5xhh+JDJJqd15YJlsDy1F +0aKWyulS4o9XK5q86rs5QbI4MwKBgQD+2uXEAiFwEXq7pw2e8STrnt0jp09KU6b1 +z/ykyArBdcVkrEudZ+jIrR/6rlSKK+SKQxtx8MG9M/Nm09KFRCAWblxHBwQ87ZnU +8tMAmPHrikLKk1dbbU3BQ3cZkIWMryCo4wzuxeT4mc2goTGNZpNZDpjqjCXbnCgP +T29aPHG3awKBgGFv8UlP4su3JnfTnC+xaprXO+J0G+oP/iKrzmEIif/Pity/0HZC +5Eu9RSRtIHeBHFtOE5uYhK5kOLLtpv9d9KjGm1DGqIWUz1LQEOEsXwIkg8nAnVw1 +VBXV/xYFupGAwCLNIkwa4Hb2vCywJ+3vDNZr0nQmN+nA/Z/syLRq7pR9AoGBALqp +l3pd2SHdG5jP/VD57IHLRMs1YwTcikAmizQh9IbH/MEE1QlALya0buTLxM3C4kxG +ZJaqsSwkHdWltd64DAyB3oKDaB48JNzs0ZDxdNeA1/TJwEUNpNK12EjYKojlSDWK +v1Evjspq1EofZkzb4XZsE6JO7feQw2KbWsKr3NprAoGBAKSSAjDpncxb+9Pr0Lwa +AS7ATgMhot6+lbtZZV6egTGUVvtgd1LyE2ZJkE+5XJRu49X1lSJdDpFT66rG5eNV ++rYnDqXL8c0Z/j1L96z1UMY6DLPj3n+07zgLiNIrOR4UKP/+TGB9MHHFMEpYnij0 +m/f6dg0Ujw6CW31Hq2QdJ9P7 +-----END PRIVATE KEY----- diff --git a/msa/black-box-tests/src/test/resources/redis-certs/redisCA.crt b/msa/black-box-tests/src/test/resources/redis-certs/redisCA.crt new file mode 100644 index 0000000000..444dac130b --- /dev/null +++ b/msa/black-box-tests/src/test/resources/redis-certs/redisCA.crt @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFkzCCA3ugAwIBAgIUK9fjeDv+ESrdFSHMqsod5djzTh4wDQYJKoZIhvcNAQEL +BQAwWTELMAkGA1UEBhMCdWExDTALBgNVBAgMBGt5aXYxDTALBgNVBAcMBGt5aXYx +CzAJBgNVBAoMAnRiMQswCQYDVQQLDAJ0YjESMBAGA1UEAwwJbG9jYWxob3N0MB4X +DTIzMDkwNDE1MDUxN1oXDTMzMDkwMTE1MDUxN1owWTELMAkGA1UEBhMCdWExDTAL +BgNVBAgMBGt5aXYxDTALBgNVBAcMBGt5aXYxCzAJBgNVBAoMAnRiMQswCQYDVQQL +DAJ0YjESMBAGA1UEAwwJbG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A +MIICCgKCAgEAsaxpM/OLfx0jNVHAiD4dmJ4t5vZQNINtaI/GgnXNv9iM3aDvbYr/ +Cp8mJgkOvI9BZqDEcLscBv+H4mxCqS2IFBqJbtkYHExBgg7V13NRtJwqsWVz0rBG +V1SFou2JSzPkQ6IDxJI+AUW6DfsbCs3o6VRPbriMfY06rNagerG1osaD9yn/EsH9 +BTdALravcvU8mxOghzWH54EzwDUA0mKUetgvgfqkzjDlqzXFnOsIinnDi0Ia3idF +RaBVs7bKokl0Zp1mdtvsEpG4lcmhDtNIogcmeH2LW2zEneHuDX2BGsN9CCwEGj3k +cftuxEck2mQVDoDgX1IpIUGBhIaAixj+UXh8RNSwU96GBwKbFNy/CXNj5+34DcL0 +kBh7p77rcrzm6xEGpP/3YYPoRVBRAX64x4QqzqF5oj6Sf2NGKH9RILmLWdqmq/up +6cMYyzAEOr3nIQ/7OfkdvxOt0oUzeB7QPYbTvM9bCqe3XA+JH1pnLhgySPxdTeVe +nUExge8WPJmdTlH1McminFDiJruFRa069hbky/b5z8BjIBN5S3lC4PdEE9YmDSL1 +u26HnRVwtqC32fkDNI1PT/4p2VaB+DmIxkFXrVUnV0TiyCyxu4jIgXhUiJRHgBn9 +zwB7lEZUhMriOBGJqHa0H0TtnH8z/5GYmipeJZllmQbhI+sMyYBS/+cCAwEAAaNT +MFEwHQYDVR0OBBYEFJ+kSG8GpbHq6yMOUbHuUTHwWXbUMB8GA1UdIwQYMBaAFJ+k +SG8GpbHq6yMOUbHuUTHwWXbUMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL +BQADggIBABCt/bx7/YbvR/0PE4nIzxVovPItR+oYcInRrbwT+VWvL22Su7rf71lc +1vlil4xjdVxSEi6s5KZ69PLJKKXukt1MBCUStDK1HKPPB1SAhtD6nuvkh7YL+2im +A5gmtg3KkD2ZD2mWCHAa8K7NEMah1XiMVMo+ByFNPQExqOk2i3+5kjBrlfElsm0Q +ixM++93T62gTibOjuO8uPP0NUcIHI+RcEalc1hJjFof4gWLnIulaeuUydXw7RhzE +HzeOeZiZWrvW2mjfiANMn27TV5K0dZoh/4+YLqkKn1bdQsYVIWxWx8jZ0Nj0yzMb +Ekkodny3F+BHqkSUb3whRWDKN82valnCSJFAKZFZzueAJgCjANTNdr7S7UUIxZyi +QKll59T4O1yhawRu/cZ6TQWzV7RWdTerFfIjHMwsohDUxlkoACJebLahsBG9IHGN +Tn+P2djY6CXBctbTXhRiYqeb79/TPU0EETv7/ilNHS/tssWcKWkFdai3yMzLvxeH +YTVPMzeAWW/PnQOwYTkgeaj7SIK5bbm5n/gpWk31R5gRWhgJc9FZSa9+oZWbWeYh +3XfsuCuTH+jSs0g+jJUx/cpIVrO38r2hSuhDPugmHgM6yEnKMubhChCPCyXjO0z9 +brEMQ1T9r2sKOYuyNDhN/W9/QsTb/RO4Ug2lYlzRTdehqvimHspW +-----END CERTIFICATE----- From e27ef320e748d4be15354dc8c1e65763cfe36204 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Mon, 22 Jan 2024 12:31:01 +0200 Subject: [PATCH 5/7] updated env variable name and descriptions --- application/src/main/resources/thingsboard.yml | 6 +++--- .../server/cache/TBRedisStandaloneConfiguration.java | 2 +- .../java/org/thingsboard/server/msa/ContainerTestSuite.java | 2 +- transport/coap/src/main/resources/tb-coap-transport.yml | 6 +++--- transport/http/src/main/resources/tb-http-transport.yml | 6 +++--- transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml | 6 +++--- transport/mqtt/src/main/resources/tb-mqtt-transport.yml | 6 +++--- transport/snmp/src/main/resources/tb-snmp-transport.yml | 6 +++--- 8 files changed, 20 insertions(+), 20 deletions(-) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index e2f1a80d42..18565f463e 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -642,7 +642,7 @@ redis: # ssl config ssl: # Enable/disable secure connection - enabled: "${REDIS_SSL_ENABLED:false}" + enabled: "${TB_REDIS_SSL_ENABLED:false}" # Server SSL credentials credentials: # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore) @@ -651,9 +651,9 @@ redis: pem: # Path redis server (CA) certificate cert_file: "${TB_REDIS_SSL_PEM_CERT:}" - # Path to user certificate file (optional) + # Path to user certificate file. This is optional for the client and can be used for two-way authentication for the client user_cert_file: "${TB_REDIS_SSL_PEM_KEY:}" - # Path to user private key file (optional) + # Path to user private key file. This is optional for the client and only needed if ‘ssl.pem.user_cert_file’ is configured. user_key_file: "${TB_REDIS_SSL_PEM_KEY_PASSWORD:}" # Keystore server credentials keystore: diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/TBRedisStandaloneConfiguration.java b/common/cache/src/main/java/org/thingsboard/server/cache/TBRedisStandaloneConfiguration.java index f0f250bbaa..d4235e3662 100644 --- a/common/cache/src/main/java/org/thingsboard/server/cache/TBRedisStandaloneConfiguration.java +++ b/common/cache/src/main/java/org/thingsboard/server/cache/TBRedisStandaloneConfiguration.java @@ -89,4 +89,4 @@ public class TBRedisStandaloneConfiguration extends TBRedisCacheConfiguration { } return jedisClientConfigurationBuilder.build(); } -} \ No newline at end of file +} diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ContainerTestSuite.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ContainerTestSuite.java index 6df75fdac4..bbaeabe907 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ContainerTestSuite.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ContainerTestSuite.java @@ -108,7 +108,7 @@ public class ContainerTestSuite { if (IS_REDIS_SSL) { addToFile(targetDir, "cache-redis.env", - Map.of("REDIS_SSL_ENABLED", "true", + Map.of("TB_REDIS_SSL_ENABLED", "true", "TB_REDIS_SSL_PEM_CERT", "/redis/certs/redisCA.crt")); } diff --git a/transport/coap/src/main/resources/tb-coap-transport.yml b/transport/coap/src/main/resources/tb-coap-transport.yml index 87e3cf870d..43a84b3d5a 100644 --- a/transport/coap/src/main/resources/tb-coap-transport.yml +++ b/transport/coap/src/main/resources/tb-coap-transport.yml @@ -96,7 +96,7 @@ redis: password: "${REDIS_PASSWORD:}" ssl: # Enable/disable secure connection - enabled: "${REDIS_SSL_ENABLED:false}" + enabled: "${TB_REDIS_SSL_ENABLED:false}" # Server SSL credentials credentials: # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore) @@ -105,9 +105,9 @@ redis: pem: # Path redis server (CA) certificate cert_file: "${TB_REDIS_SSL_PEM_CERT:}" - # Path to user certificate file + # Path to user certificate file. This is optional for the client and can be used for two-way authentication for the client user_cert_file: "${TB_REDIS_SSL_PEM_KEY:}" - # Path to user private key file + # Path to user private key file. This is optional for the client and only needed if ‘ssl.pem.user_cert_file’ is configured. user_key_file: "${TB_REDIS_SSL_PEM_KEY_PASSWORD:}" # Keystore server credentials keystore: diff --git a/transport/http/src/main/resources/tb-http-transport.yml b/transport/http/src/main/resources/tb-http-transport.yml index 3f8af8bb91..e226319c20 100644 --- a/transport/http/src/main/resources/tb-http-transport.yml +++ b/transport/http/src/main/resources/tb-http-transport.yml @@ -129,7 +129,7 @@ redis: password: "${REDIS_PASSWORD:}" ssl: # Enable/disable secure connection - enabled: "${REDIS_SSL_ENABLED:false}" + enabled: "${TB_REDIS_SSL_ENABLED:false}" # Server SSL credentials credentials: # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore) @@ -138,9 +138,9 @@ redis: pem: # Path redis server (CA) certificate cert_file: "${TB_REDIS_SSL_PEM_CERT:}" - # Path to user certificate file + # Path to user certificate file. This is optional for the client and can be used for two-way authentication for the client user_cert_file: "${TB_REDIS_SSL_PEM_KEY:}" - # Path to user private key file + # Path to user private key file. This is optional for the client and only needed if ‘ssl.pem.user_cert_file’ is configured. user_key_file: "${TB_REDIS_SSL_PEM_KEY_PASSWORD:}" # Keystore server credentials keystore: diff --git a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml index 345f2eab5e..93a553eea5 100644 --- a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml +++ b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml @@ -96,7 +96,7 @@ redis: password: "${REDIS_PASSWORD:}" ssl: # Enable/disable secure connection - enabled: "${REDIS_SSL_ENABLED:false}" + enabled: "${TB_REDIS_SSL_ENABLED:false}" # Server SSL credentials credentials: # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore) @@ -105,9 +105,9 @@ redis: pem: # Path redis server (CA) certificate cert_file: "${TB_REDIS_SSL_PEM_CERT:}" - # Path to user certificate file + # Path to user certificate file. This is optional for the client and can be used for two-way authentication for the client user_cert_file: "${TB_REDIS_SSL_PEM_KEY:}" - # Path to user private key file + # Path to user private key file. This is optional for the client and only needed if ‘ssl.pem.user_cert_file’ is configured. user_key_file: "${TB_REDIS_SSL_PEM_KEY_PASSWORD:}" # Keystore server credentials keystore: diff --git a/transport/mqtt/src/main/resources/tb-mqtt-transport.yml b/transport/mqtt/src/main/resources/tb-mqtt-transport.yml index f04c06dc81..e2c65a4a63 100644 --- a/transport/mqtt/src/main/resources/tb-mqtt-transport.yml +++ b/transport/mqtt/src/main/resources/tb-mqtt-transport.yml @@ -97,7 +97,7 @@ redis: password: "${REDIS_PASSWORD:}" ssl: # Enable/disable secure connection - enabled: "${REDIS_SSL_ENABLED:false}" + enabled: "${TB_REDIS_SSL_ENABLED:false}" # Server SSL credentials credentials: # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore) @@ -106,9 +106,9 @@ redis: pem: # Path redis server (CA) certificate cert_file: "${TB_REDIS_SSL_PEM_CERT:}" - # Path to user certificate file + # Path to user certificate file. This is optional for the client and can be used for two-way authentication for the client user_cert_file: "${TB_REDIS_SSL_PEM_KEY:}" - # Path to user private key file + # Path to user private key file. This is optional for the client and only needed if ‘ssl.pem.user_cert_file’ is configured. user_key_file: "${TB_REDIS_SSL_PEM_KEY_PASSWORD:}" # Keystore server credentials keystore: diff --git a/transport/snmp/src/main/resources/tb-snmp-transport.yml b/transport/snmp/src/main/resources/tb-snmp-transport.yml index a4e65a67c3..db20b596f0 100644 --- a/transport/snmp/src/main/resources/tb-snmp-transport.yml +++ b/transport/snmp/src/main/resources/tb-snmp-transport.yml @@ -96,7 +96,7 @@ redis: password: "${REDIS_PASSWORD:}" ssl: # Enable/disable secure connection - enabled: "${REDIS_SSL_ENABLED:false}" + enabled: "${TB_REDIS_SSL_ENABLED:false}" # Server SSL credentials credentials: # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore) @@ -105,9 +105,9 @@ redis: pem: # Path redis server (CA) certificate cert_file: "${TB_REDIS_SSL_PEM_CERT:}" - # Path to user certificate file + # Path to user certificate file. This is optional for the client and can be used for two-way authentication for the client user_cert_file: "${TB_REDIS_SSL_PEM_KEY:}" - # Path to user private key file + # Path to user private key file. This is optional for the client and only needed if ‘ssl.pem.user_cert_file’ is configured. user_key_file: "${TB_REDIS_SSL_PEM_KEY_PASSWORD:}" # Keystore server credentials keystore: From dfe23510799e4b639a8c46a5a8536af48a0fbc03 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Wed, 24 Jan 2024 13:11:32 +0200 Subject: [PATCH 6/7] yml parameter description update --- application/src/main/resources/thingsboard.yml | 2 +- transport/coap/src/main/resources/tb-coap-transport.yml | 2 +- transport/http/src/main/resources/tb-http-transport.yml | 2 +- transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml | 2 +- transport/mqtt/src/main/resources/tb-mqtt-transport.yml | 2 +- transport/snmp/src/main/resources/tb-snmp-transport.yml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 18565f463e..38cfdd64a0 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -645,7 +645,7 @@ redis: enabled: "${TB_REDIS_SSL_ENABLED:false}" # Server SSL credentials credentials: - # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore) + # Server credentials type (pem - pem certificate file; keystore - java keystore) type: "${TB_REDIS_SSL_CREDENTIALS_TYPE:pem}" # PEM server credentials pem: diff --git a/transport/coap/src/main/resources/tb-coap-transport.yml b/transport/coap/src/main/resources/tb-coap-transport.yml index 43a84b3d5a..78ca89851d 100644 --- a/transport/coap/src/main/resources/tb-coap-transport.yml +++ b/transport/coap/src/main/resources/tb-coap-transport.yml @@ -99,7 +99,7 @@ redis: enabled: "${TB_REDIS_SSL_ENABLED:false}" # Server SSL credentials credentials: - # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore) + # Server credentials type (pem - pem certificate file; keystore - java keystore) type: "${TB_REDIS_SSL_CREDENTIALS_TYPE:pem}" # PEM server credentials pem: diff --git a/transport/http/src/main/resources/tb-http-transport.yml b/transport/http/src/main/resources/tb-http-transport.yml index e226319c20..04a9c9417f 100644 --- a/transport/http/src/main/resources/tb-http-transport.yml +++ b/transport/http/src/main/resources/tb-http-transport.yml @@ -132,7 +132,7 @@ redis: enabled: "${TB_REDIS_SSL_ENABLED:false}" # Server SSL credentials credentials: - # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore) + # Server credentials type (pem - pem certificate file; keystore - java keystore) type: "${TB_REDIS_SSL_CREDENTIALS_TYPE:pem}" # PEM server credentials pem: diff --git a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml index 93a553eea5..c079f690ed 100644 --- a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml +++ b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml @@ -99,7 +99,7 @@ redis: enabled: "${TB_REDIS_SSL_ENABLED:false}" # Server SSL credentials credentials: - # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore) + # Server credentials type (pem - pem certificate file; keystore - java keystore) type: "${TB_REDIS_SSL_CREDENTIALS_TYPE:pem}" # PEM server credentials pem: diff --git a/transport/mqtt/src/main/resources/tb-mqtt-transport.yml b/transport/mqtt/src/main/resources/tb-mqtt-transport.yml index e2c65a4a63..430b5bfed5 100644 --- a/transport/mqtt/src/main/resources/tb-mqtt-transport.yml +++ b/transport/mqtt/src/main/resources/tb-mqtt-transport.yml @@ -100,7 +100,7 @@ redis: enabled: "${TB_REDIS_SSL_ENABLED:false}" # Server SSL credentials credentials: - # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore) + # Server credentials type (pem - pem certificate file; keystore - java keystore) type: "${TB_REDIS_SSL_CREDENTIALS_TYPE:pem}" # PEM server credentials pem: diff --git a/transport/snmp/src/main/resources/tb-snmp-transport.yml b/transport/snmp/src/main/resources/tb-snmp-transport.yml index db20b596f0..68b69bb03a 100644 --- a/transport/snmp/src/main/resources/tb-snmp-transport.yml +++ b/transport/snmp/src/main/resources/tb-snmp-transport.yml @@ -99,7 +99,7 @@ redis: enabled: "${TB_REDIS_SSL_ENABLED:false}" # Server SSL credentials credentials: - # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore) + # Server credentials type (pem - pem certificate file; keystore - java keystore) type: "${TB_REDIS_SSL_CREDENTIALS_TYPE:pem}" # PEM server credentials pem: From 6a755ab0b7dc54e51ee67315572e095705ce1be0 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Tue, 6 Feb 2024 15:10:09 +0200 Subject: [PATCH 7/7] deleted java keystore type of creds support --- .../src/main/resources/thingsboard.yml | 32 ++------- .../cache/RedisKeystoreCredentialsConfig.java | 36 ---------- .../cache/RedisPemCredentialsConfig.java | 28 -------- ...guration.java => RedisSslCredentials.java} | 9 ++- .../cache/TBRedisCacheConfiguration.java | 69 +++++-------------- .../org/thingsboard/common/util/SslUtil.java | 1 + msa/black-box-tests/README.md | 4 ++ .../src/main/resources/tb-coap-transport.yml | 32 ++------- .../src/main/resources/tb-http-transport.yml | 32 ++------- .../src/main/resources/tb-lwm2m-transport.yml | 32 ++------- .../src/main/resources/tb-mqtt-transport.yml | 32 ++------- .../src/main/resources/tb-snmp-transport.yml | 32 ++------- 12 files changed, 70 insertions(+), 269 deletions(-) delete mode 100644 common/cache/src/main/java/org/thingsboard/server/cache/RedisKeystoreCredentialsConfig.java delete mode 100644 common/cache/src/main/java/org/thingsboard/server/cache/RedisPemCredentialsConfig.java rename common/cache/src/main/java/org/thingsboard/server/cache/{RedisSslCredentialsConfiguration.java => RedisSslCredentials.java} (84%) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 38cfdd64a0..050d46a700 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -643,32 +643,14 @@ redis: ssl: # Enable/disable secure connection enabled: "${TB_REDIS_SSL_ENABLED:false}" - # Server SSL credentials + # Server SSL credentials (only PEM format is supported) credentials: - # Server credentials type (pem - pem certificate file; keystore - java keystore) - type: "${TB_REDIS_SSL_CREDENTIALS_TYPE:pem}" - # PEM server credentials - pem: - # Path redis server (CA) certificate - cert_file: "${TB_REDIS_SSL_PEM_CERT:}" - # Path to user certificate file. This is optional for the client and can be used for two-way authentication for the client - user_cert_file: "${TB_REDIS_SSL_PEM_KEY:}" - # Path to user private key file. This is optional for the client and only needed if ‘ssl.pem.user_cert_file’ is configured. - user_key_file: "${TB_REDIS_SSL_PEM_KEY_PASSWORD:}" - # Keystore server credentials - keystore: - # Type of the trust store (JKS or PKCS12) - truststore_type: "${TB_REDIS_SSL_KEY_STORE_TYPE:JKS}" - # The location of the trust store file - truststore_location: "${TB_REDIS_SSL_TRUSTSTORE_LOCATION:}" - # The password of trust store file if specified - truststore_password: "${TB_REDIS_SSL_TRUSTSTORE_PASSWORD:}" - # Type of the key store (JKS or PKCS12) - keystore_type: "${TB_REDIS_SSL_KEY_STORE_TYPE:JKS}" - # The location of the key store file. This is optional for the client and can be used for two-way authentication for the client - keystore_location: "${TB_REDIS_SSL_KEYSTORE_LOCATION:}" - # The store password for the key store file. This is optional for the client and only needed if ‘ssl.keystore.location’ is configured. Key store password is not supported for PEM format - keystore_password: "${TB_REDIS_SSL_KEYSTORE_PASSWORD:}" + # Path redis server (CA) certificate + cert_file: "${TB_REDIS_SSL_PEM_CERT:}" + # Path to user certificate file. This is optional for the client and can be used for two-way authentication for the client + user_cert_file: "${TB_REDIS_SSL_PEM_KEY:}" + # Path to user private key file. This is optional for the client and only needed if ‘user_cert_file’ is configured. + user_key_file: "${TB_REDIS_SSL_PEM_KEY_PASSWORD:}" # pool config pool_config: # Maximum number of connections that can be allocated by the connection pool diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/RedisKeystoreCredentialsConfig.java b/common/cache/src/main/java/org/thingsboard/server/cache/RedisKeystoreCredentialsConfig.java deleted file mode 100644 index 1d2a08e6d4..0000000000 --- a/common/cache/src/main/java/org/thingsboard/server/cache/RedisKeystoreCredentialsConfig.java +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Copyright © 2016-2024 The Thingsboard Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.thingsboard.server.cache; - -import lombok.Data; - -@Data -public class RedisKeystoreCredentialsConfig { - - private String type; - - private String truststoreType; - - private String truststoreLocation; - - private String truststorePassword; - - private String keystoreType; - - private String keystoreLocation; - - private String keystorePassword; -} diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/RedisPemCredentialsConfig.java b/common/cache/src/main/java/org/thingsboard/server/cache/RedisPemCredentialsConfig.java deleted file mode 100644 index 50e2c71966..0000000000 --- a/common/cache/src/main/java/org/thingsboard/server/cache/RedisPemCredentialsConfig.java +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Copyright © 2016-2024 The Thingsboard Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.thingsboard.server.cache; - -import lombok.Data; - -@Data -public class RedisPemCredentialsConfig { - - private String certFile; - - private String userCertFile; - - private String userKeyFile; -} diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/RedisSslCredentialsConfiguration.java b/common/cache/src/main/java/org/thingsboard/server/cache/RedisSslCredentials.java similarity index 84% rename from common/cache/src/main/java/org/thingsboard/server/cache/RedisSslCredentialsConfiguration.java rename to common/cache/src/main/java/org/thingsboard/server/cache/RedisSslCredentials.java index 6bd46baf1b..aeac975d15 100644 --- a/common/cache/src/main/java/org/thingsboard/server/cache/RedisSslCredentialsConfiguration.java +++ b/common/cache/src/main/java/org/thingsboard/server/cache/RedisSslCredentials.java @@ -22,12 +22,11 @@ import org.springframework.context.annotation.Configuration; @Configuration @ConfigurationProperties(prefix = "redis.ssl.credentials") @Data -public class RedisSslCredentialsConfiguration { +public class RedisSslCredentials { - private String type; + private String certFile; - private RedisKeystoreCredentialsConfig keystore; - - private RedisPemCredentialsConfig pem; + private String userCertFile; + private String userKeyFile; } diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/TBRedisCacheConfiguration.java b/common/cache/src/main/java/org/thingsboard/server/cache/TBRedisCacheConfiguration.java index d8805044f3..c3d3655883 100644 --- a/common/cache/src/main/java/org/thingsboard/server/cache/TBRedisCacheConfiguration.java +++ b/common/cache/src/main/java/org/thingsboard/server/cache/TBRedisCacheConfiguration.java @@ -42,11 +42,14 @@ import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManagerFactory; -import java.io.FileInputStream; +import java.io.IOException; import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.cert.CertPath; import java.security.cert.Certificate; +import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.time.Duration; @@ -100,13 +103,16 @@ public abstract class TBRedisCacheConfiguration { @Value("${redis.pool_config.blockWhenExhausted:true}") private boolean blockWhenExhausted; + @Value("${redis.ssl.enabled:false}") + private boolean sslEnabled; + @Bean public RedisConnectionFactory redisConnectionFactory() { return loadFactory(); } @Autowired - private RedisSslCredentialsConfiguration redisSslCredentials; + private RedisSslCredentials redisSslCredentials; protected abstract JedisConnectionFactory loadFactory(); @@ -176,57 +182,35 @@ public abstract class TBRedisCacheConfiguration { sslContext.init(keyManagerFactory == null ? null : keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null); return sslContext.getSocketFactory(); } catch (Exception e) { - throw new RuntimeException(e); + throw new RuntimeException("Creating TLS factory failed!", e); } } private TrustManagerFactory createAndInitTrustManagerFactory() throws Exception { - String type = redisSslCredentials.getType(); - if ("pem".equals(type)) { - RedisPemCredentialsConfig pemCredentials = redisSslCredentials.getPem(); - List caCerts = SslUtil.readCertFileByPath(pemCredentials.getCertFile()); - + List caCerts = SslUtil.readCertFileByPath(redisSslCredentials.getCertFile()); KeyStore caKeyStore = KeyStore.getInstance(KeyStore.getDefaultType()); caKeyStore.load(null, null); for (X509Certificate caCert : caCerts) { caKeyStore.setCertificateEntry("redis-caCert-cert-" + caCert.getSubjectX500Principal().getName(), caCert); } - TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("X509"); + TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); trustManagerFactory.init(caKeyStore); return trustManagerFactory; - } else if ("keystore".equals(type)) { - RedisKeystoreCredentialsConfig keystore = redisSslCredentials.getKeystore(); - KeyStore trustStore = KeyStore.getInstance(keystore.getKeystoreType()); - trustStore.load(new FileInputStream(keystore.getTruststoreLocation()), keystore.getTruststorePassword().toCharArray()); - - TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("X509"); - trustManagerFactory.init(trustStore); - return trustManagerFactory; - } else { - throw new RuntimeException(type + ": Invalid SSL credentials configuration. None of the PEM or KEYSTORE configurations can be used!"); - } } private KeyManagerFactory createAndInitKeyManagerFactory() throws Exception { - String type = redisSslCredentials.getType(); - if ("pem".equals(type)) { - RedisPemCredentialsConfig pemCredentials = redisSslCredentials.getPem(); - return getKeyManagerFactory(pemCredentials); - } else if ("keystore".equals(type)) { - RedisKeystoreCredentialsConfig keystore = redisSslCredentials.getKeystore(); - return getKeyManagerFactory(keystore); - } else { - throw new RuntimeException(type + ": Invalid SSL credentials configuration. None of the PEM or KEYSTORE configurations can be used!"); - } + KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + kmf.init(loadKeyStore(), null); + return kmf; } - private KeyManagerFactory getKeyManagerFactory(RedisPemCredentialsConfig pemCredentials) throws Exception { - if (pemCredentials.getUserCertFile().isBlank() || pemCredentials.getUserKeyFile().isBlank()) { + private KeyStore loadKeyStore() throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException { + if (redisSslCredentials.getUserCertFile().isBlank() || redisSslCredentials.getUserKeyFile().isBlank()) { return null; } - List certificates = SslUtil.readCertFileByPath(pemCredentials.getCertFile()); - PrivateKey privateKey = SslUtil.readPrivateKeyByFilePath(pemCredentials.getUserKeyFile(), null); + List certificates = SslUtil.readCertFileByPath(redisSslCredentials.getCertFile()); + PrivateKey privateKey = SslUtil.readPrivateKeyByFilePath(redisSslCredentials.getUserKeyFile(), null); KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); keyStore.load(null); @@ -242,21 +226,6 @@ public abstract class TBRedisCacheConfiguration { Certificate[] x509Certificates = path.toArray(new Certificate[0]); keyStore.setKeyEntry("redis-private-key", privateKey, null, x509Certificates); } - - KeyManagerFactory kmf = KeyManagerFactory.getInstance("PKIX"); - kmf.init(keyStore, null); - return kmf; - } - - private KeyManagerFactory getKeyManagerFactory(RedisKeystoreCredentialsConfig keystore) throws Exception { - if (keystore.getKeystoreLocation().isBlank() || keystore.getKeystoreLocation().isBlank()) { - return null; - } - KeyStore keyStore = KeyStore.getInstance(keystore.getKeystoreType()); - keyStore.load(new FileInputStream(keystore.getKeystoreLocation()), keystore.getKeystorePassword().toCharArray()); - - KeyManagerFactory kmf = KeyManagerFactory.getInstance("PKIX"); - kmf.init(keyStore, keystore.getKeystorePassword().toCharArray()); - return kmf; + return keyStore; } } diff --git a/common/util/src/main/java/org/thingsboard/common/util/SslUtil.java b/common/util/src/main/java/org/thingsboard/common/util/SslUtil.java index e520e946ec..a62870ea9b 100644 --- a/common/util/src/main/java/org/thingsboard/common/util/SslUtil.java +++ b/common/util/src/main/java/org/thingsboard/common/util/SslUtil.java @@ -129,4 +129,5 @@ public class SslUtil { } return privateKey; } + } diff --git a/msa/black-box-tests/README.md b/msa/black-box-tests/README.md index 340f0d0eb8..31277e2a55 100644 --- a/msa/black-box-tests/README.md +++ b/msa/black-box-tests/README.md @@ -22,6 +22,10 @@ As result, in REPOSITORY column, next images should be present: mvn clean install -DblackBoxTests.skip=false +- Run the black box tests (without ui tests) in the [msa/black-box-tests](../black-box-tests) directory with Redis standalone with TLS: + + mvn clean install -DblackBoxTests.skip=false -DblackBoxTests.redisSsl=true + - Run the black box tests in the [msa/black-box-tests](../black-box-tests) directory with Redis cluster: mvn clean install -DblackBoxTests.skip=false -DblackBoxTests.redisCluster=true diff --git a/transport/coap/src/main/resources/tb-coap-transport.yml b/transport/coap/src/main/resources/tb-coap-transport.yml index 78ca89851d..3934acfb87 100644 --- a/transport/coap/src/main/resources/tb-coap-transport.yml +++ b/transport/coap/src/main/resources/tb-coap-transport.yml @@ -97,32 +97,14 @@ redis: ssl: # Enable/disable secure connection enabled: "${TB_REDIS_SSL_ENABLED:false}" - # Server SSL credentials + # Server SSL credentials (only PEM format is supported) credentials: - # Server credentials type (pem - pem certificate file; keystore - java keystore) - type: "${TB_REDIS_SSL_CREDENTIALS_TYPE:pem}" - # PEM server credentials - pem: - # Path redis server (CA) certificate - cert_file: "${TB_REDIS_SSL_PEM_CERT:}" - # Path to user certificate file. This is optional for the client and can be used for two-way authentication for the client - user_cert_file: "${TB_REDIS_SSL_PEM_KEY:}" - # Path to user private key file. This is optional for the client and only needed if ‘ssl.pem.user_cert_file’ is configured. - user_key_file: "${TB_REDIS_SSL_PEM_KEY_PASSWORD:}" - # Keystore server credentials - keystore: - # Type of the trust store (JKS or PKCS12) - truststore_type: "${TB_REDIS_SSL_KEY_STORE_TYPE:JKS}" - # The location of the trust store file - truststore_location: "${TB_REDIS_SSL_TRUSTSTORE_LOCATION:}" - # The password of trust store file if specified - truststore_password: "${TB_REDIS_SSL_TRUSTSTORE_PASSWORD:}" - # Type of the key store (JKS or PKCS12) - keystore_type: "${TB_REDIS_SSL_KEY_STORE_TYPE:JKS}" - # The location of the key store file. This is optional for the client and can be used for two-way authentication for the client - keystore_location: "${TB_REDIS_SSL_KEYSTORE_LOCATION:}" - # The store password for the key store file. This is optional for the client and only needed if ‘ssl.keystore.location’ is configured. Key store password is not supported for PEM format - keystore_password: "${TB_REDIS_SSL_KEYSTORE_PASSWORD:}" + # Path redis server (CA) certificate + cert_file: "${TB_REDIS_SSL_PEM_CERT:}" + # Path to user certificate file. This is optional for the client and can be used for two-way authentication for the client + user_cert_file: "${TB_REDIS_SSL_PEM_KEY:}" + # Path to user private key file. This is optional for the client and only needed if ‘user_cert_file’ is configured. + user_key_file: "${TB_REDIS_SSL_PEM_KEY_PASSWORD:}" # pool config pool_config: # Maximum number of connections that can be allocated by the connection pool diff --git a/transport/http/src/main/resources/tb-http-transport.yml b/transport/http/src/main/resources/tb-http-transport.yml index 04a9c9417f..556c004bf8 100644 --- a/transport/http/src/main/resources/tb-http-transport.yml +++ b/transport/http/src/main/resources/tb-http-transport.yml @@ -130,32 +130,14 @@ redis: ssl: # Enable/disable secure connection enabled: "${TB_REDIS_SSL_ENABLED:false}" - # Server SSL credentials + # Server SSL credentials (only PEM format is supported) credentials: - # Server credentials type (pem - pem certificate file; keystore - java keystore) - type: "${TB_REDIS_SSL_CREDENTIALS_TYPE:pem}" - # PEM server credentials - pem: - # Path redis server (CA) certificate - cert_file: "${TB_REDIS_SSL_PEM_CERT:}" - # Path to user certificate file. This is optional for the client and can be used for two-way authentication for the client - user_cert_file: "${TB_REDIS_SSL_PEM_KEY:}" - # Path to user private key file. This is optional for the client and only needed if ‘ssl.pem.user_cert_file’ is configured. - user_key_file: "${TB_REDIS_SSL_PEM_KEY_PASSWORD:}" - # Keystore server credentials - keystore: - # Type of the trust store (JKS or PKCS12) - truststore_type: "${TB_REDIS_SSL_KEY_STORE_TYPE:JKS}" - # The location of the trust store file - truststore_location: "${TB_REDIS_SSL_TRUSTSTORE_LOCATION:}" - # The password of trust store file if specified - truststore_password: "${TB_REDIS_SSL_TRUSTSTORE_PASSWORD:}" - # Type of the key store (JKS or PKCS12) - keystore_type: "${TB_REDIS_SSL_KEY_STORE_TYPE:JKS}" - # The location of the key store file. This is optional for the client and can be used for two-way authentication for the client - keystore_location: "${TB_REDIS_SSL_KEYSTORE_LOCATION:}" - # The store password for the key store file. This is optional for the client and only needed if ‘ssl.keystore.location’ is configured. Key store password is not supported for PEM format - keystore_password: "${TB_REDIS_SSL_KEYSTORE_PASSWORD:}" + # Path redis server (CA) certificate + cert_file: "${TB_REDIS_SSL_PEM_CERT:}" + # Path to user certificate file. This is optional for the client and can be used for two-way authentication for the client + user_cert_file: "${TB_REDIS_SSL_PEM_KEY:}" + # Path to user private key file. This is optional for the client and only needed if ‘user_cert_file’ is configured. + user_key_file: "${TB_REDIS_SSL_PEM_KEY_PASSWORD:}" # pool config pool_config: # Maximum number of connections that can be allocated by the connection pool diff --git a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml index c079f690ed..6d7257d7f9 100644 --- a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml +++ b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml @@ -97,32 +97,14 @@ redis: ssl: # Enable/disable secure connection enabled: "${TB_REDIS_SSL_ENABLED:false}" - # Server SSL credentials + # Server SSL credentials (only PEM format is supported) credentials: - # Server credentials type (pem - pem certificate file; keystore - java keystore) - type: "${TB_REDIS_SSL_CREDENTIALS_TYPE:pem}" - # PEM server credentials - pem: - # Path redis server (CA) certificate - cert_file: "${TB_REDIS_SSL_PEM_CERT:}" - # Path to user certificate file. This is optional for the client and can be used for two-way authentication for the client - user_cert_file: "${TB_REDIS_SSL_PEM_KEY:}" - # Path to user private key file. This is optional for the client and only needed if ‘ssl.pem.user_cert_file’ is configured. - user_key_file: "${TB_REDIS_SSL_PEM_KEY_PASSWORD:}" - # Keystore server credentials - keystore: - # Type of the trust store (JKS or PKCS12) - truststore_type: "${TB_REDIS_SSL_KEY_STORE_TYPE:JKS}" - # The location of the trust store file - truststore_location: "${TB_REDIS_SSL_TRUSTSTORE_LOCATION:}" - # The password of trust store file if specified - truststore_password: "${TB_REDIS_SSL_TRUSTSTORE_PASSWORD:}" - # Type of the key store (JKS or PKCS12) - keystore_type: "${TB_REDIS_SSL_KEY_STORE_TYPE:JKS}" - # The location of the key store file. This is optional for the client and can be used for two-way authentication for the client - keystore_location: "${TB_REDIS_SSL_KEYSTORE_LOCATION:}" - # The store password for the key store file. This is optional for the client and only needed if ‘ssl.keystore.location’ is configured. Key store password is not supported for PEM format - keystore_password: "${TB_REDIS_SSL_KEYSTORE_PASSWORD:}" + # Path redis server (CA) certificate + cert_file: "${TB_REDIS_SSL_PEM_CERT:}" + # Path to user certificate file. This is optional for the client and can be used for two-way authentication for the client + user_cert_file: "${TB_REDIS_SSL_PEM_KEY:}" + # Path to user private key file. This is optional for the client and only needed if ‘user_cert_file’ is configured. + user_key_file: "${TB_REDIS_SSL_PEM_KEY_PASSWORD:}" # pool config pool_config: # Maximum number of connections that can be allocated by the connection pool diff --git a/transport/mqtt/src/main/resources/tb-mqtt-transport.yml b/transport/mqtt/src/main/resources/tb-mqtt-transport.yml index 430b5bfed5..41d96ff9d7 100644 --- a/transport/mqtt/src/main/resources/tb-mqtt-transport.yml +++ b/transport/mqtt/src/main/resources/tb-mqtt-transport.yml @@ -98,32 +98,14 @@ redis: ssl: # Enable/disable secure connection enabled: "${TB_REDIS_SSL_ENABLED:false}" - # Server SSL credentials + # Server SSL credentials (only PEM format is supported) credentials: - # Server credentials type (pem - pem certificate file; keystore - java keystore) - type: "${TB_REDIS_SSL_CREDENTIALS_TYPE:pem}" - # PEM server credentials - pem: - # Path redis server (CA) certificate - cert_file: "${TB_REDIS_SSL_PEM_CERT:}" - # Path to user certificate file. This is optional for the client and can be used for two-way authentication for the client - user_cert_file: "${TB_REDIS_SSL_PEM_KEY:}" - # Path to user private key file. This is optional for the client and only needed if ‘ssl.pem.user_cert_file’ is configured. - user_key_file: "${TB_REDIS_SSL_PEM_KEY_PASSWORD:}" - # Keystore server credentials - keystore: - # Type of the trust store (JKS or PKCS12) - truststore_type: "${TB_REDIS_SSL_KEY_STORE_TYPE:JKS}" - # The location of the trust store file - truststore_location: "${TB_REDIS_SSL_TRUSTSTORE_LOCATION:}" - # The password of trust store file if specified - truststore_password: "${TB_REDIS_SSL_TRUSTSTORE_PASSWORD:}" - # Type of the key store (JKS or PKCS12) - keystore_type: "${TB_REDIS_SSL_KEY_STORE_TYPE:JKS}" - # The location of the key store file. This is optional for the client and can be used for two-way authentication for the client - keystore_location: "${TB_REDIS_SSL_KEYSTORE_LOCATION:}" - # The store password for the key store file. This is optional for the client and only needed if ‘ssl.keystore.location’ is configured. Key store password is not supported for PEM format - keystore_password: "${TB_REDIS_SSL_KEYSTORE_PASSWORD:}" + # Path redis server (CA) certificate + cert_file: "${TB_REDIS_SSL_PEM_CERT:}" + # Path to user certificate file. This is optional for the client and can be used for two-way authentication for the client + user_cert_file: "${TB_REDIS_SSL_PEM_KEY:}" + # Path to user private key file. This is optional for the client and only needed if ‘user_cert_file’ is configured. + user_key_file: "${TB_REDIS_SSL_PEM_KEY_PASSWORD:}" # pool config pool_config: # Maximum number of connections that can be allocated by the connection pool diff --git a/transport/snmp/src/main/resources/tb-snmp-transport.yml b/transport/snmp/src/main/resources/tb-snmp-transport.yml index 68b69bb03a..971237efe0 100644 --- a/transport/snmp/src/main/resources/tb-snmp-transport.yml +++ b/transport/snmp/src/main/resources/tb-snmp-transport.yml @@ -97,32 +97,14 @@ redis: ssl: # Enable/disable secure connection enabled: "${TB_REDIS_SSL_ENABLED:false}" - # Server SSL credentials + # Server SSL credentials (only PEM format is supported) credentials: - # Server credentials type (pem - pem certificate file; keystore - java keystore) - type: "${TB_REDIS_SSL_CREDENTIALS_TYPE:pem}" - # PEM server credentials - pem: - # Path redis server (CA) certificate - cert_file: "${TB_REDIS_SSL_PEM_CERT:}" - # Path to user certificate file. This is optional for the client and can be used for two-way authentication for the client - user_cert_file: "${TB_REDIS_SSL_PEM_KEY:}" - # Path to user private key file. This is optional for the client and only needed if ‘ssl.pem.user_cert_file’ is configured. - user_key_file: "${TB_REDIS_SSL_PEM_KEY_PASSWORD:}" - # Keystore server credentials - keystore: - # Type of the trust store (JKS or PKCS12) - truststore_type: "${TB_REDIS_SSL_KEY_STORE_TYPE:JKS}" - # The location of the trust store file - truststore_location: "${TB_REDIS_SSL_TRUSTSTORE_LOCATION:}" - # The password of trust store file if specified - truststore_password: "${TB_REDIS_SSL_TRUSTSTORE_PASSWORD:}" - # Type of the key store (JKS or PKCS12) - keystore_type: "${TB_REDIS_SSL_KEY_STORE_TYPE:JKS}" - # The location of the key store file. This is optional for the client and can be used for two-way authentication for the client - keystore_location: "${TB_REDIS_SSL_KEYSTORE_LOCATION:}" - # The store password for the key store file. This is optional for the client and only needed if ‘ssl.keystore.location’ is configured. Key store password is not supported for PEM format - keystore_password: "${TB_REDIS_SSL_KEYSTORE_PASSWORD:}" + # Path redis server (CA) certificate + cert_file: "${TB_REDIS_SSL_PEM_CERT:}" + # Path to user certificate file. This is optional for the client and can be used for two-way authentication for the client + user_cert_file: "${TB_REDIS_SSL_PEM_KEY:}" + # Path to user private key file. This is optional for the client and only needed if ‘user_cert_file’ is configured. + user_key_file: "${TB_REDIS_SSL_PEM_KEY_PASSWORD:}" # pool config pool_config: # Maximum number of connections that can be allocated by the connection pool