2023-11-25 16:10:36 -05:00

6.0 KiB

Mosquitto TLS Setup

There is an official guide from ChirpStack, which you can cross-reference. It is fairly complete, so some details are omitted here for brevity.

In the previous guide, you set up a Caddy web server to proxy the ChirpStack web interface, and you saw that Caddy automatically sets up TLS for you. This secures traffic between web browsers and ChirpStack.

However, you also need to secure traffic between gateways and ChirpStack. Because the communication protocol between the gateways and ChirpStack is MQTT and not HTTP, security is a little bit trickier. You will still use transport-layer security (TLS) to secure the traffic, but you need to create a certificate authority (CA). The CA is, itself, a certificate with corresponding secret key which you can use to issue certificates for the Mosquitto server and all the gateways connecting to it.

Create a CA

Start by installing the CloudFlare SSL tool:

sudo apt install golang-cfssl

Run these commands wherever you like (your home folder is fine) to create a few files:

# Certificate Signing Request (CSR) to create CA
# The "request" is local; no third-party involved.
cat <<EOF > ca-csr.json
{
  "CN": "ChirpStack CA",
  "key": {
    "algo": "rsa",
    "size": 4096
  }
}
EOF

# Settings for CA creation
cat <<EOF > ca-config.json
{
  "signing": {
    "default": {
      "expiry": "8760h"
    },
    "profiles": {
      "server": {
        "expiry": "8760h",
        "usages": [
          "signing",
          "key encipherment",
          "server auth"
        ]
      }
    }
  }
}
EOF

With those files in place, generate the CA:

cfssl gencert -initca ca-csr.json | cfssljson -bare ca

This creates three files:

  • ca.csr
  • ca.pem
  • ca-key.pem

You can discard ca.csr.

(Re-)Configure ChirpStack

Copy the remaining two files to a more permanent place and set ownership/permissions:

mkdir -p /etc/chirpstack/certs
cp ca.pem /etc/chirpstack/certs
cp ca-key.pem /etc/chirpstack/certs
chown -R chirpstack:chirpstack /etc/chirpstack/certs
chmod 400 /etc/chirpstack/certs/*

Then configure ChirpStack to use the CA by modifying /etc/chirpstack/chirpstack.toml to have the following:

[gateway]
  client_cert_lifetime="12months"
  ca_cert="/etc/chirpstack/certs/ca.pem"
  ca_key="/etc/chirpstack/certs/ca-key.pem"

The official guide also recommends editing the [integration.mqtt.client] section, but you don't need to in this setup. TODO learn about and explain downlinks

Finally, restart Chirpstack to use the updated configuration:

sudo systemctl restart chirpstack

Generate MQTT Server Certificate

Create a CSR for the MQTT server in the same place you created the CA, ensuring you replace the CN with your own site name:

cat <<EOF > mqtt-server.json
{
    "CN": "your.site.name",
    "hosts": [
        "your.site.name"
    ],
    "key": {
        "algo": "rsa",
        "size": 4096
    }
}
EOF

Generate the certificate:

cfssl gencert -ca ca.pem -ca-key ca-key.pem -config ca-config.json -profile server mqtt-server.json | cfssljson -bare mqtt-server

Three more files are generated:

  • mqtt-server.csr
  • mqtt-server.pem
  • mqtt-server-key.pem

You can discard mqtt-server.csr.

Configure MQTT Server

You need to move the other two files, as well as the CA certificate, to a place where Mosquitto can access them:

mkdir -p /etc/mosquitto/certs
cp ca.pem /etc/mosquitto/certs
cp mqtt-server.pem /etc/mosquitto/certs
cp mqtt-server-key.pem /etc/mosquitto/certs
chown root:mosquitto /etc/mosquitto/certs/mqtt-server-key.pem
chmod 640 /etc/mosquitto/certs/mqtt-server-key.pem

Next, add a configuration for Mosquitto to use a local, non-TLS listener (for use by ChirpStack and for debugging) and an internet-accessible TLS listener that uses the certificate files you just copied:

per_listener_settings true

listener 1883 127.0.0.1
allow_anonymous true

listener 8883 0.0.0.0
cafile /etc/mosquitto/certs/ca.pem
certfile /etc/mosquitto/certs/mqtt-server.pem
keyfile /etc/mosquitto/certs/mqtt-server-key.pem
allow_anonymous false
require_certificate true
use_identity_as_username true
acl_file /etc/mosquitto/acl

The acl_file setting references an access control list that doesn't exist yet but which will prevent gateways from reading/writing topics that don't belong to them. Create the file by running the following:

cat <<EOF > /etc/mosquitto/acl
pattern readwrite +/gateway/%u/#
pattern readwrite application/%u/#
EOF

With the configuration files in place, restart Mosquitto:

sudo systemctl restart mosquitto

Finally, if your server is running ufw, allow external traffic in to the port you configured Mosquitto to use for TLS:

sudo ufw allow 8883

Testing/Troubleshooting

Once set up, you can create a Gateway in ChirpStack and generate a TLS certificate. The certificate is only shown after being created; clicking the TLS tab again later will not show the cert but will let you generate another one. ChirpStack does not store these generated certs anywhere (TODO confirm). TODO add screenshots

Save the certs as ca.crt, cert.crt, and cert.key onto a test machine such as your local computer or a different cloud instance.

Install mosquitto-clients onto the test machine.

On the ChirpStack server, open a terminal window and subscribe to all messages:

mosquitto_sub  -h localhost -t "#" -v -d

Keep the terminal open, and on the test machine, send a message to the us915_1/gateway/<GATEWAY_ID>/test topic, substituting your.site.name and <GATEWAY_ID> accordingly:

mosquitto_pub \
  -h your.site.name \
  -p 8883 \
  --cafile ca.crt \
  --cert cert.crt \
  --key cert.key \
  -t "us915_1/gateway/<GATEWAY_ID>/test" \
  -d \
  -m "hello"

In the terminal window on the ChirpStack server, you should see a message show up. TODO add troubleshooting procedures and other expected output