martin-doyle / node-red-contrib-aedes

MQTT broker for Node-RED based on Aedes
MIT License
61 stars 11 forks source link

Aedes over mTLS #76

Open jowavp opened 6 months ago

jowavp commented 6 months ago

Hi,

I am trying to use aesed on nodered with an mTLS connection. The only port that can be used is the https port so connection will be over websockets.

image

so I expect that I can connect to the broker on: wss://my.domain.com/ws/mqtt

I created a nodejs client to connect like this:

import mqtt from "mqtt";
import fs from "fs";

const protocol = "wss";
const host = "my.domain.com/ws/mqtt";
const port = "443";
const clientId = `mqtt_${Math.random().toString(16).slice(3)}`;

const connectUrl = `${protocol}://${host}:${port}`;

// certs for mtls
var caFile3 = fs.readFileSync("./certs/ISRoot.crt");
var certFile = fs.readFileSync("./certs/client_cert.pem");
var keyFile = fs.readFileSync("./certs/client_key.pem");

const client = mqtt.connect(connectUrl, {
  clientId,
  clean: true,
  ca: [caFile3],
  cert: certFile,
  rejectUnauthorized: true,
  key: keyFile,
  connectTimeout: 4000,
  reconnectPeriod: 1000,
});

client.on("connect", () => {
  console.log("Connected");
});

client.on("error", (err) => {
  console.log("Connection error: ", err);
  client.end();
});

client.on("reconnect", (error) => {
  console.log("Reconnecting...");
});

The result in the console is always: Reconnecting ...

When we deploy a simple nodejs program with aedes broker in stead of the nodered application, the connection over mTLS is working.

code of the simple nodejs broker:

import Aedes from "aedes";
import { createServer } from "http";
import ws from "websocket-stream";

const httpServer = createServer();
const port = process.env.PORT || 8888;
const aedes = new Aedes();

// emitted when a client connects to the broker
aedes.on("client", function (client) {
  console.log(
    `[CLIENT_CONNECTED] Client ${
      client ? client.id : client
    } connected to broker ${aedes.id}`
  );
});

// emitted when a client disconnects from the broker
aedes.on("clientDisconnect", function (client) {
  console.log(
    `[CLIENT_DISCONNECTED] Client ${
      client ? client.id : client
    } disconnected from the broker ${aedes.id}`
  );
});

// emitted when a client subscribes to a message topic
aedes.on("subscribe", function (subscriptions, client) {
  console.log(
    `[TOPIC_SUBSCRIBED] Client ${
      client ? client.id : client
    } subscribed to topics: ${subscriptions
      .map((s) => s.topic)
      .join(",")} on broker ${aedes.id}`
  );
});

// emitted when a client unsubscribes from a message topic
aedes.on("unsubscribe", function (subscriptions, client) {
  console.log(
    `[TOPIC_UNSUBSCRIBED] Client ${
      client ? client.id : client
    } unsubscribed to topics: ${subscriptions.join(",")} from broker ${
      aedes.id
    }`
  );
});

// emitted when a client publishes a message packet on the topic
aedes.on("publish", async function (packet, client) {
  if (client) {
    console.log(
      `[MESSAGE_PUBLISHED] Client ${
        client ? client.id : "BROKER_" + aedes.id
      } has published message on ${packet.topic} to broker ${aedes.id}`
    );
  }
});

ws.createServer({ server: httpServer }, aedes.handle);

httpServer.listen(port, function () {
  console.log("websocket server listening on port ", port);
});

What are we missing in the nodered configuration to run the mqtt broker over websockets and mTLS?

kr, Joachim

martin-doyle commented 6 months ago

I think you need to enable SSL/TLS including server certificates in order to setup a secure connection. What error messages do you get in the Node-RED logs?