diff --git a/doc/0-chirpstack/2-mosquitto-tls.md b/doc/0-chirpstack/2-mosquitto-tls.md index ca0856b..e27087f 100644 --- a/doc/0-chirpstack/2-mosquitto-tls.md +++ b/doc/0-chirpstack/2-mosquitto-tls.md @@ -1,65 +1,210 @@ # Mosquitto TLS Setup -Ref: +There is an [official guide](https://www.chirpstack.io/docs/guides/mosquitto-tls-configuration.html) from ChirpStack, which you can cross-reference. It is fairly complete, so some details are omitted here for brevity. -You generate a certificate authority which has the following purposes: +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. -- Generate a Mosquitto server certificate so gateways can connect to it via TLS -- Generate client certificates for gateways so they can prove their identity to the Mosquitto server +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. -When you create the CA, three files are generated: +## Create a CA + +Start by installing the CloudFlare SSL tool: + +```sh +sudo apt install golang-cfssl +``` + +Run these commands wherever you like (your home folder is fine) to create a few files: + +```sh +# Certificate Signing Request (CSR) to create CA +# The "request" is local; no third-party involved. +cat < ca-csr.json +{ + "CN": "ChirpStack CA", + "key": { + "algo": "rsa", + "size": 4096 + } +} +EOF + +# Settings for CA creation +cat < 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: + +```sh +cfssl gencert -initca ca-csr.json | cfssljson -bare ca +``` + +This creates three files: - `ca.csr` - `ca.pem` - `ca-key.pem` -Then when you create the MQTT cert, three more files are generated: +You can discard `ca.csr`. + +## (Re-)Configure ChirpStack + +Copy the remaining two files to a more permanent place and set ownership/permissions: + +```sh +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: + +```toml +[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](https://www.chirpstack.io/docs/chirpstack/integrations/mqtt.html#scheduling-a-downlink)** + +Finally, restart Chirpstack to use the updated configuration: + +```sh +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: + +```sh +cat < mqtt-server.json +{ + "CN": "your.site.name", + "hosts": [ + "your.site.name" + ], + "key": { + "algo": "rsa", + "size": 4096 + } +} +EOF +``` + +Generate the certificate: + +```sh +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` -Then you add the CA (with its key) to the ChirpStack config. Make sure to change ownership to `chirpstack` when copying certs to `/etc/chirpstack/certs`. +You can discard `mqtt-server.csr`. -Then create a folder for MQTT cert and copy files. +## Configure MQTT Server -Set ownership and permission on the key: +You need to move the other two files, as well as the CA certificate, to a place where Mosquitto can access them: ```sh +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 ``` -Once set up, you can create a Gateway in ChirpStack and generate a TLS certificate. It is only shown after being created; clicking the TLS tab again later will not show the cert but will let you generate a new one. Certs don't seem to be stored anywhere. +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: -Don't forget to allow `8883` in the firewall. +```sh +per_listener_settings true -## Gateway Bridge Config +listener 1883 127.0.0.1 +allow_anonymous true -Create `/etc/chirpstack-gateway-bridge/certs` folder and copy certs in. Make everything owned by `gatewaybridge`. Set permission to `640`. +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 +``` -Modify the config, ref: +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: -Don't forget to change `tcp` to `ssl` in the server list. +```sh +cat < /etc/mosquitto/acl +pattern readwrite +/gateway/%u/# +pattern readwrite application/%u/# +EOF +``` -Check `journalctl` on both the bridge and Mosquitto to see that the connection is established. +With the configuration files in place, restart Mosquitto: -Be sure to set the Gateway ID in both the `chirpstack-gateway-bridge` and `packet-forwarder` configs (though this doesn't seem to matter? Need to experiment). Also be sure the UDP port matches between the two. +```sh +sudo systemctl restart mosquitto +``` -## Troubleshooting +Finally, if your server is running `ufw`, allow external traffic in to the port you configured Mosquitto to use for TLS: -Install `mosquitto-clients` on the Gateway. +```sh +sudo ufw allow 8883 +``` -Send a message to the `test` topic: +## 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: + +```sh +mosquitto_sub -h localhost -t "#" -v -d +``` + +Keep the terminal open, and on the test machine, send a message to the `us915_1/gateway//test` topic, substituting `` accordingly: ```sh mosquitto_pub \ - -h chirpstack.roeber.dev \ + -h your.site.name \ -p 8883 \ - --cafile /etc/chirpstack-gateway-bridge/certs/ca.crt \ - --cert /etc/chirpstack-gateway-bridge/certs/cert.crt \ - --key /etc/chirpstack-gateway-bridge/certs/cert.key \ - -t "test" \ + --cafile ca.crt \ + --cert cert.crt \ + --key cert.key \ + -t "us915_1/gateway//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** diff --git a/doc/0-overview.md b/doc/0-overview.md index e1f07e0..782ad0c 100644 --- a/doc/0-overview.md +++ b/doc/0-overview.md @@ -74,9 +74,8 @@ Experience with the following is recommended but not required if you are able to - Rent compute from a cloud vendor - Secure shell (SSH) - Caddy web server - - TLS certificate generation - - Let's Encrypt - - DNS-01 protocol + - Transport Layer Security (TLS) + - Certificates and secret keys - Self-generated certificate authority - [`cfssl`](https://github.com/cloudflare/cfssl) - Mosquitto MQTT diff --git a/doc/1-gateway/1-gateway-bridge.md b/doc/1-gateway/1-gateway-bridge.md index 9707619..1195b21 100644 --- a/doc/1-gateway/1-gateway-bridge.md +++ b/doc/1-gateway/1-gateway-bridge.md @@ -58,4 +58,16 @@ Add/change some values: ```toml event_topic_template="us915_1/gateway/{{ .GatewayID }}/event/{{ .EventType }}" command_topic_template="us915_1/gateway/{{ .GatewayID }}/command/#" -```` +``` + +## Gateway Bridge Config + +Create `/etc/chirpstack-gateway-bridge/certs` folder and copy certs in. Make everything owned by `gatewaybridge`. Set permission to `640`. + +Modify the config, ref: + +Don't forget to change `tcp` to `ssl` in the server list. + +Check `journalctl` on both the bridge and Mosquitto to see that the connection is established. + +Be sure to set the Gateway ID in both the `chirpstack-gateway-bridge` and `packet-forwarder` configs (though this doesn't seem to matter? Need to experiment). Also be sure the UDP port matches between the two.