Skip to content

fix(mqtt): allow TLS without a custom CA certificate - #23997

Open
NoiceHax wants to merge 1 commit into
blakeblackshear:devfrom
NoiceHax:fix/issue-2471
Open

fix(mqtt): allow TLS without a custom CA certificate#23997
NoiceHax wants to merge 1 commit into
blakeblackshear:devfrom
NoiceHax:fix/issue-2471

Conversation

@NoiceHax

Copy link
Copy Markdown

Proposed change

Frigate only calls paho's tls_set() when tls_ca_certs is set, so there is no way to talk to a broker over TLS when the broker certificate is signed by a public CA such as Let's Encrypt. The workaround people have landed on in #2471 is to point tls_ca_certs at /etc/ssl/certs/ca-certificates.crt, which is just the system trust store paho would have used on its own. paho's tls_set() falls back to load_default_certs() when ca_certs is None, so this change enables TLS when any of the tls_ options is set and passes tls_ca_certs straight through. Leaving it unset now means "use the system certificates" instead of "do not use TLS at all".

The same block had a second problem. tls_insecure_set() was called outside the tls_ca_certs check, and paho raises ValueError: Must configure SSL context before using tls_insecure_set. when no SSL context exists yet. That means a config with tls_insecure but no tls_ca_certs threw out of the dispatcher setup and Frigate did not start. That call now sits inside the TLS branch, after tls_set() has built the context. tls_set() already calls tls_insecure_set(False) itself, so keeping the explicit call after it is still correct for anyone who wants tls_insecure: true.

No new config option, and no schema or UI change. I added frigate/test/test_mqtt_tls.py covering the four cases (no TLS options, CA only, client certs without a CA, and tls_insecure on its own), and updated the comments for tls_ca_certs in the config reference so it reads as optional and only needed for a private CA.

Type of change

  • Dependency upgrade
  • Bugfix (non-breaking change which fixes an issue)
  • New feature
  • Breaking change (fix/feature causing existing functionality to break)
  • Code quality improvements to existing code
  • Documentation Update

Additional information

For new features

Not a new feature, this is a bugfix, so there is nothing to link here.

  • There is an existing feature request or discussion with community interest for this change.
    • Link:

AI disclosure

  • No AI tools were used in this PR.
  • AI tools were used in this PR. Details below:

AI tool(s) used (e.g., Claude, Copilot, ChatGPT, Cursor): Claude Code

How AI was used (e.g., code generation, code review, debugging, documentation): code generation for the rewritten TLS block, the new test module, and the doc comment wording.

Extent of AI involvement (e.g., generated entire implementation, assisted with specific functions, suggested fixes): it wrote the change to _start() and the test file from the approach I described, which is about a dozen lines of source plus the tests.

Human oversight: I read through paho's client.py myself to confirm that tls_set(None) calls load_default_certs() and that tls_insecure_set() raises when _ssl_context is None, which is what the fix relies on. I went over the diff line by line, ran the new tests against the old code to check they actually fail (the tls_insecure one raises the ValueError, the client cert one shows tls_set never being called) and against the new code to check they pass, and ran ruff format --check and ruff check. I could not run the whole suite locally since most of it needs dependencies that will not install on my machine, so I only ran the two MQTT test modules.

Checklist

  • The code change is tested and works locally.
  • Local tests pass. Your PR cannot be merged unless tests pass
  • There is no commented out code in this PR.
  • I can explain every line of code in this PR if asked.
  • UI changes including text have used i18n keys and have been added to the en locale.
  • The code has been formatted using Ruff (ruff format frigate)

tls_set() was only called when tls_ca_certs was set, so a broker whose
certificate is signed by a public CA could not be used over TLS without
pointing tls_ca_certs at the system trust store by hand. paho falls back
to the system certificates when ca_certs is None, so any tls_ option now
enables TLS and tls_ca_certs is passed through unchanged.

tls_insecure_set() also ran outside that branch, and paho raises
ValueError when no SSL context has been configured yet, so a config with
tls_insecure but no tls_ca_certs failed to start. It now runs inside the
TLS branch, after tls_set() has built the context.
@greptile-apps

greptile-apps Bot commented Aug 15, 2026

Copy link
Copy Markdown

Greptile Summary

The PR allows MQTT TLS to use the system trust store when no custom CA is configured and ensures the SSL context exists before applying tls_insecure.

  • Enables TLS when a client certificate or tls_insecure option is configured
  • Passes an absent CA through to Paho so it loads system certificates
  • Adds focused MQTT TLS setup tests and updates the reference configuration

Confidence Score: 4/5

The partial client-certificate configuration path should be fixed before merging because it silently discards supplied credentials and leaves mutual-TLS connections failing without a clear configuration error.

The main public-CA and tls_insecure paths are handled correctly, but the new TLS gate exposes accepted partial client-credential configurations that are not passed to Paho or rejected during validation.

Files Needing Attention: frigate/comms/mqtt.py

Important Files Changed

Filename Overview
frigate/comms/mqtt.py Reworks TLS initialization correctly for public CAs, but accepts partial client-credential configurations and silently omits the supplied credential.
frigate/test/test_mqtt_tls.py Covers the principal TLS activation cases but does not exercise unpaired client certificate and key values.
docs/docs/configuration/advanced/reference.md Clarifies that a custom CA is optional and that other TLS options enable TLS.

Reviews (1): Last reviewed commit: "fix(mqtt): allow TLS without a custom CA..." | Re-trigger Greptile

Comment thread frigate/comms/mqtt.py
Comment on lines +342 to +343
or self.mqtt_config.tls_client_cert is not None
or self.mqtt_config.tls_insecure is not None

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Partial client credentials are discarded

If a configuration supplies only tls_client_cert or tls_client_key, the config model accepts it but this TLS setup silently omits the credential, causing brokers that require mutual TLS to reject the connection without a clear configuration error.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Support]: MQTT Configuration does not support MQTTS without self-signed certs

1 participant