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

[question]Aedes with Let's Encrypt and Paho mqtt client #1019

Open
hchautrung opened this issue Nov 3, 2024 · 4 comments
Open

[question]Aedes with Let's Encrypt and Paho mqtt client #1019

hchautrung opened this issue Nov 3, 2024 · 4 comments
Labels

Comments

@hchautrung
Copy link

hchautrung commented Nov 3, 2024

Hi all,

I want to implement MQTT over TLS using generated Let's Encrypt of domain mqtt.llos.unimetaverse.net.

  1. use nginx stream configuration
stream {
  log_format basic '$proxy_protocol_addr - $remote_addr [$time_local] $protocol $status $bytes_sent $bytes_received $session_time "$upstream_addr"';

  access_log /var/www/llos-mqtt.unimetaverse.net/logs/stream.log basic;
  error_log /var/www/llos-mqtt.unimetaverse.net/logs/stream-error.log;

  upstream backend {
    hash $remote_addr consistent;
    server 192.168.98.56:8883;  # MQTT broker address and port
  }

  server {
    listen 8883 ssl;  # Listen on port 443 for MQTT over SSL
    listen [::]:8883 ssl;

    # SSL configuration
    ssl_certificate /var/www/mqtt.llos.unimetaverse.net/letsencrypt/fullchain.pem;
    ssl_certificate_key  /etc/letsencrypt/live/mqtt.llos.unimetaverse.net/privkey.pem;
    ssl_trusted_certificate  /etc/letsencrypt/live/mqtt.llos.unimetaverse.net/chain.pem;

    #Optional: Enhance security settings. Use a unique name for SSL session cache to avoid conflicts
    ssl_session_cache shared:MQTT_SSL:10m;
    ssl_session_timeout 10m;

    ssl_prefer_server_ciphers on;

    proxy_connect_timeout 1s;
    proxy_timeout 10m; # is default

    proxy_pass backend;
  }
}
  1. Backend Node.js MQTT using aedes hosting in local IP 192.168.98.56 and open firewall port 8883
const tls = require('tls');
const aedes = require('aedes')();

const ca = fs.readFileSync('certs/signed.llos.unimetaverse.net/fullchain.pem');
const key = fs.readFileSync('certs/signed.llos.unimetaverse.net/privkey.pem');
const cert = fs.readFileSync('certs/signed.llos.unimetaverse.net/cert.pem');

const tls_port = 8883;

const tls_options = {
        ca: ca,
        key: key,
        cert: cert,
        requestCert: false,
        rejectUnauthorized: false
};

const mqtt_server = tls.createServer(tls_options, aedes.handle)
mqtt_server.listen(tls_port, function () {
    console.log(`LLOS's MQTT Broker listening on port ${tls_port}...`)
})

mqtt_server.on('secureConnection', (conn) => {
        console.log(`SECURE_CONNECTION`);
});

Note: fullchain.pem is generated by Let's Encrypt only contains intermediate cert and certificate only, not including root-ca certificate.

  1. Client using paho to connect to the broker using the generated let's encrypt
LLOS_ENDPOINT = "mqtt.llos.unimetaverse.net" # "172.16.2.177"
LLOS_PORT = 8883
PATH_TO_LLOS_ROOT_CA = "../certs/signed.llos.unimetaverse.net/root_fullchain.pem"
PATH_TO_LLOS_CERTIFICATE = "../certs/signed.llos.unimetaverse.net/cert.pem"
PATH_TO_LLOS_PRIVATE_KEY = "../certs/signed.llos.unimetaverse.net/privkey.pem"

def connect_llos():
    client = paho_mqtt.Client(paho_mqtt.CallbackAPIVersion.VERSION2, CLIENT_ID)
    client.username_pw_set("", "")
    client.tls_set(ca_certs=PATH_TO_LLOS_ROOT_CA, 
                   keyfile=PATH_TO_LLOS_PRIVATE_KEY,
                   certfile=PATH_TO_LLOS_CERTIFICATE,
                   cert_reqs=ssl.CERT_REQUIRED,
                   tls_version=ssl.PROTOCOL_TLSv1_2)
    #client.tls_insecure_set(True)
    print("Connecting to {} with client ID '{}'...".format(LLOS_ENDPOINT, CLIENT_ID))
    client.connect(LLOS_ENDPOINT, LLOS_PORT, 60)
    client.loop_start()

    return client

def main():
    client = connect_llos()

Run the Python script and get the error ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get issuer certificate (_ssl.c:1000)

To resolve the error I have to merge the root CA into fullchain.pem and update Python script to use the merged file root_fullchain.pem

$ curl -o isrgrootx1.pem https://letsencrypt.org/certs/isrgrootx1.pem
$ cp fullchain.pem root_fullchain.pem
$ cat isrgrootx1.pem >> root_fullchain.pem

Run the Python script again without error but the console.log(SECURE_CONNECTION) not showing.

Any one can help on this

Thank you

@robertsLando
Copy link
Member

you are missing aedes.handle part in your code

@hchautrung
Copy link
Author

@robertsLando its included const mqtt_server = tls.createServer(tls_options, aedes.handle) . It works fine on localhost with a self singed certificate without Nginx

@robertsLando
Copy link
Member

Sorry missed that line, anyway I have no clue how to help here, for sure it's a misconfiguration on nginx or you are creating certificates wrongly

@hchautrung
Copy link
Author

Hi removed ssl and cert part in the nginx config and it works, I quite not understand.

stream {

  log_format basic '$proxy_protocol_addr - $remote_addr [$time_local] $protocol $status $bytes_sent $bytes_received $session_time "$upstream_addr"';

  access_log /var/www/llos-mqtt.unimetaverse.net/logs/stream.log basic;
  error_log /var/www/llos-mqtt.unimetaverse.net/logs/stream-error.log;

  upstream backend {
    hash $remote_addr consistent;
    server 192.168.98.56:8883;  # Your actual MQTT broker address and port
  }

  server {
    listen 8883;

    proxy_connect_timeout 1s;
    proxy_timeout 10m; # is default

    proxy_pass backend;
  }
}


Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants