dotnet / MQTTnet

MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker). The implementation is based on the documentation from http://mqtt.org/.
MIT License
4.51k stars 1.07k forks source link

Using certificates in Websocket MQTT Server #1700

Open PJ-Kowalski opened 1 year ago

PJ-Kowalski commented 1 year ago

Describe your question

I create .Net Blazor App that works as MQTT broker (TCP and WS). I host this App on Azure WebApp Service. Due to fact on WebApp i can use only port 80, only Web Sockets work. Broker working fine, but i lake to make connection secure by certificates, to allow connection only for client with valid certificate

in program.cs i add following

uilder.Services.AddHostedMqttServer(
     optionsBuilder =>
     {
         optionsBuilder
                    .WithEncryptedEndpoint()
                    .WithEncryptedEndpointPort(80)
                    .WithEncryptionCertificate(CertificateManager.GetServerCertificateFromFile().Export(X509ContentType.Pfx))
                    .WithEncryptionSslProtocol(SslProtocols.Tls12)
                    .WithClientCertificate()
                    .Build();
     });
builder.Services.AddMqttConnectionHandler();
builder.Services.AddConnections();
builder.Services.AddSingleton<MqttController>();
   public static X509Certificate2 GetServerCertificateFromFile()
        {
            X509Certificate2 certificate = new X509Certificate2(serverCertName,"pk820405", X509KeyStorageFlags.Exportable);
            return certificate;
        }

but i can still connect with any client, and without TSL encryption (if i check ignore certificate error in client) so, my question is:

  1. How to properly secure broker when running on azure WebApp
  2. How to properly secure broker when running on kestrel
  3. Can i use certificates generated from OpenSSl

Which project is your question related to?

Devidence7 commented 1 year ago

Hi there!

Here are some suggestions for your questions:

1. Securing broker when running on Azure WebApp

Azure WebApp Service has limited support for client certificate authentication. You'll need to enable it manually in the portal or through Azure CLI:

az webapp update -g <resource_group> -n <app_name> --set clientCertEnabled=true

Then, in your Blazor app, you can check the X-ARR-ClientCert header for the client certificate. Based on the certificate, you can decide whether to allow or reject the connection. Please note that client certificate authentication is available only for the Basic or higher pricing tiers.

2. Securing broker when running on Kestrel

To configure Kestrel for client certificate authentication, you can use the KestrelServerOptions like this:

WebHost.CreateDefaultBuilder(args)
    .UseStartup<Startup>()
    .UseKestrel(options =>
    {
        options.ConfigureHttpsDefaults(httpsOptions =>
        {
            httpsOptions.ServerCertificate = GetServerCertificateFromFile();
            httpsOptions.ClientCertificateMode = ClientCertificateMode.RequireCertificate;
            httpsOptions.CheckCertificateRevocation = false;
        });
    })
    .Build();

This will enforce client certificates for incoming connections.

3. Using certificates generated from OpenSSL

Yes, you can use certificates generated with OpenSSL. Just make sure you generate a proper certificate chain with a root certificate, intermediate certificate(s), and an end-entity certificate.

Generating a certificate chain using OpenSSL

  1. Create a root CA (Certificate Authority) key and certificate:
    openssl genrsa -out rootCA.key 4096
    openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 1024 -out rootCA.pem
  2. Create a server key, certificate signing request (CSR), and sign it with the root CA:
    openssl genrsa -out server.key 2048
    openssl req -new -key server.key -out server.csr
    openssl x509 -req -in server.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out server.crt -days 365 -sha256
  3. Convert the server key and certificate into a PFX file:
    openssl pkcs12 -export -out server.pfx -inkey server.key -in server.crt -certfile rootCA.pem

This will create a server.pfx file, which you can use in your .NET application.

Using the generated certificates in your .NET application

  1. Copy the server.pfx file to your .NET application's folder (e.g., Certificates folder).
  2. Modify your GetServerCertificateFromFile() method to load the server.pfx file:
    public static X509Certificate2 GetServerCertificateFromFile()
    {
    string pfxPath = Path.Combine("Certificates", "server.pfx");
    string pfxPassword = "your_pfx_password";
    X509Certificate2 certificate = new X509Certificate2(pfxPath, pfxPassword, X509KeyStorageFlags.Exportable);
    return certificate;
    }

Remember to replace your_pfx_password with the password you set when exporting the PFX file (and make sure to keep it secure).

  1. Now, configure Kestrel to use the certificate:
    WebHost.CreateDefaultBuilder(args)
    .UseStartup<Startup>()
    .UseKestrel(options =>
    {
        options.ConfigureHttpsDefaults(httpsOptions =>
        {
            httpsOptions.ServerCertificate = GetServerCertificateFromFile();
            httpsOptions.ClientCertificateMode = ClientCertificateMode.RequireCertificate;
            httpsOptions.CheckCertificateRevocation = false;
        });
    })
    .Build();

This should enable your application to use the certificates generated with OpenSSL for securing the server. Keep in mind that client certificates should also be generated and signed by a trusted CA (either your own root CA or a public one).

I hope this helps! If you have any further questions or need more clarification, please let me know.