upstream-tls-verify: Verified TLS to an inbound domain's upstream

Owner, 2026-10-18: "Оба предложения делаем"; the mockup is c10cd78. The
security audit's M7: Required is Postfix's encrypt level, which checks no
certificate - it keeps the mail from a listener, not from one who answers
in the upstream's place.

- A fourth TLS mode, Verified, stored as Postfix's level secure (migration
  0014 rebuilds inbound_transports with the wider CHECK; schema 14) and
  written to the TLS policy map like the others. Postfix matches the
  certificate against the next hop's name (smtp_tls_secure_cert_match =
  nexthop, dot-nexthop, the default; postconf(5)), so Verified is refused
  for an upstream given by address (checkSecureHost).
- Postfix's SMTP client trusts Debian's ca-certificates bundle
  (smtp_tls_CAfile): Postfix trusts none by default (DEF_SMTP_TLS_CA_FILE
  "", DEF_TLS_APPEND_DEF_CA 0). The levels may and encrypt only log the
  verdict, so mail to recipients' MX is unchanged.
- The page: the select's fourth option, a help line under it, the lead
  "over verified TLS", the list's tag "verified"; Help word for word with
  the mockup; guide § Inbound relay, with a posttls-finger command to try
  an upstream first.

Tests: TestVerifiedTLSNeedsTheUpstreamsName, TestRenderInboundMapsSecure,
TestUpstreamTLSModeSecure; schema tests at 14. e2e
inbound_upstream_verified_tls: an address refused, a name saved as
"[sink]:25 secure" in tls_policy, the page says verified, the CA file set
and present, and posttls-finger -l secure with it calls the stand's
self-signed port 25 "Untrusted" (the stand has no TLS upstream). make e2e
(65 passed) and go vet + go test (26 packages) on the test server for this
tree. Tried against the live upstream from the 2.14.5 container:
mc-ent.mixfed.ru gives "Verified TLS connection established".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
mix
2026-10-18 10:27:37 +03:00
co-authored by Claude Opus 5.5
parent c10cd78eff
commit 6b4106f60e
17 changed files with 215 additions and 14 deletions
+13 -2
View File
@@ -1237,10 +1237,21 @@ for such a sender.
**Panel** (`/inbound/domains`): the global role adds and deletes domains. On a
domain's page, set the upstream host/port and TLS to that hop (opportunistic /
required / off), and choose recipients. *Required* is Postfix's `encrypt`
required / verified / off), and choose recipients. *Required* is Postfix's `encrypt`
level: the hop is encrypted, but the upstream's certificate is not checked,
so it guards against someone who listens on the way, not against one who
answers in the upstream's place. An upstream has one TLS mode: Postfix
answers in the upstream's place. *Verified* is Postfix's `secure` level: the
certificate must be issued by an authority Debian's `ca-certificates`
trusts, for the upstream's host name - so the upstream is given by name,
not by address (the panel refuses an address with it), and mail waits in
the queue while the check fails, a self-signed certificate or one for
another name included. To try an upstream before choosing it:
```sh
docker exec <container> posttls-finger -c -l secure -F /etc/ssl/certs/ca-certificates.crt "[mx.example.com]:25"
```
"Verified TLS connection established" means it will pass. An upstream has one TLS mode: Postfix
keeps the TLS policy per next hop, not per domain, so the mode saved for one
domain is the mode of every domain forwarded to the same host and port, and
they are changed with it; a *domain* user who does not manage all of them is