envoyproxy / envoy

Cloud-native high-performance edge/middle/service proxy
https://www.envoyproxy.io
Apache License 2.0
24.79k stars 4.76k forks source link

Redis Proxy: Auth password per endpoint in a cluster? #23962

Open dceravigupta opened 1 year ago

dceravigupta commented 1 year ago

Hi, is it possible to use different auth passwords for connecting to different redis endpoints as part of a single redis upstream clusters?

  clusters:
  - name: redis_cluster
    type: STRICT_DNS
    lb_policy: MAGLEV
    load_assignment:
      cluster_name: redis_cluster
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: abc.redis.net
                port_value: 6380
        - endpoint:
            address:
              socket_address:
                address: xyz.redis.net
                port_value: 6380
    transport_socket:
      name: envoy.transport_sockets.tls
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
    typed_extension_protocol_options:
      envoy.filters.network.redis_proxy:
        "@type": type.googleapis.com/envoy.extensions.filters.network.redis_proxy.v3.RedisProtocolOptions
        auth_password:
          inline_string: "??" <-- auth password is different for the above mentioned redis endpoints.

In the example config above, both redis instances i.e. abc.redis.net and xyz.redis.net have different auth passwords.

zuercher commented 1 year ago

cc @weisisea perhaps you can answer?

dceravigupta commented 1 year ago

@weisisea would you be able to help me out on this one?

weisisea commented 1 year ago

Sorry for the late reply.

Envoy supports individual passwords for different clusters: https://github.com/envoyproxy/envoy/blob/dede92e6e5888cdf27320bf3b6bc9987657d6e22/test/extensions/filters/network/redis_proxy/redis_proxy_integration_test.cc#L238-L271

But I don't think Envoy currently supports different passwords for different endpoints in the same cluster. Envoy Redis filter authenticates the client on the downstream connection. The authentication is done locally at Envoy and the AUTH commands aren't forwarded to upstream Redis nodes. Once the downstream connection is authenticated, the requests of the client can reach all upstream Redis nodes.

weisisea commented 1 year ago

After reading the code a little more, I realized that the previous comment is related to the downstream authentication, instead of the upstream authentication, which the question is about.

Currently, an upstream connection pool has one password: https://github.com/envoyproxy/envoy/blob/dede92e6e5888cdf27320bf3b6bc9987657d6e22/source/extensions/filters/network/redis_proxy/conn_pool_impl.h#L183 https://github.com/envoyproxy/envoy/blob/dede92e6e5888cdf27320bf3b6bc9987657d6e22/source/extensions/filters/network/redis_proxy/conn_pool_impl.cc#L137-L138

The password is passed when creating an upstream client: https://github.com/envoyproxy/envoy/blob/dede92e6e5888cdf27320bf3b6bc9987657d6e22/source/extensions/filters/network/redis_proxy/conn_pool_impl.cc#L243-L244

During the upstream client initialization, the client sends an AUTH command to the upstream Redis host: https://github.com/envoyproxy/envoy/blob/dede92e6e5888cdf27320bf3b6bc9987657d6e22/source/extensions/filters/network/common/redis/client_impl.cc#L289-L293

To support per-endpoint password, I think we could modify the RedisProtocolOptions to contain a table containing mappings from endpoint to password. The ConnPool::InstanceImpl can then store the mapping table. When we create a connection to an upstream Redis host in the connection pool, we get the password for that Redis host from the mapping table and use it to initialize an upstream client.