Stackexchange.redis: Can't connect to RedisLabs SSL

Created on 5 Apr 2019  Â·  11Comments  Â·  Source: StackExchange/StackExchange.Redis

Hi,

I've been trying to connect to RedisLabs over SSL, but I'm failing miserably.

My last attempt included copying the code from one of the tests in the repo, and I'm still getting errors

Below is the snippet of code I'm using:

```c#
redisCert = new X509Certificate2(Path.Combine(contentRootPath, "certificate.pfx"), "mypassword1!");

        /* That's not actually the host or the port */
        var options = new ConfigurationOptions
        {
            EndPoints = { { "redis-1111111.c11111.us-central1-1.gce.cloud.redislabs.com", 1111111 } },
            Password = "and-this-is-not-the-real-password-either",
            Ssl = true,
        };
        options.TrustIssuer(redisCert);
        /* I tried already 
         *  options.TrustIssuer("redislabs_ca.pem");
         */
        options.CertificateSelection += delegate
        {
            return redisCert;
        };
        Redis = ConnectionMultiplexer.Connect(options);

```

The error I'm getting is:
RedisConnectionException: It was not possible to connect to the redis server(s). There was an authentication failure; check that passwords (or client certificates) are configured correctly. AuthenticationFailure on ...

I've tried before installing the pfx in my local user and that worked, but I'm trying to deploy this to Azure, and Azure won't play ball, so I'm trying without anything installed in the local cert store.

Any help would be awesome. Thanks.

All 11 comments

Solved the connection issue in Azure. My local development is still failing, tho.

The solution for Azure App Service is to add an enviroment value named WEBSITE_LOAD_USER_PROFILE with a value of 1.

hi , can you share the ssl settings within the redis.conf file.
Trying out the same except that we have redis deployed as a standalone with SSL turned ON.
I am getting the same RedisConnectionException.

, i was given 3 files

  • ca.crt
  • redis.crt
  • redis.key

combined the redis.crt and redis.key to create a pem file (redis_includeskey.pem)

my redis.conf ssl part looks like below

################################# TLS/SSL #####################################

# By default, TLS/SSL is disabled. To enable it, the "tls-port" configuration
# directive can be used to define TLS-listening ports. To enable TLS on the
# default port, use:
#
# port 0
tls-port 6379

# Configure a X.509 certificate and private key to use for authenticating the
# server to connected clients, masters or cluster peers.  These files should be
# PEM formatted.
#
tls-cert-file /etc/ssl/certs/redis.crt 
tls-key-file /etc/ssl/certs/redis.key

# Configure a DH parameters file to enable Diffie-Hellman (DH) key exchange:
#
# tls-dh-params-file /etc/ssl/certs/redis.dh

# Configure a CA certificate(s) bundle or directory to authenticate TLS/SSL
# clients and peers.  Redis requires an explicit configuration of at least one
# of these, and will not implicitly use the system wide configuration.
#
tls-ca-cert-file /etc/ssl/certs/ca.crt
# tls-ca-cert-dir /etc/ssl/certs

# If TLS/SSL clients are required to authenticate using a client side
# certificate, use this directive.
#
# Note: this applies to all incoming clients, including replicas.
#
# tls-auth-clients yes

My client side code looks like below
``
image

If you're after a pfx from the RedisLabs files: I explain how to do that
here: https://blog.marcgravell.com/2014/07/securing-redis-in-cloud.html

On Mon, 3 Feb 2020, 06:30 keertisomu, notifications@github.com wrote:

hi , can you share the ssl settings within the redis.conf file.
Trying out the same except that we have redis deployed as a standalone
with SSL turned ON.
I am getting the same RedisConnectionException.

, i was given 3 files

  • ca.crt
  • redis.crt
  • redis.key

combined the redis.crt and redis.key to create a pem file
(redis_includeskey.pem)

my redis.conf ssl part looks like below

########################### TLS/SSL

By default, TLS/SSL is disabled. To enable it, the "tls-port" configuration

directive can be used to define TLS-listening ports. To enable TLS on the

default port, use:

#

port 0

tls-port 6379

Configure a X.509 certificate and private key to use for authenticating the

server to connected clients, masters or cluster peers. These files should be

PEM formatted.

#
tls-cert-file /etc/ssl/certs/redis.crt
tls-key-file /etc/ssl/certs/redis.key

Configure a DH parameters file to enable Diffie-Hellman (DH) key exchange:

#

tls-dh-params-file /etc/ssl/certs/redis.dh

Configure a CA certificate(s) bundle or directory to authenticate TLS/SSL

clients and peers. Redis requires an explicit configuration of at least one

of these, and will not implicitly use the system wide configuration.

#
tls-ca-cert-file /etc/ssl/certs/ca.crt

tls-ca-cert-dir /etc/ssl/certs

If TLS/SSL clients are required to authenticate using a client side

certificate, use this directive.

#

Note: this applies to all incoming clients, including replicas.

#

tls-auth-clients yes

My client side code looks like below
``
[image: image]
https://user-images.githubusercontent.com/32979227/73630653-cf07c900-46aa-11ea-8ed7-52ea229daca2.png

—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/StackExchange/StackExchange.Redis/issues/1113?email_source=notifications&email_token=AAAEHMA74I33WHQL2GG4RX3RA62YFA5CNFSM4HD5ENLKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEKSVC2Y#issuecomment-581259627,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AAAEHMCYZ57SAMPTYJ6LLJLRA62YFANCNFSM4HD5ENLA
.

Hi Marc , thanks for the link.
I forgot to mention , I am trying out the RC1 of Redis v6. So we configured the redis server on a VM with the v6 tar.
I want to know whether the configuration has been set up right on the server because the comments(TLS section) in the redis.conf file says certificates should be PEM formatted meaning the ones you generate on the server is a crt format which should be converted to PEM and then the redis.conf should be pointing to these PEM format and the client side should also consume these PEM format as well.
Please correct me if i am missing something here.
Thanks - Keerti.

There's two completely different things here:

  • what the server wants
  • what the client library wants

What the server wants is up to the server; however, on the client I'm
limited to what the runtime supports. The "new X509Certificate2"
constructor accepts PFX (PKCS12) payloads. Historically, it has been very
hard to directly load other formats; this may or may not have changed - I
haven't looked recently. For all I know it does not support other things.

The client and server don't need to agree on a storage format - they just
need to be talking about the same certificate. Interestingly, I stumbled
upon a recent comment / code sample on this a couple of days ago that
discusses PEM in the context of .NET:
https://github.com/dotnet/runtime/issues/19581#issuecomment-581147166

On Mon, 3 Feb 2020 at 22:26, keertisomu notifications@github.com wrote:

Hi Marc , thanks for the link.
I forgot to mention , I am trying out the RC1 of Redis v6. So we
configured the redis server on a VM with the v6 tar.
I want to know whether the configuration has been set up right on the
server because the comments(TLS section) in the redis.conf file says
certificates should be PEM formatted meaning the ones you generate on the
server is a crt format which should be converted to PEM and then the
redis.conf should be pointing to these PEM format and the client side
should also consume these PEM format as well.
Please correct me if i am missing something here.
Thanks - Keerti.

—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/StackExchange/StackExchange.Redis/issues/1113?email_source=notifications&email_token=AAAEHMAJQYZNH4SDNVRLUBDRBCK2NA5CNFSM4HD5ENLKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEKVUHLQ#issuecomment-581649326,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AAAEHMD2VQKRFXSDL4Z5LLDRBCK2NANCNFSM4HD5ENLA
.

--
Regards,

Marc

Additional note: there's a big difference here that depends on whether or
not you are using client certificates or not.

If you aren't using client certs, all you need to do is determine that you
trust the cert. The easiest way to do this is to import the public part of
the cert so it is known good - this only works on Windows. If you can't do
this, you need to provide your own certificate validation logic via
configuration options callbacks. In that scenario, the client doesn't need
anything really - except perhaps to know the CN/thumbprint of the cert.

If you're using client certs, then the client code gets more interesting.

So: are you using client certs? I can try to get the V6 server running and
connected locally. It'll be a useful sample.

On Tue, 4 Feb 2020, 07:32 Marc Gravell, marc.gravell@gmail.com wrote:

There's two completely different things here:

  • what the server wants
  • what the client library wants

What the server wants is up to the server; however, on the client I'm
limited to what the runtime supports. The "new X509Certificate2"
constructor accepts PFX (PKCS12) payloads. Historically, it has been very
hard to directly load other formats; this may or may not have changed - I
haven't looked recently. For all I know it does not support other things.

The client and server don't need to agree on a storage format - they
just need to be talking about the same certificate. Interestingly, I
stumbled upon a recent comment / code sample on this a couple of days ago
that discusses PEM in the context of .NET:
https://github.com/dotnet/runtime/issues/19581#issuecomment-581147166

On Mon, 3 Feb 2020 at 22:26, keertisomu notifications@github.com wrote:

Hi Marc , thanks for the link.
I forgot to mention , I am trying out the RC1 of Redis v6. So we
configured the redis server on a VM with the v6 tar.
I want to know whether the configuration has been set up right on the
server because the comments(TLS section) in the redis.conf file says
certificates should be PEM formatted meaning the ones you generate on the
server is a crt format which should be converted to PEM and then the
redis.conf should be pointing to these PEM format and the client side
should also consume these PEM format as well.
Please correct me if i am missing something here.
Thanks - Keerti.

—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/StackExchange/StackExchange.Redis/issues/1113?email_source=notifications&email_token=AAAEHMAJQYZNH4SDNVRLUBDRBCK2NA5CNFSM4HD5ENLKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEKVUHLQ#issuecomment-581649326,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AAAEHMD2VQKRFXSDL4Z5LLDRBCK2NANCNFSM4HD5ENLA
.

--
Regards,

Marc

Underneath is an example of connecting to redis v6 (with client-certs disabled) from a client that does not have the server's certs in any way.

You can make this code a lot easier if you can import the CA cert into the OS (on Windows); doing this locally with my CA's crt (without the key), I can remove the CertificateValidation hook, and just let the OS worry about the trust chain.

It would be nice if we could provide better options for providing CA certs as part of the config, and I'm open to investigating it, but: anything to do with certificates is simply awkward, not least because .NET doesn't love PEM - it really really wants you to use PFX.


``` c#
using StackExchange.Redis;
using System;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;

static class P
{
static async Task Main()
{
var config = new ConfigurationOptions
{
EndPoints =
{
new IPEndPoint(IPAddress.Loopback, 7379),
},
SslHost = "GECKO", // the CN on my server cert
Ssl = true,
};
// could also have used: ConfigurationOptions.Parse("127.0.0.1:7379,ssl=True,sslHost=GECKO")

    // now we'll add our own cert validation
    config.CertificateValidation += Config_CertificateValidation;
    using var muxer = await ConnectionMultiplexer.ConnectAsync(config);
    Console.WriteLine(await muxer.GetDatabase().PingAsync());

}

private static bool Config_CertificateValidation(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
    // note: if you don't specify SslHost you should anticite RemoteCertificateNameMismatch, RemoteCertificateChainErrors here
    // noting that SslPolicyErrors is a [Flags] enum (i.e. bitwise testing)

    // NOTE: THIS IS NOT SECURITY GUIDANCE; please implement your own certificate validation logic here!
    // was it the expected CA in the chain? 
    if (sslPolicyErrors == SslPolicyErrors.RemoteCertificateChainErrors
        && FindCA(chain) != null) return true;
    return sslPolicyErrors == SslPolicyErrors.None;

    static X509Certificate FindCA(X509Chain chain)
    {
        if (chain != null)
        {
            foreach (var cert in chain.ChainElements)
            {
                if (string.Equals(cert.Certificate.Thumbprint, "4ef72eaff1b01dc29d3cd806a466b19261497048",
                    StringComparison.OrdinalIgnoreCase))
                    return cert.Certificate;
            }
        }
        return null;
    }
}

}
```

FYI on my server config here:

tls-port 7379
tls-cert-file myserver.crt
tls-key-file myserver.key
tls-ca-cert-file rootCA.crt
tls-auth-clients no

and I generated my self-signed certificates with:

openssl genrsa -des3 -out rootCA.key 4096
openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 1024 -out rootCA.crt
openssl genrsa -out myserver.key 2048
openssl req -new -key myserver.key -out myserver.csr
openssl x509 -req -in myserver.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out myserver.crt -days 500 -sha256

Here's a much better validation method that allows the CRT to be used:

c# static X509Certificate2 s_LazyCA; static X509Certificate2 CertificateAuthority => s_LazyCA ??= new X509Certificate2(@"C:\Code\redis-6.0-rc1\rootCA.crt"); private static bool Config_CertificateValidation(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { if (sslPolicyErrors == SslPolicyErrors.RemoteCertificateChainErrors) { var root = chain.ChainElements[chain.ChainElements.Count - 1].Certificate; return CertificateAuthority.Equals(root); } return sslPolicyErrors == SslPolicyErrors.None; }

The fact that this works gives me some hope that we can simplify this and just do something like making the CA crt a config option.

I think this should work for new X509Certificate2(@"..somewhere..\redislabs_ca.pem"); too

Closing out for inactivity, let us know if this still presents issues!

Was this page helpful?
0 / 5 - 0 ratings