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

Add MQTT server authentication #1816

Merged
merged 2 commits into from
Mar 30, 2023
Merged

Conversation

Bravo555
Copy link
Contributor

@Bravo555 Bravo555 commented Mar 16, 2023

Proposed changes

This commit adds to our MQTT clients (tedge mqtt and mqtt_channel) the capability to connect to secure MQTT brokers via TLS. For the broker certificate to be successfully verified, this certificate has to be signed by a CA certificate, and the CA certificate needs to be trusted by the client.

To select a CA trusted certificate, a new configuration setting, mqtt.client.cafile, has been added.

Additionally the broker certificate needs to be X.509 v3 and have a "X509v3 Subject Alternative Name" section containing its Common Name as a DNS name. This behaviour happens upstream in rumqttc crate, and was documented in rumqtt#498.

Types of changes

  • Bugfix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Improvement (general improvements like code refactoring that doesn't explicitly fix a bug or add any new functionality)
  • Documentation Update (if none of the other choices apply)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)

Paste Link to the issue

Checklist

  • I have read the CONTRIBUTING doc
  • I have signed the CLA (in all commits with git commit -s)
  • I ran cargo fmt as mentioned in CODING_GUIDELINES
  • I used cargo clippy as mentioned in CODING_GUIDELINES
  • I have added tests that prove my fix is effective or that my feature works
  • I have added necessary documentation (if appropriate)

Further comments

Did some minimal Robot framework tests to test connecting to a TLS broker. Should I maybe expand them or add unit tests? Also I haven't really updated any documentation, as I don't remember any part that would be made out of date by this PR. Also added a warning when attempting to connect via TLS without CA file and vice versa.

@Bravo555 Bravo555 temporarily deployed to Test Pull Request March 16, 2023 16:47 — with GitHub Actions Inactive
@github-actions
Copy link
Contributor

github-actions bot commented Mar 16, 2023

Robot Results

✅ Passed ❌ Failed ⏭️ Skipped Total Pass %
164 0 5 164 100

Passed Tests

Name ⏱️ Duration Suite
Define Child device 1 ID 0.012 s C8Y Child Alarms Rpi
Normal case when the child device does not exist on c8y cloud 1.8940000000000001 s C8Y Child Alarms Rpi
Normal case when the child device already exists 1.189 s C8Y Child Alarms Rpi
Reconciliation when the new alarm message arrives, restart the mapper 3.188 s C8Y Child Alarms Rpi
Reconciliation when the alarm that is cleared 7.261 s C8Y Child Alarms Rpi
Prerequisite Parent 24.714 s Child Conf Mgmt Plugin
Prerequisite Child 0.769 s Child Conf Mgmt Plugin
Child device bootstrapping 19.553 s Child Conf Mgmt Plugin
Snapshot from device 61.832 s Child Conf Mgmt Plugin
Child device config update 62.945 s Child Conf Mgmt Plugin
Configuration types should be detected on file change (without restarting service) 53.76 s Inotify Crate
Child devices support sending simple measurements 3.919 s Child Device Telemetry
Child devices support sending custom measurements 1.8399999999999999 s Child Device Telemetry
Child devices support sending custom events 2.181 s Child Device Telemetry
Child devices support sending custom events overriding the type 1.795 s Child Device Telemetry
Child devices support sending custom alarms #1699 1.4020000000000001 s Child Device Telemetry
Child devices support sending inventory data via c8y topic 1.056 s Child Device Telemetry
Main device support sending inventory data via c8y topic 1.506 s Child Device Telemetry
Child device supports sending custom child device measurements directly to c8y 1.6059999999999999 s Child Device Telemetry
Main device supports sending custom child device measurements directly to c8y 2.368 s Child Device Telemetry
Successful firmware operation 81.153 s Firmware Operation
Install with empty firmware name 73.81 s Firmware Operation
Prerequisite Parent 28.326 s Firmware Operation Child Device
Prerequisite Child 8.361 s Firmware Operation Child Device
Child device firmware update 6.349 s Firmware Operation Child Device
Child device firmware update with cache 4.301 s Firmware Operation Child Device
Update Inventory data via inventory.json 1.335 s Inventory Update
Retrieve a JWT tokens 63.895 s Jwt Request
Main device registration 2.036 s Device Registration
Child device registration 3.173 s Device Registration
Supports restarting the device 74.049 s Restart Device
Update tedge version from previous using Cumulocity 129.115 s Tedge Self Update
Test if all c8y services are up 83.055 s Service Monitoring
Test if all c8y services are down 72.768 s Service Monitoring
Test if all c8y services are using configured service type 81.455 s Service Monitoring
Test if all c8y services using default service type when service type configured as empty 49.528 s Service Monitoring
Check health status of tedge-mapper-c8y service on broker stop start 34.537 s Service Monitoring
Check health status of tedge-mapper-c8y service on broker restart 35.945 s Service Monitoring
Check health status of child device service 29.194 s Service Monitoring
Successful shell command with output 3.664 s Shell Operation
Check Successful shell command with literal double quotes output 3.518 s Shell Operation
Execute multiline shell command 3.7199999999999998 s Shell Operation
Failed shell command 3.417 s Shell Operation
Software list should be populated during startup 67.776 s Software
Install software via Cumulocity 85.991 s Software
Software list should only show currently installed software and not candidates 60.708 s Software
Validate updated data path used by tedge-agent 1.367 s Data Path Config
Validate updated data path used by c8y-firmware-plugin 11.796 s Data Path Config
Stop tedge-agent service 0.877 s Log Path Config
Customize the log path 0.241 s Log Path Config
Initialize tedge-agent 0.372 s Log Path Config
Check created folders 0.182 s Log Path Config
Remove created custom folders 0.378 s Log Path Config
Install thin-edge via apt 41.07 s Install Apt
Install latest via script (from current branch) 36.958 s Install Tedge
Install specific version via script (from current branch) 23.172 s Install Tedge
Install latest tedge via script (from main branch) 29.917 s Install Tedge
Support starting and stopping services 53.749 s Service-Control
Supports a reconnect 71.103 s Test-Commands
Supports disconnect then connect 67.345 s Test-Commands
Update unknown setting 49.387 s Test-Commands
Update known setting 28.522 s Test-Commands
Stop c8y-configuration-plugin 0.452 s Health C8Y-Configuration-Plugin
Update the service file 0.497 s Health C8Y-Configuration-Plugin
Reload systemd files 1.227 s Health C8Y-Configuration-Plugin
Start c8y-configuration-plugin 0.572 s Health C8Y-Configuration-Plugin
Start watchdog service 10.712 s Health C8Y-Configuration-Plugin
Check PID of c8y-configuration-plugin 0.117 s Health C8Y-Configuration-Plugin
Kill the PID 0.543 s Health C8Y-Configuration-Plugin
Recheck PID of c8y-configuration-plugin 0.258 s Health C8Y-Configuration-Plugin
Compare PID change 0.001 s Health C8Y-Configuration-Plugin
Stop watchdog service 0.335 s Health C8Y-Configuration-Plugin
Remove entry from service file 0.29 s Health C8Y-Configuration-Plugin
Stop c8y-log-plugin 0.598 s Health C8Y-Log-Plugin
Update the service file 0.419 s Health C8Y-Log-Plugin
Reload systemd files 1.403 s Health C8Y-Log-Plugin
Start c8y-log-plugin 0.491 s Health C8Y-Log-Plugin
Start watchdog service 10.634 s Health C8Y-Log-Plugin
Check PID of c8y-log-plugin 0.139 s Health C8Y-Log-Plugin
Kill the PID 0.404 s Health C8Y-Log-Plugin
Recheck PID of c8y-log-plugin 0.244 s Health C8Y-Log-Plugin
Compare PID change 0.005 s Health C8Y-Log-Plugin
Stop watchdog service 0.227 s Health C8Y-Log-Plugin
Remove entry from service file 0.165 s Health C8Y-Log-Plugin
Stop tedge-mapper 0.417 s Health Tedge Mapper C8Y
Update the service file 0.388 s Health Tedge Mapper C8Y
Reload systemd files 1.184 s Health Tedge Mapper C8Y
Start tedge-mapper 0.319 s Health Tedge Mapper C8Y
Start watchdog service 10.354 s Health Tedge Mapper C8Y
Check PID of tedge-mapper 0.196 s Health Tedge Mapper C8Y
Kill the PID 0.507 s Health Tedge Mapper C8Y
Recheck PID of tedge-mapper 0.21 s Health Tedge Mapper C8Y
Compare PID change 0.001 s Health Tedge Mapper C8Y
Stop watchdog service 0.434 s Health Tedge Mapper C8Y
Remove entry from service file 0.384 s Health Tedge Mapper C8Y
Stop tedge-agent 0.388 s Health Tedge-Agent
Update the service file 0.215 s Health Tedge-Agent
Reload systemd files 1.029 s Health Tedge-Agent
Start tedge-agent 0.211 s Health Tedge-Agent
Start watchdog service 10.442 s Health Tedge-Agent
Check PID of tedge-mapper 0.121 s Health Tedge-Agent
Kill the PID 0.256 s Health Tedge-Agent
Recheck PID of tedge-agent 0.209 s Health Tedge-Agent
Compare PID change 0.001 s Health Tedge-Agent
Stop watchdog service 0.347 s Health Tedge-Agent
Remove entry from service file 0.267 s Health Tedge-Agent
Stop tedge-mapper-az 0.371 s Health Tedge-Mapper-Az
Update the service file 0.372 s Health Tedge-Mapper-Az
Reload systemd files 1.366 s Health Tedge-Mapper-Az
Start tedge-mapper-az 0.374 s Health Tedge-Mapper-Az
Start watchdog service 10.609 s Health Tedge-Mapper-Az
Check PID of tedge-mapper-az 0.114 s Health Tedge-Mapper-Az
Kill the PID 0.27 s Health Tedge-Mapper-Az
Recheck PID of tedge-agent 0.172 s Health Tedge-Mapper-Az
Compare PID change 0.001 s Health Tedge-Mapper-Az
Stop watchdog service 0.322 s Health Tedge-Mapper-Az
Remove entry from service file 0.274 s Health Tedge-Mapper-Az
Stop tedge-mapper-collectd 0.891 s Health Tedge-Mapper-Collectd
Update the service file 0.367 s Health Tedge-Mapper-Collectd
Reload systemd files 1.855 s Health Tedge-Mapper-Collectd
Start tedge-mapper-collectd 0.683 s Health Tedge-Mapper-Collectd
Start watchdog service 10.672 s Health Tedge-Mapper-Collectd
Check PID of tedge-mapper-collectd 0.137 s Health Tedge-Mapper-Collectd
Kill the PID 0.302 s Health Tedge-Mapper-Collectd
Recheck PID of tedge-mapper-collectd 0.19 s Health Tedge-Mapper-Collectd
Compare PID change 0.001 s Health Tedge-Mapper-Collectd
Stop watchdog service 0.341 s Health Tedge-Mapper-Collectd
Remove entry from service file 0.39 s Health Tedge-Mapper-Collectd
c8y-log-plugin health status 6.556 s MQTT health endpoints
c8y-configuration-plugin health status 6.06 s MQTT health endpoints
Publish on a local insecure broker 0.3 s Connect Broker
Publish on a local secure broker 3.23 s Connect Broker
Wrong package name 0.203 s Improve Tedge Apt Plugin Error Messages
Wrong version 0.203 s Improve Tedge Apt Plugin Error Messages
Wrong type 0.404 s Improve Tedge Apt Plugin Error Messages
tedge_connect_test_positive 1.057 s Tedge Connect Test
tedge_connect_test_negative 2.89 s Tedge Connect Test
tedge_connect_test_sm_services 10.697 s Tedge Connect Test
tedge_disconnect_test_sm_services 2.476 s Tedge Connect Test
Install thin-edge.io 16.695 s Call Tedge
call tedge -V 0.085 s Call Tedge
call tedge -h 0.09 s Call Tedge
call tedge -h -V 0.112 s Call Tedge
call tedge help 0.131 s Call Tedge
tedge config list 0.186 s Call Tedge Config List
tedge config list --all 0.269 s Call Tedge Config List
set/unset device.type 1.393 s Call Tedge Config List
set/unset device.key.path 0.92 s Call Tedge Config List
set/unset device.cert.path 0.781 s Call Tedge Config List
set/unset c8y.root.cert.path 1.534 s Call Tedge Config List
set/unset c8y.smartrest.templates 0.891 s Call Tedge Config List
set/unset az.root.cert.path 0.64 s Call Tedge Config List
set/unset az.mapper.timestamp 0.905 s Call Tedge Config List
set/unset mqtt.bind_address 0.598 s Call Tedge Config List
set/unset mqtt.port 0.564 s Call Tedge Config List
set/unset tmp.path 0.453 s Call Tedge Config List
set/unset logs.path 0.428 s Call Tedge Config List
set/unset run.path 0.559 s Call Tedge Config List
Get Put Delete 3.9 s Http File Transfer Api
Set keys should return value on stdout 0.134 s Tedge Config Get
Unset keys should not return anything on stdout and warnings on stderr 0.279 s Tedge Config Get
Invalid keys should not return anything on stdout and warnings on stderr 0.316 s Tedge Config Get
Set configuration via environment variables 1.024 s Tedge Config Get
Set unknown configuration via environment variables 0.075 s Tedge Config Get

Copy link
Contributor

@PradeepKiruvale PradeepKiruvale left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs the mosquitto config to be updated right? How this will be done here? Is this a manual step now?

@Bravo555
Copy link
Contributor Author

Bravo555 commented Mar 17, 2023

This needs the mosquitto config to be updated right? How this will be done here? Is this a manual step now?

I understood the issue to mean that it's not as much about making local MQTT broker secure by default, but about being able to connect even if somebody manually configures server authentication for their broker. If we were to handle handle TLS config for mosquitto in thin-edge, this would more effort required to come up with sensible defaults, making sure everything is secure, also letting people tweak the config, etc.

I think just adding more configuration options for MQTT clients can be considered completely separately from adding options or changing current defaults of broker configuration.

@didier-wenzek
Copy link
Contributor

I understood the issue to mean that it's not as much about making local MQTT broker secure by default, but about being able to connect even if somebody manually configures server authentication for their broker.

You understood correctly. I would even consider a bad idea to update from thin-edge the broker configuration. This configuration must stay owned by the device owner.

@PradeepKiruvale
Copy link
Contributor

This needs the mosquitto config to be updated right? How this will be done here? Is this a manual step now?

I understood the issue to mean that it's not as much about making local MQTT broker secure by default, but about being able to connect even if somebody manually configures server authentication for their broker. If we were to handle handle TLS config for mosquitto in thin-edge, this would more effort required to come up with sensible defaults, making sure everything is secure, also letting people tweak the config, etc.

I think just adding more configuration options for MQTT clients can be considered completely separately from adding options or changing current defaults of broker configuration.

Thanks for the clarification.

@reubenmiller
Copy link
Contributor

@Bravo555 Can you please rebase, as the failed integration test seems to be due to this recently fixed/merged issue, #1821

Copy link
Contributor

@didier-wenzek didier-wenzek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nicely done. Thank you.

@@ -56,6 +60,9 @@ pub struct Config {
///
/// Default: None
pub initial_message: Option<InitMessageFn>,

/// TLS configuration used to connect to the broker.
pub tls_config: Option<ClientConfig>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would either rename the type or use rustls::ClienConfig as the current name is really vague.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ended up changing it to rustls::RootTrustStore

@@ -27,6 +28,25 @@ pub fn create_tls_config(
.with_single_cert(cert_chain, pvt_key)?)
}

pub fn create_tls_config_from_single_ca(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why only a single CA? It's can be convenient to be given a directory of trusted CA.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As described in #1816 (comment), will add an option for adding multiple CA.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replaced with functions that add certificates from a file and a directory respectively to the trust store.

const KEY: &'static str = "mqtt.client.cafile";

const DESCRIPTION: &'static str = concat!(
"Path to the CA certificate used by MQTT clients to use when ",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would allow this path to be a directory of trusted certificates.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made it a path to a single certificate because when developing I had both CA certificate and server certificate in one directory, and didn't want to include both. But you're right that just 1 certificate might be too restrictive. Both MQTT clients that I used had both cafile and capath options, so perhaps I shall add mqtt.client.capath option?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The usage is indeed to have two options, one for a ca file and one for a capath directory. However, I wonder if a single option can be used for both as the behavior can be adapted whether the path points to a file or a directory.

@reubenmiller waht do you think about these options?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However, I wonder if a single option can be used for both as the behavior can be adapted whether the path points to a file or a directory.

Having thought about it, I think with two separate options it is clear from the invocation whether or not we use a single certificate, or multiple certificates. With one option, you would have to look in the filesystem whether or not this path is a file or a directory, making the invocation ambiguous. For this reason I think it would be better to have two options.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrt. the capath option, I have a question. How do we decide which certificates do we read and add? Do we attempt to parse every file in the directory as a certificate? Do we filter by file extensions, like .pem or .crt?

Here's what two example MQTT clients do:

  • mosquitto_pub
    --capath
             Define the path to a directory containing PEM encoded CA certificates that are trusted. Used to enable SSL
             communication.
    
             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.
    
  • MQTT CLI
    It does not explain in the manpage, but it seems to include all files with extensions .pem, .cer, and .crt

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think with two separate options it is clear from the invocation

By this, I meant "invocation" for CLI clients, and forgot that in the case of thin-edge, it is hidden inside configuration files. Still, having a distinction whether or not we use only one or multiple certificates, is what I would be in favour of keeping, even in a config file, unless there is some clear use case where one option that deals with both files and directories is superior.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It makes senses to have these two options in the configuration file - as proposed by this PR.

Comment on lines 50 to 52
// Not sure if there is a better way to do this, unfortunately rumqttc error
// reporting is a bit awkward
impl From<rumqttc::TlsError> for ServerCertVerifyError {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, TLS error reporting is tedious in many crates. See

pub fn get_webpki_error_from_reqwest(err: reqwest::Error) -> CertError {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the biggest issue is that if we connect via TLS, then all the errors come wrapped inside rumqttc::ConnectionError::Tls(..) even if the issue was not with TLS specifically. If it was a TLS error, there is another layer of rumqttc::TlsError::Io(..) despite the issue not being related to IO at all, and only then inside we have an actual error which is stringified.

This nesting results in the structure of the error just being the copy of rumqttc call stack. All the errors are wrapped in TlsError(..) becuase the errors are returned from a function like TlsClient::read(), which just wraps all the errors, and that's all the way down the stack.

This is I think an antipattern that I want to look into making sure we're not replicating in thin-edge after I complete this issue. Sure we're the only consumers of our APIs, so the impact is limited, but it's still there, and might cause bad error formatting for the users, if one's not careful when reporting errors.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is I think an antipattern that I want to look into making sure we're not replicating in thin-edge after I complete this issue. Sure we're the only consumers of our APIs, so the impact is limited, but it's still there, and might cause bad error formatting for the users, if one's not careful when reporting errors.

I would be really happy to have you working on such improvements.

Comment on lines 40 to 43
#[error(
"Received certificate is not valid for the name it is being validated for.
\nHint: Be sure to use a hostname specified in the CN field of the certificate and for the certificate to have a Subject Alt Name section."
)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This error message is written from the point of view of the guy who created the broker certificate. It might be less useful for an end-user who used the wrong hostname to connect the broker.

Suggested change
#[error(
"Received certificate is not valid for the name it is being validated for.
\nHint: Be sure to use a hostname specified in the CN field of the certificate and for the certificate to have a Subject Alt Name section."
)]
#[error(
"The MQTT server certificate is not valid as not matching the server hostname.
\nHint: Be sure to use a hostname specified in the CN field of the certificate or one the Subject Alt Name section."
)]

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One correction: We can only connect to a hostname if this hostname is present in subjectAltName section. Connecting to hostname specified in CN is not sufficient if it's not also in the subjectAltName section.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the clarification.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error message was reworded according to the recommendations and error structure was changed a bit.

#[derive(thiserror::Error, Debug)]
pub enum ServerCertVerifyError {
/// Received certificate is not in X509v3 format
#[error("Received certificate is not in X.509 v3 format")]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you mean by received certificate?

Suggested change
#[error("Received certificate is not in X.509 v3 format")]
#[error("The MQTT server certificate is not in X.509 v3 format - as required by thin-edge")]

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant "received from the other side of the connection", but you're right that it's a bit unclear. Will fix.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reworded this error message as well.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It can be useful to link this file from the documentation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On which documentation page would you like to like to see this file linked?

@Bravo555
Copy link
Contributor Author

Okay, I think I implemented most of the feedback, the only thing remaining is maybe making use of the created script for generating mosquitto server certificates by featuring it in the documentation.

As for the client authentication that needs to be done as the other part of the linked issue, I think it should be done in another PR as the scope of the changes for server authentication is large enough.

Copy link
Contributor

@didier-wenzek didier-wenzek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A system test is failing because of a change introduced by this PR:

Invalid value "mqtt.client.cafile" for '<KEY>': Invalid key `mqtt.client.cafile'. See `tedge config list --doc` for a list of valid keys.

The following tests are failing, but I would not bother to fix them. They add really little value (checking that tedge mqtt returns a status of 1 when it fails to connect). So I would simply remove all these tests. Furthermore, robot framework would be more adapted for those tests that require a specific environment (with an MQTT broker up or down).

  • tests::mqtt_sub_no_broker_running::none_expects
  • tests::mqtt_sub_no_broker_running::some_0_expects
  • tests::mqtt_sub_no_broker_running::some_1_expects
  • tests::mqtt_sub_no_broker_running::some_2_expects

file.path()
.extension()
.filter(|&extension| {
["pem", "cer", "crt"]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is okay. However, such a closed list of accepted names is always a source of surprises. For instance, I would expect to see cert but not cer.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These 3 extensions are what MQTT CLI uses (mosquitto_pub/sub only allows .crt), but it's largely a matter of convention. More complete list of extensions can be found here, and maybe we could accept more extensions, but I don't think it's an issue as long as we properly document the extensions we accept, which I've just noticed I forgot about. Will add the list of accepted extensions to the description of relevant configuration options.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay. So let's start with these 3 extensions.

Comment on lines +107 to -75
// TODO: should we keep trying to reconnect for all errors, or just
// if the broker isn't up and abort when e.g. we receive connection
// refused?
Err(err) => {
let err_msg = err.to_string();
if err_msg.contains("I/O: Connection refused (os error 111)") {
return Err(MqttError::ServerConnection(err_msg));
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm okay with the current proposal (to keep trying reconnect whatever the connection error) as the aim of tedge mqtt is not to replace a full-fledged MQTT command line tool but just to provide a convenient way to interact with thin-edge leveraging the same configuration.

const KEY: &'static str = "mqtt.client.cafile";

const DESCRIPTION: &'static str = concat!(
"Path to the CA certificate used by MQTT clients to use when ",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It makes senses to have these two options in the configuration file - as proposed by this PR.

@Bravo555
Copy link
Contributor Author

Fixed mqtt.client.ca_path config setting documentation and removed flaky mqtt pub/sub tests.

@Bravo555 Bravo555 force-pushed the mqtt-auth branch 2 times, most recently from a147ae5 to 9f2385e Compare March 28, 2023 10:05
@Bravo555 Bravo555 temporarily deployed to Test Pull Request March 28, 2023 10:14 — with GitHub Actions Inactive
Copy link
Contributor

@didier-wenzek didier-wenzek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved. Thank you

@Bravo555 Bravo555 mentioned this pull request Mar 29, 2023
11 tasks
This commit adds to our MQTT clients (tedge mqtt and mqtt_channel) the
capability to connect to secure MQTT brokers via TLS. For the broker
certificate to be successfully verified, this certificate has to be
signed by a CA certificate, and the CA certificate needs to be trusted
by the client.

To select a CA trusted certificate, new configuration settings,
`mqtt.client.ca_file` and `mqtt.client.ca_path` have been added.

Additionally the broker certificate needs to be X.509 v3 and have a
"X509v3 Subject Alternative Name" section containing its Common Name as
a DNS name. This behaviour happens upstream in rumqttc crate, and was
documented in [rumqtt#498].

[rumqtt#498]: bytebeamio/rumqtt#498

Signed-off-by: Marcel Guzik <marcel.guzik@inetum.com>
These tests were flaky as they relied on mosquitto configuration not
present in the tests and other things in the environment. For such
integration testing we now use Robot Framework tests.

Signed-off-by: Marcel Guzik <marcel.guzik@inetum.com>
@Bravo555 Bravo555 temporarily deployed to Test Pull Request March 30, 2023 09:50 — with GitHub Actions Inactive
@didier-wenzek didier-wenzek merged commit 339bb6e into thin-edge:main Mar 30, 2023
@Bravo555 Bravo555 deleted the mqtt-auth branch March 30, 2023 13:14
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

Successfully merging this pull request may close these issues.

None yet

4 participants