Relay: each relay's certificate, ordered by DNS-01 (RL-27) #269

Merged
jcoffey-dev merged 1 commits from relay/certificates into main 2026-10-30 23:27:25 +00:00
Owner

Each relay's SMTP certificate, ordered by this server over DNS-01 (relay spec, RL-27).

  • When: a joined, enabled relay needs a certificate when it has none, when its certificate doesn't name its public name (a wildcard covers only one level down), or when it runs out within 30 days.
  • From where: the public name must be under a domain whose DNS and certificates are both Automatic here. The closest such domain is used, with its ACME provider and its DNS server.
  • How: always DNS-01, whatever challenge the provider uses for the domain itself, because the relay opens no port 80. The certificate is for the public name alone, with its own key, so the domain's wildcard key never leaves this server. A renewal keeps the relay's key; a new name gets a new one.
  • Who orders: the link service checks at each scan, and one node orders. It claims the order under c + relay id first, and a claim lasts an hour. A failed order waits six hours before the next, for the provider's rate limits.
  • Install: the certificate is stored on the relay unless its public name changed during the order, and every link pushes it with the settings. ACME order-start, order-completed and order-invalid events name the relay.
  • On inbuxa:Relay: new read-only certificateNotAfter (read from the stored certificate) and certificateError (why the last order failed).
  • Manual: without such a domain, nothing is ordered, and an administrator uploads smtpCertificate and smtpPrivateKey as before. An uploaded certificate that still does is left alone.
  • Removing a relay also removes its order record.

Tests:

  • Unit tests pass: when a relay needs a certificate (missing, unreadable, another name, expiring, wildcard depth) and when an order may run again.
  • automation_tests now has a relay case against pebble, run locally with the cached images. A joined relay named mx1.dns.org gets a certificate for that name alone, by DNS-01. It's not among this server's own certificates, certificateNotAfter is set with no error, it isn't ordered again, and its order record goes when the relay is removed.
  • relay_tests and relay_link_tests pass. fmt, clippy on the changed files, and the fork checks are clean.

Not in this PR: showing certificateError in inbuxa-admin's Relays page (next, small), and upgrades (RL-29).

Each relay's SMTP certificate, ordered by this server over DNS-01 (relay spec, RL-27). - **When:** a joined, enabled relay needs a certificate when it has none, when its certificate doesn't name its public name (a wildcard covers only one level down), or when it runs out within 30 days. - **From where:** the public name must be under a domain whose DNS and certificates are both Automatic here. The closest such domain is used, with its ACME provider and its DNS server. - **How:** always DNS-01, whatever challenge the provider uses for the domain itself, because the relay opens no port 80. The certificate is for the public name alone, with its own key, so the domain's wildcard key never leaves this server. A renewal keeps the relay's key; a new name gets a new one. - **Who orders:** the link service checks at each scan, and one node orders. It claims the order under `c` + relay id first, and a claim lasts an hour. A failed order waits six hours before the next, for the provider's rate limits. - **Install:** the certificate is stored on the relay unless its public name changed during the order, and every link pushes it with the settings. ACME `order-start`, `order-completed` and `order-invalid` events name the relay. - **On `inbuxa:Relay`:** new read-only `certificateNotAfter` (read from the stored certificate) and `certificateError` (why the last order failed). - **Manual:** without such a domain, nothing is ordered, and an administrator uploads `smtpCertificate` and `smtpPrivateKey` as before. An uploaded certificate that still does is left alone. - Removing a relay also removes its order record. Tests: - Unit tests pass: when a relay needs a certificate (missing, unreadable, another name, expiring, wildcard depth) and when an order may run again. - `automation_tests` now has a relay case against pebble, run locally with the cached images. A joined relay named `mx1.dns.org` gets a certificate for that name alone, by DNS-01. It's not among this server's own certificates, `certificateNotAfter` is set with no error, it isn't ordered again, and its order record goes when the relay is removed. - `relay_tests` and `relay_link_tests` pass. fmt, clippy on the changed files, and the fork checks are clean. Not in this PR: showing `certificateError` in inbuxa-admin's Relays page (next, small), and upgrades (RL-29).
jcoffey-dev added 1 commit 2026-10-30 22:19:46 +00:00
Relay: each relay's certificate, ordered by DNS-01 (RL-27)
ci / fork-checks (pull_request) Skipped
ci / build (pull_request) Skipped
github/ci (branch) GitHub Actions
ci / github (pull_request) Successful in 9m26s
de3c4f0c75
A joined relay whose certificate is missing, for another name, or runs
out within 30 days gets one for its public name, when the name is under
a domain whose DNS and certificates are both Automatic here. The order
uses that domain's ACME provider and DNS server, always by DNS-01, for
the public name alone and with a key of its own: never the domain's
wildcard key. A renewal keeps the relay's key.

The link service checks at each scan. One node orders: it claims the
order under `c` + relay id first. A failed order waits six hours, for
the provider's rate limits, and its reason is the relay's new
certificateError; certificateNotAfter reads the stored certificate. The
certificate goes on the relay unless its public name changed meanwhile,
and every link pushes it. Without such a domain, nothing is ordered and
an administrator uploads one, as before.

Tested against pebble in the automation tests.
jcoffey-dev merged commit 5ec9af2241 into main 2026-10-30 23:27:25 +00:00
jcoffey-dev deleted branch relay/certificates 2026-10-30 23:27:25 +00:00
Sign in to join this conversation.