panel-dkim-signing stage 2: OpenDKIM removed
test / test (push) Canceled after 0s

The panel's signer is the only one. Gone: the opendkim package and its
configuration, the syslog-relay and opendkim programs, /dev/log and
/run/opendkim, the reload by USR1 through supervisord
(internal/supervisor/supervisor.go), internal/syslogrelay, the port of
OpenDKIM's From: parser (internal/milter/mailparse.go and its probe,
harness and test/upstream scripts), OPENDKIM_SOCKET and OPENDKIM_DIR.

Keys: internal/domain/keys.go (Keys, NewKeys, DKIM_DIR=/data/dkim) keeps
the keys and writes a selector table, /data/dkim/selectors ("<name>
<selector>"), which the signer reads in place of the KeyTable - it reads
no database, as the sender check reads none. The table is written before
the signer serves (EnsureServerSigned moved there from the notifier).
Keys and table 0600, directories 0700, the panel's. The entrypoint copies
/data/opendkim/keys once, as the panel user, into /data/dkim.new renamed
when whole, and stops the start if the copy fails; /data/opendkim is left
for a rollback to 2.7.x.

Sender check: one RFC 5322 address as a mail program reads it, held
against the bindings; the 256-byte refusal and the texts naming OpenDKIM
go. Allowed() folded the domain through strings.ToLower, which makes the
Kelvin sign a "k" - the comparison with OpenDKIM's reading had hidden it;
it folds ASCII only now.

Health: two dkim-signer rows (applications, notifications) in Milter
sockets, opendkim out of the liveness set; the card no longer takes any
row with a note for the spam filter. Texts as in the design commit.

KILL stays in deploy/docker-compose.yml: measured on the test server,
root without it cannot signal a process of another uid - supervisord
stopping the panel, Postfix's master its children. The plan's "only use
was the reload" was wrong; the comment now gives the real uses.

e2e: one signature, the panel's, verified by dkimpy; the /data/dkim modes;
the OpenDKIM log and process checks, testNeverSignedForAnother and the
cited opendkim, libopendkim11 and libmilter1.0.1 go.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
mix
2026-10-16 01:05:39 +03:00
co-authored by Claude Opus 5.5
parent 005922bc7d
commit faa3c11ae7
96 changed files with 971 additions and 2247 deletions
+2 -3
View File
@@ -1148,9 +1148,8 @@ unsupported rather than as a missing doc:
and `build/postfix-wrapper.sh`, which must agree), `MAIL_LOG`
(`/data/log/mail.log` — read by the panel and written by Postfix, so a change
here has to be matched in `build/postfix-config.sh`),
`PANEL_COOKIE_SECURE` (`true`), `OPENDKIM_SOCKET`
(`/run/opendkim/opendkim.sock`), `OPENDKIM_DIR` (`/data/opendkim`),
`DKIM_SELECTOR_DEFAULT` (`selfpost`), `SASL_DB_PATH`
`PANEL_COOKIE_SECURE` (`true`), `DKIM_DIR` (`/data/dkim` — the keys and
the selector table), `DKIM_SELECTOR_DEFAULT` (`selfpost`), `SASL_DB_PATH`
(`/data/sasl/sasldb2`), `SASL_REALM` (defaults to `SELFPOST_HOSTNAME`),
`POSTFIX_DIR` (`/data/postfix`), `POSTFIX_SENDER_LOGIN_MAPS`
(`/data/postfix/sender_login_maps` — read by Postfix config only; the panel
-3
View File
@@ -253,9 +253,6 @@ re-read what changed, update the citations, then this table:
| Package | Version read |
|---|---|
| `postfix` | `3.10.13-0+deb13u1` |
| `opendkim` | `2.11.0~beta2-9.1+b1` |
| `libopendkim11` | `2.11.0~beta2-9.1+b1` |
| `libmilter1.0.1` | `8.18.1-6+b1` |
| `libsasl2-2` | `2.1.28+dfsg1-9` |
| `sasl2-bin` | `2.1.28+dfsg1-9` |
| `supervisor` | `4.2.5-3` |
+30 -7
View File
@@ -155,25 +155,48 @@ Two findings while writing it: a folded header reaches a milter
`-separated (the signer rebuilds CRLF), and go-milter calls no Abort on a
dropped connection (a one-hour watchdog closes the signer).
### Stage 2 - OpenDKIM removed (no release)
### Stage 2 - OpenDKIM removed (no release) - done
- [ ] Chain: OpenDKIM out of both milter lists.
- [ ] Go: `internal/domain/opendkim.go` reduced to key storage (tables,
- [x] Chain: OpenDKIM out of both milter lists.
- [x] Go: `internal/domain/opendkim.go` reduced to key storage (tables,
`Rebuild`, `assertConfigSafe`, the USR1 reload go), `internal/supervisor`
(its only caller is the reload), `internal/syslogrelay`,
`internal/milter/mailparse.go` and its tests and testdata, the
sender-check texts; Resync's "OpenDKIM's tables" step; Health's
liveness set and socket row (Q3); `OPENDKIM_SOCKET`/`OPENDKIM_DIR`.
- [ ] Image: the `opendkim` package, `opendkim.conf`, the two supervisord
- [x] Image: the `opendkim` package, `opendkim.conf`, the two supervisord
programs, the `/dev/log` link and `/run/opendkim`, `usermod -aG selfpost
opendkim`, crashexit's spared list; `deploy/docker-compose.yml`'s `KILL`
capability (its only use was the reload).
- [ ] Keys: `/data/opendkim/keys` -> `/data/dkim/keys` (Q2): the entrypoint
capability (its only use was the reload) - **kept, see below**.
- [x] Keys: `/data/opendkim/keys` -> `/data/dkim/keys` (Q2): the entrypoint
copies the tree once and leaves the old one for a rollback to 2.7.x until
the next release; KeyTable and SigningTable go with the new layout.
- [ ] Tests: `test/upstream/*.sh`, e2e's OpenDKIM log and process checks,
- [x] Tests: `test/upstream/*.sh`, e2e's OpenDKIM log and process checks,
the 256-byte test rewritten for the new rule.
*Done (2026-10-16):* `internal/domain/keys.go` (`Keys`, `NewKeys`,
`DKIM_DIR`) keeps the keys and writes a selector table,
`/data/dkim/selectors`, a line `<name> <selector>` each, which the signer
reads instead of the KeyTable: the signer reads no database, as the sender
check reads none - the panel's one SQLite connection is shared with the
pages, and a long query would hold up mail. The table is written before the
signer serves (`EnsureServerSigned`, moved there from the notifier), so the
first start of 2.8.0 needs nothing of the operator. Keys and table are
0600, directories 0700, owned by the panel; the entrypoint copies the old
keys as the panel user (`setpriv`), into `/data/dkim.new`, renamed when
whole, and stops the start if the copy fails - else the server's name would
get a new key. Three findings: `KILL` stays - measured on the test server,
root without it cannot signal a process of another uid, and supervisord
stops the panel and Postfix's master its children that way (the plan's
"only use" was wrong); the sender check's `Allowed` took the domain through
`strings.ToLower`, which makes the Kelvin sign a "k" - the comparison with
OpenDKIM's reading had hidden it, it now folds ASCII only; the Milter
sockets card told the spam filter by its row having a note, which the
signer's rows have too. The e2e drops the OpenDKIM-only cases
(`testNeverSignedForAnother`) and checks the one signature, the tree's
modes and the cited packages without opendkim, libopendkim11 and
libmilter1.0.1.
### Stage 3 - documents, the canary, the cut
- [ ] architecture § OpenDKIM -> § DKIM signing; security.md (the
+1 -1
View File
@@ -44,7 +44,7 @@ in `git log` and [CHANGELOG.md](../CHANGELOG.md).
| own-mta-builds | Analysis: build Postfix and OpenDKIM ourselves, patched, instead of Debian's packages | analysed 2026-10-15: no own builds; three rows proposed instead | — | [own-mta-builds-2026-10-15.md](own-mta-builds-2026-10-15.md) |
| port25-bare-newline | The inbound relay's port 25 refuses bare newlines in DATA (`smtpd_forbid_bare_newline=normalize`) | shipped `2.6.1` | — | — |
| base-trixie | The image's base from Debian bookworm (LTS since 2026-07-12) to trixie: Postfix 3.10 with the 2026 security batches | shipped `2.7.0` | — | — |
| panel-dkim-signing | DKIM signing in the panel's own milter; OpenDKIM, the syslog relay and the parser port removed | agreed (2026-10-15; stage 1 done) | 5/14 | [plans/panel-dkim-signing.md](plans/panel-dkim-signing.md) |
| panel-dkim-signing | DKIM signing in the panel's own milter; OpenDKIM, the syslog relay and the parser port removed | agreed (2026-10-15; stages 1-2 done) | 10/14 | [plans/panel-dkim-signing.md](plans/panel-dkim-signing.md) |
| phone-desktop-mode | A phone browser in "desktop site" mode gets the phone navigation | agreed (2026-10-13: after stages 1 and 2 of audit-2026-10-12) | — | — |
| from-header-binding | Hold a message's `From:` header against the application that sends it | shipped `2.4.0` | 9/9 | [plans/from-header-binding.md](plans/from-header-binding.md) |
| panel-redesign | Panel redesign (accepted mockups, design contract) | shipped `2.0.0` | 27/27 | [plans/panel-redesign.md](plans/panel-redesign.md) |