Skip to content

Conversation

supercaracal
Copy link
Contributor

@supercaracal supercaracal commented Mar 3, 2022

Description

This PR will solve the following issue.

The issue is an error the client fails to verify the certificate of nodes. It is caused in a case which we use cluster feature with SSL/TLS connection. Since the client relies and depends on CLUSTER NODES and CLUSTER SLOTS, the client may fail to verify certificates if servers return IP addresses of nodes in reply to the client.

AWS ElastiCache and Redis versions since 7.* possess an ability to be able to reply FQDN of nodes by the following directives of configuration. They were added by AWS folks and have been available since Redis 7.*.

On the other hand, other architectures for cluster mode with SSL/TLS may use proxy servers such that stunnel or something like that for SSL/TLS termination. In that case, the client has to connect to the nodes via the FQDN of a single endpoint.

So this PR adds a fixed_hostname option to the client and modifying to be able to pass it to internal connector.

Redis.new(cluster: %w[rediss://foo-endpoint.example.com:6379], fixed_hostname: 'foo-endpoint.example.com')

How does cluster client work?

sequenceDiagram
    participant Client
    participant Server Shard 1
    participant Server Shard 2
    participant Server Shard 3
    Note over Client,Server Shard 3: Redis.new(cluster: %w[redis://node1:6379])
    Client->>+Server Shard 1: CLUSTER SLOTS
    Server Shard 1-->>-Client: nodes and slots data
    Client->>+Server Shard 1: GET key1
    Server Shard 1-->>-Client: value1
    Client->>+Server Shard 2: GET key2
    Server Shard 2-->>-Client: value2
    Client->>+Server Shard 3: GET key3
    Server Shard 3-->>-Client: value3
    Client->>+Server Shard 3: GET key1
    Server Shard 3-->>-Client: MOVED Server Shard 1
    Note over Client,Server Shard 3: Client needs to redirect to correct node
    Client->>+Server Shard 2: MGET key2 key3
    Server Shard 2-->>-Client: CROSSSLOTS
    Note over Client,Server Shard 2: Cannot command across shards
Loading

Architectures of Redis cluster with SSL/TLS as I can imagine

AWS

The client can connect to the nodes directly. The endpoint is just a CNAME record of DNS. It is as simple as that.

graph TB
  client(Cluster Client)

  subgraph Amazon ElastiCache for Redis
    node0(Node0)
    node1(Node1)
    node2(Node2)
  end

  node0-.-node1-.-node2-.-node0
  client--rediss://node0.example.com:6379-->node0
  client--rediss://node1.example.com:6379-->node1
  client--rediss://node2.example.com:6379-->node2
Loading

Microsoft Azure

The service provides a single IP address and multiple ports mapped to each node. The endpoint doesn't support redirection. It does only SSL/TLS termination.

graph TB
  client(Cluster Client)

  subgraph Azure Cache for Redis
    subgraph Endpoint
      endpoint(Active)
      endpoint_sb(Standby)
    end

    subgraph Cluster
      node0(Node0)
      node1(Node1)
      node2(Node2)
    end
  end

  endpoint-.-endpoint_sb
  node0-.-node1-.-node2-.-node0
  client--rediss://endpoint.example.com:15000-->endpoint--redis://node0:6379-->node0
  client--rediss://endpoint.example.com:15001-->endpoint--redis://node1:6379-->node1
  client--rediss://endpoint.example.com:15002-->endpoint--redis://node2:6379-->node2
Loading

@supercaracal supercaracal force-pushed the support-azure-cache-for-redis-with-cluster-mode-and-ssl-tls branch 5 times, most recently from 8e7d89f to 9a9cd32 Compare March 3, 2022 10:30
@supercaracal supercaracal force-pushed the support-azure-cache-for-redis-with-cluster-mode-and-ssl-tls branch from 9a9cd32 to ab7c371 Compare March 3, 2022 10:51
@supercaracal supercaracal marked this pull request as ready for review March 3, 2022 23:23
options = @options.merge(opt)
options = options.merge(host: @fixed_hostname) if @fixed_hostname && !@fixed_hostname.empty?
[node_key, options]
end.to_h
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

def build_clients(options)
clients = options.map do |node_key, option|
next if replica_disabled? && slave?(node_key)
option = option.merge(readonly: true) if slave?(node_key)
client = Client.new(option)
[node_key, client]
end
clients.compact.to_h
end

ssl_sock.hostname = host

@byroot byroot merged commit 5fb64bd into redis:master Mar 11, 2022
@supercaracal supercaracal deleted the support-azure-cache-for-redis-with-cluster-mode-and-ssl-tls branch March 11, 2022 12:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants