Skip to content

fix(tls): Don't push a wildcard cert to servers in a nested root domain - #7395

Open
vanglian wants to merge 1 commit into
frappe:developfrom
vanglian:fix-wildcard-tls-selects-nested-root-domain-servers
Open

vanglian wants to merge 1 commit into
frappe:developfrom
vanglian:fix-wildcard-tls-selects-nested-root-domain-servers

Conversation

@vanglian

@vanglian vanglian commented Sep 7, 2026

Copy link
Copy Markdown

Problem

TLSCertificate.trigger_server_tls_setup_callback() picks the servers to push a renewed wildcard certificate to by pattern-matching the server's name:

filters={
    "status": ("not in", ["Archived", "Installing"]),
    "name": ("like", f"%.{self.domain}"),
},

SQL % matches any character, dots included. So a wildcard certificate for a parent root domain also selects every server whose own root domain is nested inside it — %.fc.dev matches n2.internal.fc.dev just as readily as n1.fc.dev.

A wildcard covers exactly one label, so *.fc.dev is not valid for n2.internal.fc.dev. The push replaces a working certificate with one that fails hostname verification, and every agent request to that server then dies with:

SSLCertVerificationError: Hostname mismatch,
certificate is not valid for 'n2.internal.fc.dev'

This is silent until something tries to talk to the agent. In our deployment it broke site backups for ~28 hours before anyone noticed, and it recurs on every renewal of the parent domain's certificate.

It only affects installs that nest one Root Domain inside another — e.g. tenant sites on fc.dev with server hostnames under internal.fc.dev.

Fix

Match domain exactly instead of pattern-matching the name.

This isn't a new convention — it's the one the codebase already uses. BaseServer.get_certificate() resolves the reverse mapping with an exact domain match:

certificate_name = frappe.db.get_value(
    "TLS Certificate", {"wildcard": True, "domain": self.domain}, "name"
)

The two functions are inverses of one another and disagreed: one exact, one fuzzy. After this change they agree. setup_standalone_wildcard_hosts() in the same file already filters on domain exactly too.

All nine server doctypes in the list (Server, Proxy Server, Database Server, Log, Monitor, Registry, Analytics, Trace, NAT Server) carry domain as a Link to Root Domain, so the filter is valid for each.

Tenant-site TLS is unaffected: that travels via _update_secondary_wildcard_domains() / setup_standalone_wildcard_hosts()setup_wildcard_hosts() on the agent API, not through this callback's tls.yml path. A proxy serving *.fc.dev for tenant sites still receives it.

Test

test_wildcard_renewal_does_not_target_servers_in_a_nested_root_domain asserts both halves, since a fix that stopped the over-matching but also stopped legitimate renewals would trade a loud failure for a silent one:

  • the parent domain's own server is still targeted
  • the nested domain's server is not

Verification

Reproduced and confirmed against a live install by calling the real trigger_server_tls_setup_callback() with frappe.enqueue stubbed out and the transaction rolled back, on a deployment with <tenant>.example.com sites and *.internal.example.com server hostnames:

Certificate Before After
*.example.com targeted all 3 internal. servers targets none
*.internal.example.com targeted the 3 servers targets the same 3

🤖 Generated with Claude Code

- `trigger_server_tls_setup_callback` selected servers with
  `name LIKE '%.<domain>'`. SQL `%` matches dots, so a wildcard certificate
  for a parent root domain also selected every server whose own root domain
  is nested inside it -- `%.fc.dev` matches `n2.internal.fc.dev`.
- A wildcard covers exactly one label, so `*.fc.dev` is not valid for
  `n2.internal.fc.dev`. Pushing it there replaces a working certificate with
  one that fails hostname verification, breaking agent communication until
  it is repaired by hand.
- Match `domain` exactly instead. This mirrors `BaseServer.get_certificate`,
  which already resolves the reverse mapping with an exact `domain` match --
  the two are inverses of each other and disagreed.
- Add a regression test covering both halves: the parent domain's servers are
  still targeted, and the nested domain's servers are not.
@greptile-apps

greptile-apps Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Confidence Score: 5/5

Safe to merge.

The filter aligns certificate deployment with persisted server root domains, and no actionable defect was found.

Reviews (1): Last reviewed commit: "fix(tls): Don't push a wildcard cert to ..." | Re-trigger Greptile

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.

1 participant