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

Improvement - TLS for mqtt communication #260

Merged
merged 3 commits into from
Jun 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions backend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,8 @@ Read more about the `launchSettings.json` file

For the backend to work when dockerized, you need to have the client secret exposed as
an environment variable named `FLOTILLA_CLIENT_SECRET`.
The simplest way to do this in bash is to run

```
export FLOTILLA_CLIENT_SECRET=SuperSecret
```
The best way to do this is to store it in an `.env` file in the root of the flotilla repository.
See [Using the “--env-file” option](https://docs.docker.com/compose/environment-variables/#using-the---env-file--option) for more information.

To run the backend in docker, run the following command in the root folder of flotilla:

Expand Down
45 changes: 43 additions & 2 deletions backend/api/MQTT/MqttService.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Text;
using System.Net.Security;
using System.Text;
using System.Text.Json;
using Api.Mqtt.Events;
using Api.Mqtt.MessageModels;
Expand All @@ -24,14 +25,16 @@ public class MqttService : BackgroundService

private readonly ManagedMqttClientOptions _options;

private readonly bool _isDevelopment;

private readonly string _serverHost;
private readonly int _serverPort;

private readonly TimeSpan _reconnectDelay = TimeSpan.FromSeconds(5);
private readonly int _maxRetryAttempts;
private readonly bool _shouldFailOnMaxRetries;

private int _reconnectAttempts;

private CancellationToken _cancellationToken;

public MqttService(ILogger<MqttService> logger, IConfiguration config)
Expand All @@ -42,6 +45,9 @@ public MqttService(ILogger<MqttService> logger, IConfiguration config)
_mqttClient = mqttFactory.CreateManagedMqttClient();

string password = config.GetValue<string>("mqtt-broker-password");
_isDevelopment = (
config.GetValue<string?>("ASPNETCORE_ENVIRONMENT") ?? "Production"
).Equals("Development", StringComparison.OrdinalIgnoreCase);

var mqttConfig = config.GetSection("Mqtt");
string username = mqttConfig.GetValue<string>("Username");
Expand All @@ -52,6 +58,15 @@ public MqttService(ILogger<MqttService> logger, IConfiguration config)

var builder = new MqttClientOptionsBuilder()
.WithTcpServer(_serverHost, _serverPort)
.WithTls(
o =>
{
o.UseTls = true;
o.CertificateValidationHandler = CustomCertificateHandler;
if (_isDevelopment)
o.IgnoreCertificateChainErrors = true;
}
)
.WithCredentials(username, password);

_options = new ManagedMqttClientOptionsBuilder()
Expand Down Expand Up @@ -246,5 +261,31 @@ private void OnIsarTopicReceived<T>(string content) where T : MqttMessage
_logger.LogWarning("{msg}", e.Message);
}
}

/// <summary>
/// A workaround for a bug in the MQTTNet framework where the IgnoreCertificateChainErrors option is not being considered.
/// </summary>
/// <remarks>
/// Proposed solution in MQTTNet: <see href="https://github.com/dotnet/MQTTnet/pull/1447"/>
/// </remarks>
/// <param name="context"></param>
/// <returns></returns>
private bool CustomCertificateHandler(
MqttClientCertificateValidationCallbackContext context
)
{
bool approved;
if (context.ClientOptions.TlsOptions.IgnoreCertificateChainErrors)
approved =
context.SslPolicyErrors == SslPolicyErrors.RemoteCertificateChainErrors
|| context.SslPolicyErrors == SslPolicyErrors.None;
else
approved = context.SslPolicyErrors == SslPolicyErrors.None;

if (!approved)
_logger.LogError("Error with remote certificate: {error}", context.SslPolicyErrors);

return approved;
}
}
}
30 changes: 30 additions & 0 deletions backend/api/appsettings.Production.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"AzureAd": {
"ClientId": "ea4c7b92-47b3-45fb-bd25-a8070f0c495c",
"ClientSecret": "Fill in ASP.NET Secret Manager"
},
"KeyVault": {
"VaultUri": "https://PlaceboFlotillaDevKv.vault.azure.net/"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Warning"
}
},
"AllowedHosts": "*",
"AllowedOrigins": "http://localhost:3001",
"Mqtt": {
"Host": "localhost",
"Port": 1883,
"Username": "flotilla",
"Topics": [
"isar/+/mission",
"isar/+/task",
"isar/+/step"
],
"MaxRetryAttempts": 15,
"ShouldFailOnMaxRetries": true
}
}
6 changes: 5 additions & 1 deletion broker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ FROM eclipse-mosquitto:latest

COPY mosquitto/config/ mosquitto/config/

EXPOSE 1883 9001
ARG TLS_SERVER_KEY

RUN echo "${TLS_SERVER_KEY}" > mosquitto/config/certs/server-key.pem

EXPOSE 1883

USER 1883

Expand Down
8 changes: 8 additions & 0 deletions broker/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Mosquitto MQTT Broker

## Set up the broker

The broker expects a private key for its server x509 certificate used for TLS.
This must be provided through an environment variable called `FLOTILLA_BROKER_SERVER_KEY`.
This is a secret, and should be treated as such.
The best way to pass this is to store it in a `.env` file in the root of flotilla, and docker compose loads this by default on startup.
See [Using the “--env-file” option](https://docs.docker.com/compose/environment-variables/#using-the---env-file--option) for more information.

## Running the broker

From the flotilla root directory, run the following command:
Expand Down
35 changes: 35 additions & 0 deletions broker/mosquitto/config/certs/ca-cert.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
-----BEGIN CERTIFICATE-----
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
NOEALuJzso8ziFZOqO+rGx5jX5ii
-----END CERTIFICATE-----
34 changes: 34 additions & 0 deletions broker/mosquitto/config/certs/server-cert.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
-----BEGIN CERTIFICATE-----
MIIF+zCCA+OgAwIBAgIUMsBK/Fg9GkEJpInOnGuQScXxJ3MwDQYJKoZIhvcNAQEL
BQAwgZcxCzAJBgNVBAYTAk5PMQ8wDQYDVQQIDAZCZXJnZW4xDzANBgNVBAcMBkJl
cmdlbjEUMBIGA1UECgwLRXFfUm9ib3RpY3MxETAPBgNVBAsMCFJvYm90aWNzMRww
GgYDVQQDDBNSb2JvdGljc19TZWxmU2lnbmVkMR8wHQYJKoZIhvcNAQkBFhB0bG5l
QGVxdWlub3IuY29tMB4XDTIyMDYyODE0MTEyNVoXDTIyMDgyNzE0MTEyNVowgZgx
CzAJBgNVBAYTAk5PMQ8wDQYDVQQIDAZCZXJnZW4xDzANBgNVBAcMBkJlcmdlbjER
MA8GA1UECgwIRmxvdGlsbGExFDASBgNVBAsMC01RVFQgQnJva2VyMR0wGwYDVQQD
DBRGbG90aWxsYV9NUVRUX0Jyb2tlcjEfMB0GCSqGSIb3DQEJARYQdGxuZUBlcXVp
bm9yLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMe05p5K08ii
zG7dv/LJmIWCLGj6FUp5+Whpni9UIFATibXUl2yTl/FAtrxq/L4ZkVpiTDP5kQno
7/Y3MuWQumC2ivjfL3TSAKES5ec3Vmdolz16sCn1BZtKe68t4re9nF5AhS5i6WPh
NWyMN2o5UwBsEe3tZBowkAPLdfFaOc1JSEDbFnHqyiypeBbwfJ2qJe/J2yUN+m+5
MY22kZDf2J+6k3MUJQvA8KF6usMjjMrenx7uvGE3OU9XtDU4qtvOMD8p5I4fDqBv
k7v2STOiOkuZOoBD98PpRFVjh+2HijiHfZqzKhNs6XWicOhYlJzp3nNr7+fJp+DJ
8PP+zqBKeK2TlKCJAISCVSNiTHbHaHwbCXzNzj9vfy8+8qplcUe35hF2fXlVr1zF
VObkWeVNVQxR726TF0l/pvFez6qNTMag4IZaZyi6joU+06OdBSO8Ch57hwIkkp46
jGxs/zoSwevA0PU0vcYCbydQXkfgvmEzOvluUBwN/WgR+v8r0ubPTAl9I5EhuKU4
7sBD43OZD1nSWEWGidTjzMcOOLSZLAP50eWxF486DuLf65UKoZ0oWB0LDH+N+lU8
kSix4RJuGNIOSEd+AJCw9+zG6efL5cAy/yy4SsbL/QRxE0wk4pA+v3xzlBdDdxlu
PXPaMYClvHZDTiN7p0fx6IjYyBp49F8ZAgMBAAGjPDA6MDgGA1UdEQQxMC+HBAAA
AACCCWxvY2FsaG9zdIIGYnJva2VyghRob3N0LmRvY2tlci5pbnRlcm5hbDANBgkq
hkiG9w0BAQsFAAOCAgEAZpNWT1c99ClbW1N299u/fZ6CQ7aLFyDyMintK3SPjNgc
nUz78MAm/rP4tH2FjG7GLlXEaKKxzenqeWlF/LbndykrN9vRwkiz0C15MWRz3wLU
lYm8XaXRsA5CKOGKFyxpBAngHkiIVOBX2aAhWFUPHrxnoldgBK8MNdK3+xBy6Ck8
04G7pbg/4sGDflDoo+e2NOeU69JCt5mrpLGIggPP+tvwn9jnxYOJfPxahdGHx44N
ajbjtJtKm9jMHxaHzfkAPIIdMITLiwNBIS0+JINwaJv4Er9zkK0jxeIwkKPxmfNI
za8f2dPxecOqLSvKo/+JFAu4Ib/NCcb9f+b8WykS52YuWaO+9KQsQV3HDx4EXDjv
KoMNw1YfViYn5vLTynukR4BGnessEm9+F3ZD8xEdSHzSOpZx2iAJB8xKjCthmhfz
9S508us7C3bkc6L+JFWg6ph4/5VC2gfUnKAUIqfygsLHYFSKmHKmz+m71yrLzviG
wCV11ca9e18GKUQohnA99fclCAwn7mI6Osr5WtaabcKJwh3PEmekQKic+OK3Yop0
x54U+SbPbNbWIX/E3wCppL/s3zHA4/m1X5kardBcD5x9uJybcNpTY/TDJFV+XxOx
rGgbfAwb3QqJs8qt+45JFMQ8B2YAqQc+aozdd1Mvvv9h/9+ut6to3uV/pokhpX4=
-----END CERTIFICATE-----
10 changes: 5 additions & 5 deletions broker/mosquitto/config/mosquitto.conf
Original file line number Diff line number Diff line change
Expand Up @@ -232,8 +232,8 @@
listener 1883 0.0.0.0
protocol mqtt

listener 9001 0.0.0.0
protocol websockets
#listener 9001 0.0.0.0
#protocol websockets

# By default, a listener will attempt to listen on all supported IP protocol
# versions. If you do not have an IPv4 or IPv6 interface you may wish to
Expand Down Expand Up @@ -316,10 +316,10 @@ protocol websockets
# TLS encryption.

# Path to the PEM encoded server certificate.
#certfile
certfile mosquitto/config/certs/server-cert.pem

# Path to the PEM encoded keyfile.
#keyfile
keyfile mosquitto/config/certs/server-key.pem

# If you wish to control which encryption ciphers are used, use the ciphers
# option. The list of available ciphers can be optained using the "openssl
Expand Down Expand Up @@ -360,7 +360,7 @@ protocol websockets
# containing the CA certificates. For capath to work correctly, the
# certificate files must have ".crt" as the file ending and you must run
# "openssl rehash <path to capath>" each time you add/remove a certificate.
#cafile
cafile mosquitto/config/certs/ca-cert.pem
#capath


Expand Down
2 changes: 1 addition & 1 deletion broker/mosquitto/config/passwd_file
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
admin:$7$101$+GsirAIRSKXQLk5z$MMl/WR6vxmH0igzvtcYx3LmhLn168CJk2b8c1TiPheYtgK4A0eJrRxptz4iA6B62TLda1u2329ntw7YkLVrRUw==
admin:$7$101$0gb0/MsZQODnBqea$cKG/aB3kZ2ThPFKCxxwBMCfgIAgeLNsmiU4oljI82AOrNplnG41LJ224S2Gq4212M5cvZr4PoOCc5IjKgjIldA==
flotilla:$7$101$tmAqSZNbVPjre70A$/yJ+WcI/749Q9SYpbBe+wii0pea5omHssdUIb3+NQiwLmy/ppwFVFTFvHLCoZasDNMGfkQ+FoLilLMtgjqwUZA==
isar:$7$101$ge+J8JDGhAXCDgud$SKG7TYUaKzTcYhLBjOwNAP0G2tr25pMKneo4ehOF1I/15QjgjNsYqP8NZKu+n52F3B/7Oqv0KI3NFBg3xcTd1A==
7 changes: 5 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
version: "3.7"

services:
frontend:
build: frontend
ports:
- "3001:3001"
broker:
build: broker
build:
context: broker
args:
- TLS_SERVER_KEY=${FLOTILLA_BROKER_SERVER_KEY}
ports:
- "1883:1883"
- "9001:9001"
backend:
build: backend
ports:
Expand Down