Skip to content

Enable TLS on the broker, with server-certificate verification on every client #25

Open

Description

@bazauto

#7 put usernames, passwords and an ACL on the bench broker (#24), but everything still crosses the LAN in plain text. Anyone who can sniff that segment gets the passwords, and with the io-node password they can publish readings the orchestrator will trust. TLS closes that. Deferred until the certificates are sorted out.

Hostname verification: the cert has to match the name each client dials

None of these clients has a separate "expected hostname" setting. Each one checks the certificate against the host it connected to, so the cert needs a SAN for every name in use:

Client Dials today Verifies hostname?
Orchestrator (mqtt.js on Node tls) localhost (MQTT_URL) Yes, by default. IP SANs are supported.
mosquitto_sub/_pub with --cafile localhost on the bench, the IP or a name from the LAN Yes, unless --insecure
io-node (ESP-AT) 172.18.10.240 (config.MQTT_HOST) Unverified. See below.

So a cert with these SANs covers everything as configured today:

DNS:pbarrett-HP-EliteDesk-800-G2.localdomain   # resolves via 172.18.10.1 today
DNS:localhost
IP:127.0.0.1
IP:172.18.10.240

Alternatively, give the broker a stable alias such as mqtt.localdomain on the router, and point clients at that. Moving the Pico to a DNS name adds a dependency on the router's DNS to a node whose silence is dangerous. Keeping it on the IP avoids that.

ESP-AT: what has to be checked on the bench first

These are all not yet verified. The modem's ESP-AT version is not recorded anywhere yet (AT+GMR).

  • TLS support at all. AT+MQTTUSERCFG's scheme becomes 3 (verify the server cert) rather than 1 (plain TCP). Scheme 2 encrypts without verifying anything, and that is not worth doing, because it doesn't stop a MITM.
  • How the CA gets onto the modem. ESP-AT reads certificates from its own flash partition, not per connection over AT. Recent versions write that partition with AT+SYSMFG; older ones need the partition reflashed with esptool. The deploy would have to provision the modem as well as the Pico.
  • Whether it checks the hostname against an IP. The esp-tls layer passes the AT+MQTTCONN host through for verification. Older mbedTLS matches DNS SANs and the CN only, not IP SANs. If so, the Pico needs either a DNS name or a CN of 172.18.10.240.
  • Clock. If certificate validity dates are enforced and the modem has no SNTP time, a fresh cert can read as "not yet valid". Check whether AT+CIPSNTPCFG is needed.
  • A refused handshake will flash code 5, the same as any broker fault. docs/broker-auth.md and docs/startup-and-status-led.md should say that.

Broker shape

  • TLS listener on 8883 for the LAN.
  • 1883 either goes or is restricted to loopback for the orchestrator. Note Broker accepts loopback connections only, so no node can publish #7's warning: listener 1883 127.0.0.1 drops [::1], and the orchestrator's localhost may resolve to either. Moving the orchestrator to mqtts://localhost:8883 with the CA avoids the question.
  • Keep password_file and acl_file on every listener. TLS protects the password in transit; it doesn't replace the ACL.

Expiry is an outage

An expired server cert takes every client off the broker at once. The node would flash code 5, the orchestrator would lose its sensors, and blocks would degrade to unknown. Choose a long validity for a private CA, and record the renewal date and procedure in docs/broker-auth.md. Consider a check that warns ahead of expiry.

Later, optional

Client certificates (ESP-AT schemes 4 and 5) could replace per-node passwords. The ACL can then key on the cert's CN with use_identity_as_username. That's more provisioning, and the ACL already limits what a stolen node credential can do, so it's not part of this issue.

Acceptance

  • The node connects over TLS with server-certificate verification enabled (not scheme 2), and it's proven on the bench that the node refuses a cert signed by a different CA.
  • The orchestrator and bench mosquitto_sub connect with the CA. Plain-text connects to the LAN listener are refused.
  • A packet capture of a node publish shows no readable password or payload.
  • docs/broker-auth.md covers the CA, the SANs, expiry and renewal, and modem provisioning.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions