Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't connect to RedisLabs SSL #1113

Closed
erick2red opened this issue Apr 5, 2019 · 14 comments
Closed

Can't connect to RedisLabs SSL #1113

erick2red opened this issue Apr 5, 2019 · 14 comments

Comments

@erick2red
Copy link

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:

            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.

@erick2red
Copy link
Author

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.

@keertisomu
Copy link

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

@mgravell
Copy link
Collaborator

mgravell commented Feb 3, 2020 via email

@keertisomu
Copy link

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.

@mgravell
Copy link
Collaborator

mgravell commented Feb 4, 2020 via email

@mgravell
Copy link
Collaborator

mgravell commented Feb 4, 2020 via email

@mgravell
Copy link
Collaborator

mgravell commented Feb 4, 2020

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.


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;
        }
    }
}

@mgravell
Copy link
Collaborator

mgravell commented Feb 4, 2020

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

@mgravell
Copy link
Collaborator

mgravell commented Feb 4, 2020

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

    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.

@mgravell
Copy link
Collaborator

mgravell commented Feb 4, 2020

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

@NickCraver
Copy link
Collaborator

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

@mikeries
Copy link

@mgravell Thanks for this! I'm new to TLS/SSL and I've been spinning my wheels for a couple days trying to figure this out. Thanks to your examples, I have it working now.

But one question -- how does this code configure the private key? Or don't you need it? My code has a crt file (in PEM format) and a CA file (also in PEM format) but I didn't specify the key anywhere...

@mgravell
Copy link
Collaborator

@mikeries are we talking about a client cert or a server cert? Presumably the latter. The client doesn't need the key to verify a server using the server's public key - that's kinda the point. Only the server needs the private key.

@mikeries
Copy link

Yes, the cert is for both server or client. So I guess in this case we are just using certs to verify identity, and then exchanging data that is encrypted with session keys. I looked at an overview of the TLS handshake protocol, and I think I get it now. Thanks!

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

No branches or pull requests

5 participants