尝试使用 StackExchange.Redis 连接到 AWS Elasticache 时出错

问题描述 投票:0回答:1

我正在为 Redis 使用 AWS Elasticache。它配置为启用集群模式。引擎版本为6.2.6.

下面的代码示例从完全相同的机器运行,具有所需的所有权限、证书和路由/网络/acl 规则。

让我从以下一小段 python 代码开始:

fromt redis.cluster import RedisCluster
rc = RedisCluster(host="myhost.mydomain.internal", ssl=True, passowrd="mysupersecretpassword")
rc.ping()

有效并返回

True
.

在我试图用来做几乎相同事情的 csharp 代码下面:

using StackExchange.Redis;
using System.Net;
using System.Threading.Tasks;

namespace CSharpRedisCli
{
    class Program
    {
        static readonly ConnectionMultiplexer redis = ConnectionMultiplexer.Connect(
            new ConfigurationOptions{
                EndPoints = { new DnsEndPoint("myhost.mydomain.internal", 6379) },
                ResolveDns = true,
                Ssl = true,
                Password = "mysupersecretpassword",
                AbortOnConnectFail=false
            });
        
        static async Task Main(string[] args)
        {
            var db = redis.GetDatabase();
            var pong = await db.PingAsync();
            Console.WriteLine(pong);
        }
    }
}

但比我在以下问题中运行:

Unhandled exception. StackExchange.Redis.RedisConnectionException: The message timed out in the backlog attempting to send because no connection became available - Last Connection Exception: AuthenticationFailure on myhost.mydomain.internal:6379/Interactive, Initializing/NotStarted, last: NONE, origin: ConnectedAsync, outstanding: 0, last-read: 7s ago, last-write: 7s ago, keep-alive: 60s, state: Connecting, mgr: 10 of 10 available, last-heartbeat: never, global: 7s ago, v: 2.6.104.40210, command=PING, timeout: 5000, inst: 0, qu: 0, qs: 0, aw: False, bw: CheckingForTimeout, rs: NotStarted, ws: Initializing, in: 0, last-in: 0, cur-in: 0, sync-ops: 0, async-ops: 1, serverEndpoint: myhost.mydomain.internal:6379, conn-sec: n/a, aoc: 0, mc: 1/1/0, mgr: 10 of 10 available, clientName: C02FJ1DMMD6Q(SE.Redis-v2.6.104.40210), IOCP: (Busy=0,Free=1000,Min=1,Max=1000), WORKER: (Busy=0,Free=32767,Min=16,Max=32767), POOL: (Threads=6,QueuedItems=0,CompletedItems=174), v: 2.6.104.40210 (Please take a look at this article for some common client-side issues that can cause timeouts: https://stackexchange.github.io/StackExchange.Redis/Timeouts)
 ---> StackExchange.Redis.RedisConnectionException: AuthenticationFailure on myhost.mydomain.internal:6379/Interactive, Initializing/NotStarted, last: NONE, origin: ConnectedAsync, outstanding: 0, last-read: 7s ago, last-write: 7s ago, keep-alive: 60s, state: Connecting, mgr: 10 of 10 available, last-heartbeat: never, global: 7s ago, v: 2.6.104.40210
 ---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure: RemoteCertificateNameMismatch
   at System.Net.Security.SslStream.SendAuthResetSignal(ProtocolToken message, ExceptionDispatchInfo exception)
   at System.Net.Security.SslStream.CompleteHandshake(SslAuthenticationOptions sslAuthenticationOptions)
   at System.Net.Security.SslStream.ForceAuthenticationAsync[TIOAdapter](Boolean receiveFirst, Byte[] reAuthenticationData, CancellationToken cancellationToken)
   at System.Net.Security.SslStream.AuthenticateAsClient(SslClientAuthenticationOptions sslClientAuthenticationOptions)
   at StackExchange.Redis.ExtensionMethods.AuthenticateAsClientUsingDefaultProtocols(SslStream ssl, String host) in /_/src/StackExchange.Redis/ExtensionMethods.cs:line 206
   at StackExchange.Redis.ExtensionMethods.AuthenticateAsClient(SslStream ssl, String host, Nullable`1 allowedProtocols, Boolean checkCertificateRevocation) in /_/src/StackExchange.Redis/ExtensionMethods.cs:line 196
   at StackExchange.Redis.PhysicalConnection.ConnectedAsync(Socket socket, LogProxy log, SocketManager manager) in /_/src/StackExchange.Redis/PhysicalConnection.cs:line 1500
   --- End of inner exception stack trace ---
   --- End of inner exception stack trace ---
   at CSharpRedisCli.Program.Main(String[] args) in Program.cs:line 21
   at CSharpRedisCli.Program.<Main>(String[] args)

我的 csharp 代码缺少什么?

编辑

主机

myhost.mydomain.internal
是指向 Elasticache 配置端点的 route53 CNAME 记录。

直接调用配置端点时有效。

调用route53主机时出现异常。虽然我的 python 代码能够处理这个调用,但需要在 dotnet/stackexchanghe.redis 端配置一些东西。

c# redis stackexchange.redis amazon-elasticache
1个回答
0
投票

使用与redis端点配置不同的

EndPoint
时,需要设置SslHost配置选项。

基于此,我编写了一个代码来从我的 R53 记录中查询 redis 端点:

using Amazon.Route53;
using Amazon.SecretsManager;
using Amazon.Route53.Model;
using StackExchange.Redis;
using System.Net;
using System.Net.Security;
using System.Security.Authentication;
using Amazon.SecretsManager.Model;

namespace CSharpRedisCli
{
    class Program
    {

        private static async Task<String> getRedisEndpointFromR53(String r53RecordName, String hostedZoneName)
        {
            var route53Client = new AmazonRoute53Client();

            var listHostedZoneResponse = await route53Client.ListHostedZonesByNameAsync(
                            new ListHostedZonesByNameRequest { DNSName = hostedZoneName });

            var hostedZoneId = listHostedZoneResponse.HostedZones.First().Id.Split("/").Last();

            var listRecordSetResponse = await route53Client.ListResourceRecordSetsAsync(
                new ListResourceRecordSetsRequest
                {
                    HostedZoneId = hostedZoneId,
                    StartRecordName = r53RecordName
                });

            return listRecordSetResponse.ResourceRecordSets.First().ResourceRecords.First().Value;
        }

        private static async Task<String> getRedisPassword(String secretId)
        {
            var ssmClient = new AmazonSecretsManagerClient();

            var ssmResponse = await ssmClient.GetSecretValueAsync(new GetSecretValueRequest
            {
                SecretId = secretId
            });

            var pwd = ssmResponse.SecretString;

            return pwd;
        }

        static void Main(string[] args)
        {
            var r53RecordName = "myhost.mydomain.internal";
            var hostedZoneName = "mydomain.internal.";
            var secretId = "mypasswordid";

            var configurationOptions = new ConfigurationOptions
            {
                EndPoints = { new DnsEndPoint(r53RecordName, 6379) },
                Ssl = true,
                Password = getRedisPassword(secretId).Result,
                SslProtocols = SslProtocols.Tls12 | SslProtocols.Tls13
            };

            configurationOptions.CertificateValidation += (sender, certificate, chain, sslPolicyErrors) =>
            {
                if (sslPolicyErrors == SslPolicyErrors.None)
                {
                    Console.WriteLine("No certificate error");
                    return true;
                }

                if (sslPolicyErrors == SslPolicyErrors.RemoteCertificateNameMismatch)
                {
                    Console.WriteLine("Remote certificate name mismatch. Updating SslHost...");
                    configurationOptions.SslHost = getRedisEndpointFromR53(r53RecordName, hostedZoneName).Result;
                    return true;
                }

                Console.WriteLine("Ops");
                return false;
            };

            var redis = ConnectionMultiplexer.Connect(configurationOptions);
            var db = redis.GetDatabase();
            var pong = db.Ping();

            Console.WriteLine("ack: " + pong);
        }
    }
}

我仍然需要弄清楚 Python 库如何处理这个问题,看看是否可以对 StackExchange.Redis 库做同样的事情。

© www.soinside.com 2019 - 2024. All rights reserved.