Mosquitto MQTT client certificate exception - ssl

I'm developing an application that, in summary, uses MQTT to send sensor values to a broker to later visualize that data in a dashboard web application.
I have five microcontrollers connected to the broker and I've set up a server certificate for the broker and client certificates for each microcontroller.
The problem is that, in the mosquitto.conf file I require the use of client certificates for the clients that want to connect, so if I want to subscribe to a topic from my web application I need a client certificate. I'm trying to find the right approach for accomplishing this, but it seems that having a certificate and key in a machine you cannot control is a big security risk.
It would be ideal if someone knew a way of tweaking the mosquitto configuration file or establish some kind of exception (maybe similar to ACL's) to only require client certificates for certain clients (in my case, the microcontrollers) and use username#password for the others (web clients). Is it possible to do such a thing?
Any help would be much appreciated
EDIT (regarding #hardillb 's answer)
My mosquitto.conf:
pid_file /var/run/mosquitto.pid
persistence true
persistence_location /var/lib/mosquitto/
log_dest file /var/log/mosquitto/mosquitto.log
include_dir /etc/mosquitto/conf.d
per_listener_settings true
listener 9873
protocol websockets
#http_dir /home/jamengual/Desktop/UIB/TFG/mqtt/webAPP
cafile /etc/mosquitto/ca_certificates/ca.crt
keyfile /etc/mosquitto/certs/server.key
certfile /etc/mosquitto/certs/server.crt
listener 8883
cafile /etc/mosquitto/ca_certificates/ca.crt
keyfile /etc/mosquitto/certs/server.key
certfile /etc/mosquitto/certs/server.crt
require_certificate true
The "per_listener_settings true" makes the server go to an active(exited) state.
From the mosquitto.conf guide:
Talking about authentication mechanisms:
Both certificate and PSK based encryption are configured on a
per-listener basis.
Talking about the per_listener_settings options:
per_listener_settings [ true | false ]
If true, then authentication and access control settings will be controlled on a per-listener basis. The following options are affected:
password_file, acl_file, psk_file, allow_anonymous, allow_zero_length_clientid, auth_plugin, auth_opt_*, auto_id_prefix.
So I understand that the per_listener_settings option might not be necessary for the require_certificate part. However, I still need it to configure the usernames and passwords for the websockets.
Is there something wrong with my configuration file?
Link to my question about how to store client certificates and keys in the client's machine

Mosquitto allows you to have multiple listeners per broker that all share the same topic space.
Listeners can support native MQTT, MQTT over Websockets (including Websockets over TLS) and MQTT over TLS.
It also has the per_listener_settings option which allows you to specify different authentication options for different listeners. This option was added in mosquitto version 1.5.
So in this case, you can create a MQTT over TLS listener and use client certificates to authenticate those users (devices) and a MQTT over Websocket listener that will use username/password authentication.
e.g. something like this (but probably using a authentication plugin rather than acl/password files)
per_listener_settings true
listener 1884
cafile /path/to/ca
certfile /path/to/cert
keyfile /path/to/key
require_certificate true
acl_file /path/to/acl_file
listener 8883
protocol websockets
acl_file /path/to/acl_file
password_file /path/to/password
You can also include the ca_file, cert_file and key_file options for the websocket listener, to enable Websockets over TLS (but don't use the require_certificate because browser side client certificate handling for websockets is not a great experience, as they don't ask which to use). But normally I would normally use something like NGINX to proxy for the websocket listener and also do the TLS termination.
Details of all the options can be found in the mosquitto.conf man page: https://mosquitto.org/man/mosquitto-conf-5.html

Related

Does server only CA certificate with Mosquitto encrypt messages from the client to the server

This is probably a stupid question, but, in the Mosquitto.conf documentation on SSL says,
If false, the SSL/TLS component of the client will verify the server but there is no requirement for the client to provide anything for the server: authentication is limited to the MQTT built in username/password
If one chooses this particular protocol does it mean the encryption is only one way, i.e. only broker traffic to the client is encrypted, or is traffic encrypted in both directions?
if you set require_certificate config to false only the server(broker) will be authenticated. If you want to authenticate the client as well, you have to set the said config to true.
if it's set to true, client has to send the certificates to the broker, therefore enabling mutual authentication.

How to apply TLS in Mosquitto with websockets?

I'm tring to test mosquitto+websocket broker.
My website that include mqtt-javacript use https, so i have to use wss:// protocol
So first I apply to broker TLS option(cafile, certfile, key), and it worked well.(not websockets)
But when i add websockets option in config file, It work only on ws:// protocol not wss://.
I don't know why TLS wasn't applied..... Somebody who know about this problem please help me...
port 1883
listener 9002
protocol websockets
cafile /etc/mosquitto/tls/ca.crt
certfile /etc/mosquitto/tls/server.crt
keyfile /etc/mosquitto/tls/server.key
I followed steps to make CA and certificate file at http://mosquitto.org/man/mosquitto-tls-7.html

SSL/TLS with Eclipse Paho JavaScript Client

I've got a JavaScript-based WebApp that includes the Eclipse Paho client.
The WebApp is stored and executed on an NGINX webserver.
On the same Server where the webserver is installed, the MQTT broker mosquitto is running. I've defined port 8884 as listener port for secured connections.
Running mosquitto_sub (simple C client) with --cafile and -p 8884 works fine!
Now I want to secure the WebApp using SSL by passing mqttOptions = { useSSL: true } in my MQTT client implementation.
I can see that the app is trying to establish an connection to wss://ip instead of ws://ip. But the server responds with a connection refused which is totally clear because I did not configure anything on the webserver as I do not have a clue how to manage this. Will the wss connection be 'mapped' to a https or something? Do I need a websocket proxy in NGINX? Thanks in advance for any help.
You can not use the same port for raw MQTT and MQTT over websockets with mosquitto, you need to create 2 separate listeners.
The fact that you can connect with mosquitto_sub implies you have only set up a listener with the raw MQTT.
e.g.
listener 8883
listener 8884
protocol websockets
This will create a native MQTT listener on 8883 and a MQTT over websockets on port 8884
I did so. Here is the mosquitto conf entry:
listener 8884 127.0.0.1
protocol websockets
cafile /path/to/ca.crt
certfile /path/to/certfile.crt
keyfile /path/to/keyfile.key
require_certificate false
and so the app is trying to connect to myip:8884

How do you set up encrypted mosquitto broker like a webpage which has https?

I'm trying to setup a mosquitto broker which is encrypted using ssl/tls. I don't want to generate client certificates. I just want an encrypted connection.
The man page only described the settings which are available, not which are needed and how they are used.
Which settings are needed and how do you set them?
I use mosquitto 1.3.5
There is a small guide here, but it does not say much: http://mosquitto.org/man/mosquitto-tls-7.html
You need to set these:
certfile
keyfile
cafile
They can be generated with the commands in the link above. But easier is to use this script: https://github.com/owntracks/tools/blob/master/TLS/generate-CA.sh
After running the script and changing the config it could look something like this:
listener 8883
cafile /etc/mosquitto/certs/ca.crt
certfile /etc/mosquitto/certs/hostname.localdomain.crt
keyfile /etc/mosquitto/certs/hostname.localdomain.key
If mosquitto says Unable to load server key file it means that the user which is running mosquitto does not have permission to read the file. Even if you start it as root the broker might start as another user, mosquitto for example. To solve this do e.g. chown mosquitto:root keyfile
To connect to the broker the client will need the ca.crt-file. If you do not supply this the broker will say something like:
OpenSSL Error: error:1408F10B:SSL routines:SSL3_GET_RECORD:wrong version number
To supply it to the mosquitto_sub command you use --cafile pathToCaCrt. The ca.crt can be distributed with the clients and it will make sure that the server it is connected to actually is the correct server.
The --insecure flag of mosquitto_sub does not make the client accept all certificates (like with wget or similar), it just allows that the certificate not to have the host you are connecting to in common name. So you should make sure your certificate has your broker host as common name.
To secure WebSocket access of Mosquitto, e.g. using a Let's Encrypt certificate, your config file could look like this:
listener 9001
protocol websockets
certfile /etc/letsencrypt/live/yourdomain.com/cert.pem
cafile /etc/letsencrypt/live/yourdomain.com/chain.pem
keyfile /etc/letsencrypt/live/yourdomain.com/privkey.pem
Make sure that the files are readable by Mosquitto (Debian in particular runs Mosquitto under the mosquitto user, which is unprivileged). You need Mosquitto 1.4 to support WebSockets.
To connect to this WebSocket using the Paho JavaScript client:
// host and port overwritten at connect
var mqtt = new Paho.MQTT.Client("yourdomain.com", 9001, "");
mqtt.connect({
hosts: [ "wss://yourdomain.com:9001/" ],
useSSL: true
});
Note that this does not imply any access control yet, so your MQTT broker will be publicly accessible. You may want to add authorization, too.

Is there a way to validate the broker's SSL certificate in django-celery?

I'm using django-celery do connect to a RabbitMQ broker through SSL (with the BROKER_USE_SSL setting). Is there a way to:
Verify the certificate of the broker when the connection is established.
Configure a client certificate to us to establish the connection.
The RabbitMQ side is working correctly, but I don't know how to configure Celery for this and I haven't found anything in Celery's documentation either. The settings CELERY_SECURITY_KEY, CELERY_SECURITY_CERTIFICATE and CELERY_SECURITY_CERT_STORE look like they could do this, but it seems that they're only used for message signing.
kombu.Connection accepts ssl argument as a dictionary of SSL configuration (ssl=False by default). I suppose it is applicable for BROKER_USE_SSL too.
BROKER_USE_SSL={
'ca_certs': '/etc/pki/tls/certs/something.crt',
'keyfile': '/etc/something/system.key',
'certfile': '/etc/something/system.cert',
'cert_reqs': ssl.CERT_REQUIRED,
}