redis/go-redis

Unable to connect ClusterClient to Azure Cache for Redis

Closed this issue · 8 comments

I'm unable to establish a connection to Azure Cache for Redis, when using the ClusterClient:

//this works, but I need a ClusterClient from now on...
client := redis.NewClient(&redis.Options{
		Addr:       config.Queue.Redis.Addr,
		Password:   config.Queue.Redis.Pw,
		DB:         config.Queue.Redis.Db,
		TLSConfig: &tls.Config{
			InsecureSkipVerify: false,
		},
	})
//this is giving me a i/o timeout error
client := redis.NewClusterClient(&redis.ClusterOptions{
		Addrs:    []string{config.Queue.Redis.Addr},
		Password: config.Queue.Redis.Pw,
	})
//this is giving me the error: x509: cannot validate certificate for xx.xxx.xx.xx because it doesn't contain any IP SANs
client := redis.NewClusterClient(&redis.ClusterOptions{
		Addrs:    []string{config.Queue.Redis.Addr},
		Password: config.Queue.Redis.Pw,
		TLSConfig: &tls.Config{
			InsecureSkipVerify:          false,
		},
	})

This issue might be related to #1691 ? Any ideas?

/edit: formatting
/edit2: I'm using go-redis v8.6.0, tried on MacOS & Linux

After further analysis I assume the standard Client correctly connects via DNS while the ClusterClient tries to connect via IP address... this causes issues because the Azure certificate is only valid for the hostname present in the Subject field of the certificate.

Thanks for your help. I Just checked: executing cluster slots via redis-cli does indeed return the ip addresses, which do not match the Azure certificates...

What would be your recommendation to connect redis-go with the Azure Redis Cluster under these circumstances? The only possibility I see is to overwrite the NewClient func(opt *Options) *Client or ClusterSlots func(context.Context) ([]ClusterSlot, error) in the ClusterOptions...

No ideas here. I would expect Azure Cache team to have some solution.

I've opened a ticket with them and will post updates here.

In the meantime, I managed to work around it by passing in my own NewClient function and substituting the IP-address with the hostname.

Response from azure support:

According to our Doc you will need to use hostname instead of IP to access Azure Redis (since this is PaaS based service) . As per document looks StackExchange.Redis you can use sslHost in the connection string when talk to the resource , not sure if go-redis has such feature or not.
https://docs.microsoft.com/en-us/azure/azure-cache-for-redis/cache-how-to-premium-vnet#when-i-try-to-connect-to-my-azure-cache-for-redis-instance-in-a-virtual-network-why-do-i-get-an-error-stating-the-remote-certificate-is-invalid

and

As you known Azure Cache for Redis is a PaaS service and Azure LB will always be in front of the backend service which client application reaches first . So we need hostname for the LB to route the correct backend service to .
Redis-cli only return server IP and you can stick with FQDN of the resource when format connection string (if using other redis client).
IP based Cert is not a good practice considering if particular LB has issue the platform will dynamically failover FQDN to other healthy one which only work with SNI

@johannesvietze

you can try

redis.NewClusterClient(&redis.ClusterOptions{
                Addrs: []string{"..."},
                TLSConfig: &tls.Config{
                                ServerName: "you domain",
                },
})

@johannesvietze

you can try

redis.NewClusterClient(&redis.ClusterOptions{
                Addrs: []string{"..."},
                TLSConfig: &tls.Config{
                                ServerName: "you domain",
                },
})

Awesome, that's the solution. Thank you!