SSL/TLS with Eclipse Paho JavaScript Client - ssl

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

Related

Mosquitto MQTT client certificate exception

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

Connect to RabbitMQ via URL

I'm trying to connect to the rabbitmq which is hidden behind nginx proxy. It's declared as:
location ^~ /rabbitmq/ {
proxy_pass http://127.0.0.1:5672/;
}
The problem is that as I found AMPQ only specifies host but it doesn't know anything about urls.
Can I connect rabbit client to www.myserver.com/rabbitmq somehow? I'm using EasyNetQ to connect, but it looks like a protocol limitation, and implementation doesn't matter.
If it's not possible at all maybe there are some workarounds?
For AMQP, If using Nginx probably doing a TCP load balancing could help: https://docs.nginx.com/nginx/admin-guide/load-balancer/tcp-udp-load-balancer/, otherwise if you could use HAProxy you could try something like this:
frontend rabbitmq
mode tcp
bind *:5672
use_backend bunny
backend bunny
mode tcp
server bunny 127.0.0.1:5672 check
If you want to publish message over HTTP probably you would like to expose the rabbitmq API:
http://localhost:15672/api/index.html
Notice the port 15672, from the docs:
Note that the UI and HTTP API port — typically 15672 — does not support AMQP 0-9-1, AMQP 1.0, STOMP or MQTT connections. Separate ports should be used by those clients.

Mosquitto - Internal & External Client Configuration

I was wondering if there is a way to configure Mosquitto to require TLS and client certificates if it is connecting to an external clients and not to require TLS and client certificate for internal clients. Should I do anything with the CA(Certficiate Authority) or .conf files? What would I need to do to configure it properly to accomplish this? Any help on this would be greatly appreciated.
If you want to use the same port (1883) for both internal and external then you will probably need the broker machine to have 2 network interfaces (one internal, one external) so you can bind the listeners to different IP addresses (e.g. not doing port forwarding).
If you are doing port forwarding then you will have to use different ports for internal/external.
Assuming 2 interfaces:
# internal
port 1883
bind_address <internal-ip>
#external
listener <external-ip>:1883
cafile /path/to/ca/cert
keyfile /path/to/key
certfiel /path/to/cert
require_certificate true
This should allow anonymous none ssl connections internally and SSL + Client certificates from outside.
If you are doing port forwarding remove the external ip address and change the port number it listens on, you can still forward 1883 from the router.

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

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.