Browse Source

Merge pull request #9225 from dashevchenko/tls_for_redis

Added ssl support for redis
pull/10158/head
Andrew Shvayka 3 years ago
committed by GitHub
parent
commit
1673d3d065
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 12
      application/src/main/resources/thingsboard.yml
  2. 32
      common/cache/src/main/java/org/thingsboard/server/cache/RedisSslCredentials.java
  3. 79
      common/cache/src/main/java/org/thingsboard/server/cache/TBRedisCacheConfiguration.java
  4. 23
      common/cache/src/main/java/org/thingsboard/server/cache/TBRedisClusterConfiguration.java
  5. 24
      common/cache/src/main/java/org/thingsboard/server/cache/TBRedisSentinelConfiguration.java
  6. 36
      common/cache/src/main/java/org/thingsboard/server/cache/TBRedisStandaloneConfiguration.java
  7. 70
      common/util/src/main/java/org/thingsboard/common/util/SslUtil.java
  8. 4
      msa/black-box-tests/README.md
  9. 23
      msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ContainerTestSuite.java
  10. 27
      msa/black-box-tests/src/test/resources/docker-compose.redis-ssl.volumes.yml
  11. 129
      msa/black-box-tests/src/test/resources/docker-compose.redis-ssl.yml
  12. 28
      msa/black-box-tests/src/test/resources/redis-certs/redis.crt
  13. 28
      msa/black-box-tests/src/test/resources/redis-certs/redis.key
  14. 32
      msa/black-box-tests/src/test/resources/redis-certs/redisCA.crt
  15. 11
      transport/coap/src/main/resources/tb-coap-transport.yml
  16. 11
      transport/http/src/main/resources/tb-http-transport.yml
  17. 11
      transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml
  18. 11
      transport/mqtt/src/main/resources/tb-mqtt-transport.yml
  19. 11
      transport/snmp/src/main/resources/tb-snmp-transport.yml

12
application/src/main/resources/thingsboard.yml

@ -639,6 +639,18 @@ redis:
db: "${REDIS_DB:0}" db: "${REDIS_DB:0}"
# db password # db password
password: "${REDIS_PASSWORD:}" password: "${REDIS_PASSWORD:}"
# ssl config
ssl:
# Enable/disable secure connection
enabled: "${TB_REDIS_SSL_ENABLED:false}"
# Server SSL credentials (only PEM format is supported)
credentials:
# 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
pool_config: pool_config:
# Maximum number of connections that can be allocated by the connection pool # Maximum number of connections that can be allocated by the connection pool

32
common/cache/src/main/java/org/thingsboard/server/cache/RedisSslCredentials.java

@ -0,0 +1,32 @@
/**
* 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 RedisSslCredentials {
private String certFile;
private String userCertFile;
private String userKeyFile;
}

79
common/cache/src/main/java/org/thingsboard/server/cache/TBRedisCacheConfiguration.java

@ -16,6 +16,8 @@
package org.thingsboard.server.cache; package org.thingsboard.server.cache;
import lombok.Data; 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.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cache.CacheManager; import org.springframework.cache.CacheManager;
@ -31,10 +33,25 @@ import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.format.support.DefaultFormattingConversionService; import org.springframework.format.support.DefaultFormattingConversionService;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.thingsboard.common.util.SslUtil;
import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import redis.clients.jedis.JedisPoolConfig; 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.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; import java.time.Duration;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@ -44,6 +61,7 @@ import java.util.List;
@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "redis") @ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "redis")
@EnableCaching @EnableCaching
@Data @Data
@Slf4j
public abstract class TBRedisCacheConfiguration { public abstract class TBRedisCacheConfiguration {
private static final String COMMA = ","; private static final String COMMA = ",";
@ -85,11 +103,17 @@ public abstract class TBRedisCacheConfiguration {
@Value("${redis.pool_config.blockWhenExhausted:true}") @Value("${redis.pool_config.blockWhenExhausted:true}")
private boolean blockWhenExhausted; private boolean blockWhenExhausted;
@Value("${redis.ssl.enabled:false}")
private boolean sslEnabled;
@Bean @Bean
public RedisConnectionFactory redisConnectionFactory() { public RedisConnectionFactory redisConnectionFactory() {
return loadFactory(); return loadFactory();
} }
@Autowired
private RedisSslCredentials redisSslCredentials;
protected abstract JedisConnectionFactory loadFactory(); protected abstract JedisConnectionFactory loadFactory();
/** /**
@ -149,4 +173,59 @@ public abstract class TBRedisCacheConfiguration {
} }
return result; return result;
} }
protected SSLSocketFactory createSslSocketFactory() {
try {
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("Creating TLS factory failed!", e);
}
}
private TrustManagerFactory createAndInitTrustManagerFactory() throws Exception {
List<X509Certificate> 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(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(caKeyStore);
return trustManagerFactory;
}
private KeyManagerFactory createAndInitKeyManagerFactory() throws Exception {
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(loadKeyStore(), null);
return kmf;
}
private KeyStore loadKeyStore() throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
if (redisSslCredentials.getUserCertFile().isBlank() || redisSslCredentials.getUserKeyFile().isBlank()) {
return null;
}
List<X509Certificate> certificates = SslUtil.readCertFileByPath(redisSslCredentials.getCertFile());
PrivateKey privateKey = SslUtil.readPrivateKeyByFilePath(redisSslCredentials.getUserKeyFile(), null);
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null);
List<X509Certificate> unique = certificates.stream().distinct().toList();
for (X509Certificate cert : unique) {
keyStore.setCertificateEntry("redis-cert" + cert.getSubjectX500Principal().getName(), cert);
}
if (privateKey != null) {
CertificateFactory factory = CertificateFactory.getInstance("X.509");
CertPath certPath = factory.generateCertPath(certificates);
List<? extends Certificate> path = certPath.getCertificates();
Certificate[] x509Certificates = path.toArray(new Certificate[0]);
keyStore.setKeyEntry("redis-private-key", privateKey, null, x509Certificates);
}
return keyStore;
}
} }

23
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.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisClusterConfiguration; import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
@Configuration @Configuration
@ -39,15 +40,29 @@ public class TBRedisClusterConfiguration extends TBRedisCacheConfiguration {
@Value("${redis.password:}") @Value("${redis.password:}")
private String password; private String password;
@Value("${redis.ssl.enabled:false}")
private boolean useSsl;
public JedisConnectionFactory loadFactory() { public JedisConnectionFactory loadFactory() {
RedisClusterConfiguration clusterConfiguration = new RedisClusterConfiguration(); RedisClusterConfiguration clusterConfiguration = new RedisClusterConfiguration();
clusterConfiguration.setClusterNodes(getNodes(clusterNodes)); clusterConfiguration.setClusterNodes(getNodes(clusterNodes));
clusterConfiguration.setMaxRedirects(maxRedirects); clusterConfiguration.setMaxRedirects(maxRedirects);
clusterConfiguration.setPassword(password); clusterConfiguration.setPassword(password);
if (useDefaultPoolConfig) { return new JedisConnectionFactory(clusterConfiguration, buildClientConfig());
return new JedisConnectionFactory(clusterConfiguration); }
} else {
return new JedisConnectionFactory(clusterConfiguration, buildPoolConfig()); private JedisClientConfiguration buildClientConfig() {
JedisClientConfiguration.JedisClientConfigurationBuilder jedisClientConfigurationBuilder = JedisClientConfiguration.builder();
if (!useDefaultPoolConfig) {
jedisClientConfigurationBuilder
.usePooling()
.poolConfig(buildPoolConfig());
}
if (useSsl) {
jedisClientConfigurationBuilder
.useSsl()
.sslSocketFactory(createSslSocketFactory());
} }
return jedisClientConfigurationBuilder.build();
} }
} }

24
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.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisSentinelConfiguration; import org.springframework.data.redis.connection.RedisSentinelConfiguration;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
@Configuration @Configuration
@ -42,6 +43,9 @@ public class TBRedisSentinelConfiguration extends TBRedisCacheConfiguration {
@Value("${redis.db:}") @Value("${redis.db:}")
private Integer database; private Integer database;
@Value("${redis.ssl.enabled:false}")
private boolean useSsl;
@Value("${redis.password:}") @Value("${redis.password:}")
private String password; private String password;
@ -52,11 +56,21 @@ public class TBRedisSentinelConfiguration extends TBRedisCacheConfiguration {
redisSentinelConfiguration.setSentinelPassword(sentinelPassword); redisSentinelConfiguration.setSentinelPassword(sentinelPassword);
redisSentinelConfiguration.setPassword(password); redisSentinelConfiguration.setPassword(password);
redisSentinelConfiguration.setDatabase(database); redisSentinelConfiguration.setDatabase(database);
if (useDefaultPoolConfig) { return new JedisConnectionFactory(redisSentinelConfiguration, buildClientConfig());
return new JedisConnectionFactory(redisSentinelConfiguration);
} else {
return new JedisConnectionFactory(redisSentinelConfiguration, buildPoolConfig());
}
} }
private JedisClientConfiguration buildClientConfig() {
JedisClientConfiguration.JedisClientConfigurationBuilder jedisClientConfigurationBuilder = JedisClientConfiguration.builder();
if (!useDefaultPoolConfig) {
jedisClientConfigurationBuilder
.usePooling()
.poolConfig(buildPoolConfig());
}
if (useSsl) {
jedisClientConfigurationBuilder
.useSsl()
.sslSocketFactory(createSslSocketFactory());
}
return jedisClientConfigurationBuilder.build();
}
} }

36
common/cache/src/main/java/org/thingsboard/server/cache/TBRedisStandaloneConfiguration.java

@ -57,32 +57,36 @@ public class TBRedisStandaloneConfiguration extends TBRedisCacheConfiguration {
@Value("${redis.password:}") @Value("${redis.password:}")
private String password; private String password;
@Value("${redis.ssl.enabled:false}")
private boolean useSsl;
public JedisConnectionFactory loadFactory() { public JedisConnectionFactory loadFactory() {
RedisStandaloneConfiguration standaloneConfiguration = new RedisStandaloneConfiguration(); RedisStandaloneConfiguration standaloneConfiguration = new RedisStandaloneConfiguration();
standaloneConfiguration.setHostName(host); standaloneConfiguration.setHostName(host);
standaloneConfiguration.setPort(port); standaloneConfiguration.setPort(port);
standaloneConfiguration.setDatabase(db); standaloneConfiguration.setDatabase(db);
standaloneConfiguration.setPassword(password); standaloneConfiguration.setPassword(password);
if (useDefaultClientConfig) { return new JedisConnectionFactory(standaloneConfiguration, buildClientConfig());
return new JedisConnectionFactory(standaloneConfiguration);
} else {
return new JedisConnectionFactory(standaloneConfiguration, buildClientConfig());
}
} }
private JedisClientConfiguration buildClientConfig() { private JedisClientConfiguration buildClientConfig() {
if (usePoolConfig) { JedisClientConfiguration.JedisClientConfigurationBuilder jedisClientConfigurationBuilder = JedisClientConfiguration.builder();
return JedisClientConfiguration.builder() if (!useDefaultClientConfig) {
.clientName(clientName) jedisClientConfigurationBuilder
.connectTimeout(Duration.ofMillis(connectTimeout))
.readTimeout(Duration.ofMillis(readTimeout))
.usePooling().poolConfig(buildPoolConfig())
.build();
} else {
return JedisClientConfiguration.builder()
.clientName(clientName) .clientName(clientName)
.connectTimeout(Duration.ofMillis(connectTimeout)) .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();
} }
} }

70
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.openssl.jcajce.JcePEMDecryptorProviderBuilder;
import org.bouncycastle.operator.InputDecryptorProvider; import org.bouncycastle.operator.InputDecryptorProvider;
import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo; import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo;
import org.bouncycastle.pkcs.PKCSException;
import org.bouncycastle.pkcs.jcajce.JcePKCSPBEInputDecryptorProviderBuilder; import org.bouncycastle.pkcs.jcajce.JcePKCSPBEInputDecryptorProviderBuilder;
import org.thingsboard.server.common.data.StringUtils; 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.io.StringReader;
import java.security.PrivateKey; import java.security.PrivateKey;
import java.security.Security; import java.security.Security;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -57,9 +62,18 @@ public class SslUtil {
@SneakyThrows @SneakyThrows
public static List<X509Certificate> readCertFile(String fileContent) { public static List<X509Certificate> readCertFile(String fileContent) {
return readCertFile(new StringReader(fileContent));
}
@SneakyThrows
public static List<X509Certificate> readCertFileByPath(String filePath) {
return readCertFile( new FileReader(filePath));
}
private static List<X509Certificate> readCertFile(Reader reader) throws IOException, CertificateException {
List<X509Certificate> certificates = new ArrayList<>(); List<X509Certificate> certificates = new ArrayList<>();
JcaX509CertificateConverter certConverter = new JcaX509CertificateConverter(); JcaX509CertificateConverter certConverter = new JcaX509CertificateConverter();
try (PEMParser pemParser = new PEMParser(new StringReader(fileContent))) { try (PEMParser pemParser = new PEMParser(reader)) {
Object object; Object object;
while ((object = pemParser.readObject()) != null) { while ((object = pemParser.readObject()) != null) {
if (object instanceof X509CertificateHolder) { if (object instanceof X509CertificateHolder) {
@ -73,29 +87,43 @@ public class SslUtil {
@SneakyThrows @SneakyThrows
public static PrivateKey readPrivateKey(String fileContent, String passStr) { 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; PrivateKey privateKey = null;
JcaPEMKeyConverter keyConverter = new JcaPEMKeyConverter(); JcaPEMKeyConverter keyConverter = new JcaPEMKeyConverter();
if (StringUtils.isNotEmpty(fileContent)) { try (PEMParser pemParser = new PEMParser(reader)) {
try (PEMParser pemParser = new PEMParser(new StringReader(fileContent))) { Object object;
Object object; while ((object = pemParser.readObject()) != null) {
while ((object = pemParser.readObject()) != null) { if (object instanceof PEMEncryptedKeyPair) {
if (object instanceof PEMEncryptedKeyPair) { PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder().build(password);
PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder().build(password); privateKey = keyConverter.getKeyPair(((PEMEncryptedKeyPair) object).decryptKeyPair(decProv)).getPrivate();
privateKey = keyConverter.getKeyPair(((PEMEncryptedKeyPair) object).decryptKeyPair(decProv)).getPrivate(); break;
break; } else if (object instanceof PKCS8EncryptedPrivateKeyInfo) {
} else if (object instanceof PKCS8EncryptedPrivateKeyInfo) { InputDecryptorProvider decProv =
InputDecryptorProvider decProv = new JcePKCSPBEInputDecryptorProviderBuilder().setProvider(DEFAULT_PROVIDER).build(password);
new JcePKCSPBEInputDecryptorProviderBuilder().setProvider(DEFAULT_PROVIDER).build(password); privateKey = keyConverter.getPrivateKey(((PKCS8EncryptedPrivateKeyInfo) object).decryptPrivateKeyInfo(decProv));
privateKey = keyConverter.getPrivateKey(((PKCS8EncryptedPrivateKeyInfo) object).decryptPrivateKeyInfo(decProv)); break;
break; } else if (object instanceof PEMKeyPair) {
} else if (object instanceof PEMKeyPair) { privateKey = keyConverter.getKeyPair((PEMKeyPair) object).getPrivate();
privateKey = keyConverter.getKeyPair((PEMKeyPair) object).getPrivate(); break;
break; } else if (object instanceof PrivateKeyInfo) {
} else if (object instanceof PrivateKeyInfo) { privateKey = keyConverter.getPrivateKey((PrivateKeyInfo) object);
privateKey = keyConverter.getPrivateKey((PrivateKeyInfo) object);
}
} }
} }
} }

4
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 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: - 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 mvn clean install -DblackBoxTests.skip=false -DblackBoxTests.redisCluster=true

23
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 { public class ContainerTestSuite {
final static boolean IS_REDIS_CLUSTER = Boolean.parseBoolean(System.getProperty("blackBoxTests.redisCluster")); 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_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 boolean IS_HYBRID_MODE = Boolean.parseBoolean(System.getProperty("blackBoxTests.hybridMode"));
final static String QUEUE_TYPE = System.getProperty("blackBoxTests.queue", "kafka"); final static String QUEUE_TYPE = System.getProperty("blackBoxTests.queue", "kafka");
private static final String SOURCE_DIR = "./../../docker/"; private static final String SOURCE_DIR = "./../../docker/";
@ -82,6 +83,7 @@ public class ContainerTestSuite {
installTb.createVolumes(); installTb.createVolumes();
log.info("System property of blackBoxTests.redisCluster is {}", IS_REDIS_CLUSTER); 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.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); log.info("System property of blackBoxTests.hybridMode is {}", IS_HYBRID_MODE);
boolean skipTailChildContainers = Boolean.parseBoolean(System.getProperty("blackBoxTests.skipTailChildContainers")); boolean skipTailChildContainers = Boolean.parseBoolean(System.getProperty("blackBoxTests.skipTailChildContainers"));
try { try {
@ -104,6 +106,12 @@ public class ContainerTestSuite {
} }
} }
if (IS_REDIS_SSL) {
addToFile(targetDir, "cache-redis.env",
Map.of("TB_REDIS_SSL_ENABLED", "true",
"TB_REDIS_SSL_PEM_CERT", "/redis/certs/redisCA.crt"));
}
List<File> composeFiles = new ArrayList<>(Arrays.asList( List<File> composeFiles = new ArrayList<>(Arrays.asList(
new File(targetDir + "docker-compose.yml"), new File(targetDir + "docker-compose.yml"),
new File(targetDir + "docker-compose.volumes.yml"), new File(targetDir + "docker-compose.volumes.yml"),
@ -188,6 +196,9 @@ public class ContainerTestSuite {
if (IS_REDIS_SENTINEL) { if (IS_REDIS_SENTINEL) {
return "docker-compose.redis-sentinel.yml"; return "docker-compose.redis-sentinel.yml";
} }
if (IS_REDIS_SSL) {
return "docker-compose.redis-ssl.yml";
}
return "docker-compose.redis.yml"; return "docker-compose.redis.yml";
} }
@ -198,6 +209,9 @@ public class ContainerTestSuite {
if (IS_REDIS_SENTINEL) { if (IS_REDIS_SENTINEL) {
return "docker-compose.redis-sentinel.volumes.yml"; return "docker-compose.redis-sentinel.volumes.yml";
} }
if (IS_REDIS_SSL) {
return "docker-compose.redis-ssl.volumes.yml";
}
return "docker-compose.redis.volumes.yml"; return "docker-compose.redis.volumes.yml";
} }
@ -218,6 +232,15 @@ public class ContainerTestSuite {
Files.write(envFilePath, data.getBytes(StandardCharsets.UTF_8)); Files.write(envFilePath, data.getBytes(StandardCharsets.UTF_8));
} }
private static void addToFile(String targetDir, String fileName, Map<String, String> 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) { private static String getSysProp(String propertyName) {
var value = System.getProperty(propertyName); var value = System.getProperty(propertyName);
if (StringUtils.isEmpty(value)) { if (StringUtils.isEmpty(value)) {

27
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}

129
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

28
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-----

28
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-----

32
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-----

11
transport/coap/src/main/resources/tb-coap-transport.yml

@ -94,6 +94,17 @@ redis:
db: "${REDIS_DB:0}" db: "${REDIS_DB:0}"
# db password # db password
password: "${REDIS_PASSWORD:}" password: "${REDIS_PASSWORD:}"
ssl:
# Enable/disable secure connection
enabled: "${TB_REDIS_SSL_ENABLED:false}"
# Server SSL credentials (only PEM format is supported)
credentials:
# 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
pool_config: pool_config:
# Maximum number of connections that can be allocated by the connection pool # Maximum number of connections that can be allocated by the connection pool

11
transport/http/src/main/resources/tb-http-transport.yml

@ -127,6 +127,17 @@ redis:
db: "${REDIS_DB:0}" db: "${REDIS_DB:0}"
# db password # db password
password: "${REDIS_PASSWORD:}" password: "${REDIS_PASSWORD:}"
ssl:
# Enable/disable secure connection
enabled: "${TB_REDIS_SSL_ENABLED:false}"
# Server SSL credentials (only PEM format is supported)
credentials:
# 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
pool_config: pool_config:
# Maximum number of connections that can be allocated by the connection pool # Maximum number of connections that can be allocated by the connection pool

11
transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml

@ -94,6 +94,17 @@ redis:
db: "${REDIS_DB:0}" db: "${REDIS_DB:0}"
# db password # db password
password: "${REDIS_PASSWORD:}" password: "${REDIS_PASSWORD:}"
ssl:
# Enable/disable secure connection
enabled: "${TB_REDIS_SSL_ENABLED:false}"
# Server SSL credentials (only PEM format is supported)
credentials:
# 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
pool_config: pool_config:
# Maximum number of connections that can be allocated by the connection pool # Maximum number of connections that can be allocated by the connection pool

11
transport/mqtt/src/main/resources/tb-mqtt-transport.yml

@ -95,6 +95,17 @@ redis:
db: "${REDIS_DB:0}" db: "${REDIS_DB:0}"
# db password # db password
password: "${REDIS_PASSWORD:}" password: "${REDIS_PASSWORD:}"
ssl:
# Enable/disable secure connection
enabled: "${TB_REDIS_SSL_ENABLED:false}"
# Server SSL credentials (only PEM format is supported)
credentials:
# 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
pool_config: pool_config:
# Maximum number of connections that can be allocated by the connection pool # Maximum number of connections that can be allocated by the connection pool

11
transport/snmp/src/main/resources/tb-snmp-transport.yml

@ -94,6 +94,17 @@ redis:
db: "${REDIS_DB:0}" db: "${REDIS_DB:0}"
# db password # db password
password: "${REDIS_PASSWORD:}" password: "${REDIS_PASSWORD:}"
ssl:
# Enable/disable secure connection
enabled: "${TB_REDIS_SSL_ENABLED:false}"
# Server SSL credentials (only PEM format is supported)
credentials:
# 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
pool_config: pool_config:
# Maximum number of connections that can be allocated by the connection pool # Maximum number of connections that can be allocated by the connection pool

Loading…
Cancel
Save