Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RabbitMQ + C# + SSL

Tags:

c#

ssl

rabbitmq

I'm trying to use C# to get RabbitMQ 3.6.2 to use SSL/TLS on Windows 7 against Erlang 18.0. I'm running into errors when I'm enabling SSL in my C# code. I have gone through the steps to set up SSL/TLS here. I've also gone through the [troubleshooting steps][2] which show turn up successful (except I couldn't do the stunnel step due to lack of knowledge of stunnel). Here's my C# code trying to connect to RabbitMQ:

var factory = new ConnectionFactory()
{
    // NOTE: guest username ONLY works with HostName "localhost"!
    //HostName = Environment.MachineName,
    HostName = "localhost",
    UserName = "guest",
    Password = "guest",
};

// Without this line, RabbitMQ.log shows error: "SSL: hello: tls_handshake.erl:174:Fatal error: protocol version"
// When I add this line to go to TLS 1.2, .NET throws an exception: The remote certificate is invalid according to the validation procedure.
//      https://stackoverflow.com/questions/9983265/the-remote-certificate-is-invalid-according-to-the-validation-procedure:
//      Walked through this tutorial to add the client certificate as a Windows Trusted Root Certificate: http://www.sqlservermart.com/HowTo/Windows_Import_Certificate.aspx
factory.Ssl.Version = SslProtocols.Tls12;

factory.Ssl.ServerName = "localhost"; //System.Net.Dns.GetHostName();
factory.Ssl.CertPath = @"C:\OpenSSL-Win64\client\keycert.p12";
factory.Ssl.CertPassphrase = "Re$sp3cMyS3curi1ae!";
factory.Ssl.Enabled = true;
factory.Port = 5671;

// Error: "The remote certificate is invalid according to the validation procedure."
using (var connection = factory.CreateConnection())
{
}

There's a StackOverflow post regarding the "The remote certificate is invalid according to the validation procedure." exception, but the hack fix doesn't seem to take effect as the callback method suggested is never called. I think that I've added my certificate generated via OpenSSL to the Windows Trusted Root Certification Authorities certificates list for local computer. So I'm at a loss here. Any ideas on how to proceed?

Edit: Here's the final working code for anyone struggling to implement SSL on Rabbit:

var factory = new ConnectionFactory();
factory.HostName = ConfigurationManager.AppSettings["rabbitmqHostName"];

factory.AuthMechanisms = new AuthMechanismFactory[] { new ExternalMechanismFactory() };
// Note: This should NEVER be "localhost"
factory.Ssl.ServerName = ConfigurationManager.AppSettings["rabbitmqServerName"];
// Path to my .p12 file.
factory.Ssl.CertPath = ConfigurationManager.AppSettings["certificateFilePath"];
// Passphrase for the certificate file - set through OpenSSL
factory.Ssl.CertPassphrase = ConfigurationManager.AppSettings["certificatePassphrase"];
factory.Ssl.Enabled = true;
// Make sure TLS 1.2 is supported & enabled by your operating system
factory.Ssl.Version = SslProtocols.Tls12;
// This is the default RabbitMQ secure port
factory.Port = 5671;
factory.VirtualHost = "/";
// Standard RabbitMQ authentication (if not using ExternalAuthenticationFactory)
//factory.UserName = ConfigurationManager.AppSettings["rabbitmqUsername"];
//factory.Password = ConfigurationManager.AppSettings["rabbitmqPassword"];

using (var connection = factory.CreateConnection())
{
    using (var channel = connection.CreateModel())
    {
        // publish some messages...
    }
}

Thanks,

Andy

like image 344
Andy Avatar asked Sep 22 '16 15:09

Andy


4 Answers

It can be done as simple as this

        const string RabbitMqServerHostname = "myserver.northeurope.cloudapp.azure.com";

        var factory = new ConnectionFactory()
        {
            HostName = RabbitMqServerHostname,
            UserName = "myuser",
            Password = "mypassword",

            // The settings below turn on SSL
            Port = 5671,
            Ssl = new SslOption
            {
                Enabled = true,
                ServerName = RabbitMqServerHostname
            }
        };
like image 81
Bo Christian Skjøtt Avatar answered Sep 20 '22 14:09

Bo Christian Skjøtt


My problem was related to using self signed certificates. I had to add the SslOption AcceptablePolicyErrors = SslPolicyErrors.RemoteCertificateNameMismatch | SslPolicyErrors.RemoteCertificateChainErrors

In the example connection factory creation code sslEnabled is true.

new ConnectionFactory()
            {
                Uri = uri,
                ClientProvidedName = clientProvidedName,
                AutomaticRecoveryEnabled = true,
                Ssl = new SslOption(){
                    Enabled = sslEnabled,
                 AcceptablePolicyErrors = SslPolicyErrors.RemoteCertificateNameMismatch |
                                                SslPolicyErrors.RemoteCertificateChainErrors} ,

                NetworkRecoveryInterval = TimeSpan.FromSeconds(networkRecoveryIntervalSecs)
            }
like image 43
Gregory Green Avatar answered Sep 20 '22 14:09

Gregory Green


Usual problem is mismatch between what you provide in Ssl.ServerName and host SSL certificate was issued for.

Also note that server-side SSL (encrypted connection between your client and server) and client-side authentication with certificate (you provide server with information which confirms that you have certificate it expects) are two different things. By providing Ssl.CertPath you intent to authorize at server using this certificate, which might or might not be what you want.

like image 32
Evk Avatar answered Sep 19 '22 14:09

Evk


I just went through a similar frustrating exercise with the .NET 4.5 client (v. 3.6.6) and the RabbitMQ broker/service on Windows (v. 3.6.6, Erlang 19.2).

The correct combination of RabbitMQ config file options and client settings is not intuitive and the client factory object has changed since the documentation was last updated. Now there's an SslOption class.

Are you still having problems? Perhaps I can help you.

like image 40
MikeZ Avatar answered Sep 18 '22 14:09

MikeZ