Skip to content
This repository has been archived by the owner on Dec 13, 2023. It is now read-only.

Redis password authentication support #2950

Merged
merged 2 commits into from
May 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions docs/docs/how-tos/redis.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Redis Configuration

By default conductor runs with an in-memory Redis mock. However, you
can change the configuration by setting the properties `conductor.db.type` and `conductor.redis.hosts`.

## `conductor.db.type`

| Value | Description |
|--------------------------------|----------------------------------------------------------------------------------------|
| dynomite | Dynomite Cluster. Dynomite is a proxy layer that provides sharding and replication. |
| memory | Uses an in-memory Redis mock. Should be used only for development and testing purposes.|
| redis_cluster | Redis Cluster configuration. |
| redis_sentinel | Redis Sentinel configuration. |
| redis_standalone | Redis Standalone configuration. |



## `conductor.redis.hosts`

Expected format is `host:port:rack` separated by semicolon, e.g.:

```properties
conductor.redis.hosts=host0:6379:us-east-1c;host1:6379:us-east-1c;host2:6379:us-east-1c
```

### Auth Support

Password authentication is supported. The password should be set as the 4th param of the first host `host:port:rack:password`, e.g.:

```properties
conductor.redis.hosts=host0:6379:us-east-1c:my_str0ng_pazz;host1:6379:us-east-1c;host2:6379:us-east-1c
```


**Notes**

- In a cluster, all nodes use the same password.
- In a sentinel configuration, sentinels and redis nodes use the same password.
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,35 @@
*/
package com.netflix.conductor.redis.config;

import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;

import com.netflix.conductor.core.config.ConductorProperties;
import com.netflix.conductor.redis.jedis.JedisCluster;
import com.netflix.dyno.connectionpool.Host;
import com.netflix.dyno.connectionpool.HostSupplier;
import com.netflix.dyno.connectionpool.TokenMapSupplier;

import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.Protocol;
import redis.clients.jedis.commands.JedisCommands;

@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(name = "conductor.db.type", havingValue = "redis_cluster")
public class RedisClusterConfiguration extends JedisCommandsConfigurer {

private static final Logger log = LoggerFactory.getLogger(JedisCommandsConfigurer.class);

// Same as redis.clients.jedis.BinaryJedisCluster
protected static final int DEFAULT_MAX_ATTEMPTS = 5;

@Override
protected JedisCommands createJedisCommands(
RedisProperties properties,
Expand All @@ -43,7 +53,25 @@ protected JedisCommands createJedisCommands(
hostSupplier.getHosts().stream()
.map(h -> new HostAndPort(h.getHostName(), h.getPort()))
.collect(Collectors.toSet());
return new JedisCluster(
new redis.clients.jedis.JedisCluster(hosts, genericObjectPoolConfig));
String password = getPassword(hostSupplier.getHosts());

if (password != null) {
log.info("Connecting to Redis Cluster with AUTH");
return new JedisCluster(
new redis.clients.jedis.JedisCluster(
hosts,
Protocol.DEFAULT_TIMEOUT,
Protocol.DEFAULT_TIMEOUT,
DEFAULT_MAX_ATTEMPTS,
password,
genericObjectPoolConfig));
} else {
return new JedisCluster(
new redis.clients.jedis.JedisCluster(hosts, genericObjectPoolConfig));
}
}

private String getPassword(List<Host> hosts) {
return hosts.isEmpty() ? null : hosts.get(0).getPassword();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
package com.netflix.conductor.redis.config;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
Expand All @@ -28,6 +29,7 @@
import com.netflix.dyno.connectionpool.TokenMapSupplier;

import redis.clients.jedis.JedisSentinelPool;
import redis.clients.jedis.Protocol;
import redis.clients.jedis.commands.JedisCommands;

@Configuration(proxyBeanMethods = false)
Expand Down Expand Up @@ -59,8 +61,31 @@ protected JedisCommands createJedisCommands(
for (Host host : hostSupplier.getHosts()) {
sentinels.add(host.getHostName() + ":" + host.getPort());
}
return new JedisSentinel(
new JedisSentinelPool(
properties.getClusterName(), sentinels, genericObjectPoolConfig));
// We use the password of the first sentinel host as password and sentinelPassword
String password = getPassword(hostSupplier.getHosts());
if (password != null) {
return new JedisSentinel(
new JedisSentinelPool(
properties.getClusterName(),
sentinels,
genericObjectPoolConfig,
Protocol.DEFAULT_TIMEOUT,
Protocol.DEFAULT_TIMEOUT,
password,
Protocol.DEFAULT_DATABASE,
null,
Protocol.DEFAULT_TIMEOUT,
Protocol.DEFAULT_TIMEOUT,
password,
null));
} else {
return new JedisSentinel(
new JedisSentinelPool(
properties.getClusterName(), sentinels, genericObjectPoolConfig));
}
}

private String getPassword(List<Host> hosts) {
return hosts.isEmpty() ? null : hosts.get(0).getPassword();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.Protocol;
import redis.clients.jedis.commands.JedisCommands;

@Configuration(proxyBeanMethods = false)
Expand All @@ -44,6 +45,20 @@ protected JedisCommands createJedisCommands(
config.setMaxTotal(properties.getMaxConnectionsPerHost());
log.info("Starting conductor server using redis_standalone.");
Host host = hostSupplier.getHosts().get(0);
return new JedisStandalone(new JedisPool(config, host.getHostName(), host.getPort()));
return new JedisStandalone(getJedisPool(config, host));
}

private JedisPool getJedisPool(JedisPoolConfig config, Host host) {
if (host.getPassword() != null) {
log.info("Connecting to Redis Standalone with AUTH");
return new JedisPool(
config,
host.getHostName(),
host.getPort(),
Protocol.DEFAULT_TIMEOUT,
host.getPassword());
} else {
return new JedisPool(config, host.getHostName(), host.getPort());
}
}
}
3 changes: 2 additions & 1 deletion server/src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ conductor.db.type=memory

conductor.indexing.enabled=false

#Dynomite Cluster details.
apanicker-nflx marked this conversation as resolved.
Show resolved Hide resolved
#Redis configuration details.
#format is host:port:rack separated by semicolon
#Auth is supported. Password is taken from host[0]. format: host:port:rack:password
conductor.redis.hosts=host1:port:rack;host2:port:rack:host3:port:rack

#namespace for the keys stored in Dynomite/Redis
Expand Down