mirror of
https://github.com/shankar0123/certctl.git
synced 2026-06-07 18:31:37 +00:00
082b8cf660
Extracts the file-based deploy target connectors: - haproxy.md (107 lines) — combined-PEM (cert+chain+key) deploy with haproxy -c validate; multi-frontend + crt-list directory guidance - traefik.md (105 lines) — file-provider zero-reload deploy; file watcher latency notes; mixing with built-in ACME guidance - caddy.md (100 lines) — admin API mode (recommended) vs file mode; admin-API exposure threat model - envoy.md (112 lines) — file SDS mode (recommended) vs static bootstrap; service-mesh interactions - postfix.md (175 lines) — dual-mode (Postfix MTA / Dovecot IMAPS) connector with daemon-specific quirks (STARTTLS chain expectations, no shared session cache); Bundle 11 test pins Index forward-list expanded to enumerate all 10 target connectors (5 from Phase 4 structural + 5 from this batch) in alphabetical order. This is part 3 of 4 for the Phase 4 follow-on (per-connector page extraction) tracked in cowork/docs-overhaul-phase-2-restructure-2026-05-04/log.md. Net add: 5 files, 599 lines. No content removed from index.md.
176 lines
6.4 KiB
Markdown
176 lines
6.4 KiB
Markdown
# Postfix / Dovecot Connector — Operator Deep-Dive
|
|
|
|
> Last reviewed: 2026-05-05
|
|
>
|
|
> Operator-grade documentation for the Postfix / Dovecot mail server
|
|
> TLS connector. For the connector-development context (interface
|
|
> contract, registry, atomic deploy primitive shared across all
|
|
> targets), see the [connector index](index.md).
|
|
|
|
## Overview
|
|
|
|
A dual-mode mail-server TLS connector. Writes certificate, key, and
|
|
chain files to configured paths and reloads the mail service. The
|
|
`mode` field selects between Postfix MTA and Dovecot IMAP/POP3,
|
|
which determines default file paths and reload commands.
|
|
|
|
This connector pairs with certctl's S/MIME certificate support
|
|
(email protection EKU, email SAN routing) for a complete email
|
|
infrastructure story — TLS for transport encryption, S/MIME for
|
|
end-to-end message signing and encryption.
|
|
|
|
Implementation lives at `internal/connector/target/postfix/`.
|
|
|
|
## When to use this connector
|
|
|
|
Use the Postfix / Dovecot connector when:
|
|
|
|
- You operate a self-hosted mail server (Postfix as MTA, Dovecot
|
|
as IMAPS/POP3S) and want certctl to rotate the TLS material in
|
|
place.
|
|
- You want validate-before-reload behaviour to keep a bad cert
|
|
config from taking down mail.
|
|
|
|
Look elsewhere when:
|
|
|
|
- You're running a mail provider (Google Workspace, Microsoft 365)
|
|
— the provider rotates certs internally.
|
|
- Your MTA is something else (Exim, Sendmail) — these don't have
|
|
built-in connectors yet; use a [generic file-based
|
|
target](index.md#target-connector) by hand or commission a
|
|
custom adapter.
|
|
|
|
## Configuration
|
|
|
|
### Postfix mode
|
|
|
|
```json
|
|
{
|
|
"mode": "postfix",
|
|
"cert_path": "/etc/postfix/certs/cert.pem",
|
|
"key_path": "/etc/postfix/certs/key.pem",
|
|
"chain_path": "/etc/postfix/certs/chain.pem",
|
|
"reload_command": "postfix reload",
|
|
"validate_command": "postfix check"
|
|
}
|
|
```
|
|
|
|
### Dovecot mode
|
|
|
|
```json
|
|
{
|
|
"mode": "dovecot",
|
|
"cert_path": "/etc/dovecot/certs/cert.pem",
|
|
"key_path": "/etc/dovecot/certs/key.pem",
|
|
"chain_path": "/etc/dovecot/certs/chain.pem",
|
|
"reload_command": "doveadm reload",
|
|
"validate_command": "doveconf -n"
|
|
}
|
|
```
|
|
|
|
### Field reference
|
|
|
|
| Field | Default (Postfix) | Default (Dovecot) | Description |
|
|
|---|---|---|---|
|
|
| `mode` | `postfix` | `dovecot` | Service mode — determines defaults |
|
|
| `cert_path` | `/etc/postfix/certs/cert.pem` | `/etc/dovecot/certs/cert.pem` | Path for certificate file |
|
|
| `key_path` | `/etc/postfix/certs/key.pem` | `/etc/dovecot/certs/key.pem` | Path for private key (0600 permissions) |
|
|
| `chain_path` | (empty) | (empty) | If set, chain written separately; otherwise appended to cert |
|
|
| `reload_command` | `postfix reload` | `doveadm reload` | Command to reload the mail service |
|
|
| `validate_command` | `postfix check` | `doveconf -n` | Optional config validation before reload |
|
|
|
|
All commands are validated against shell injection via
|
|
`validation.ValidateShellCommand()`. File permissions: cert /
|
|
chain 0644, key 0600.
|
|
|
|
## Choosing Mode=postfix vs Mode=dovecot
|
|
|
|
Both modes share the same Go connector code (atomic-write,
|
|
PreCommit/PostCommit hooks, post-deploy verify, rollback), so the
|
|
rollback contract is identical across modes. The mode flag just
|
|
swaps the daemon-specific defaults.
|
|
|
|
`mode: postfix` is also the **default when `mode` is unset**.
|
|
|
|
### Hosts running BOTH Postfix and Dovecot
|
|
|
|
The common mail-server pattern. Configure **two separate targets**
|
|
in the certctl control plane, one per daemon. Each gets its own
|
|
cert path, its own validate / reload command, and its own
|
|
optional verify endpoint. The cert + key bytes can be identical
|
|
across the two targets if your mail server uses the same TLS
|
|
material for both daemons (which many do); certctl does not
|
|
deduplicate the deploys, but the byte-equal cert hits the
|
|
SHA-256 idempotency short-circuit on subsequent renewals when
|
|
the target paths haven't changed.
|
|
|
|
### Sharing a single cert file across daemons via symlink
|
|
|
|
Works fine with the connector — the atomic-write path's
|
|
`os.Rename` follows symlinks. Configure both targets to point at
|
|
the same canonical path, or have one target's `cert_path`
|
|
symlink into the other's. Operators who want byte-deduplication
|
|
should rely on this approach rather than asking certctl to
|
|
coordinate it.
|
|
|
|
## Daemon-specific quirks
|
|
|
|
### Postfix STARTTLS (port 25)
|
|
|
|
Typically requires the cert to chain to a public root for
|
|
receiving mail from arbitrary external MTAs that validate
|
|
SMTP-side server certs. If you're deploying a self-signed cert
|
|
from `iss-local`, configure the receiving Postfix accordingly
|
|
(e.g. `smtpd_use_tls=yes` + `smtpd_tls_security_level=may` for
|
|
opportunistic TLS so external senders that don't validate
|
|
continue to deliver).
|
|
|
|
### Dovecot IMAPS (port 993)
|
|
|
|
Typically client-facing — the chain you ship matters more here
|
|
because IMAPS clients (Thunderbird, Outlook) actively validate.
|
|
Set `chain_path` if your certificate chain is supplied
|
|
separately; when `chain_path` is unset, the connector appends the
|
|
chain bytes to `cert_path`.
|
|
|
|
### No shared TLS session cache
|
|
|
|
Postfix and Dovecot do not share a TLS session cache by default.
|
|
Both reload independently, so a cert renewal that updates both
|
|
targets via certctl requires both reloads to succeed before
|
|
clients re-handshake. The two targets are fully independent in
|
|
the certctl scheduler — one reload failing rolls back that
|
|
target only.
|
|
|
|
## Post-deploy verify
|
|
|
|
Operator-supplied via `post_deploy_verify` (`enabled` +
|
|
`endpoint` + `timeout`) — the connector does NOT bake in a
|
|
per-mode default port. Operators that opt in should set
|
|
`endpoint` to their daemon's listener (e.g. `mail.example.com:25`
|
|
for Postfix STARTTLS, `mail.example.com:993` for Dovecot IMAPS).
|
|
|
|
## Test pins
|
|
|
|
Bundle 11 (commit `88e8881`) added end-to-end tests for
|
|
`Mode=dovecot`:
|
|
|
|
- `TestPostfix_Atomic_DovecotMode_HappyPath` — confirms
|
|
`applyDefaults` populates the dovecot validate + reload
|
|
commands AND the deploy threads them through to `runValidate`
|
|
+ `runReload`.
|
|
- `TestPostfix_Atomic_DovecotMode_VerifyFails_Rollback` —
|
|
confirms the rollback path under `Mode=dovecot` restores
|
|
pre-deploy cert + key bytes byte-exact.
|
|
|
|
The `Mode=postfix` branch has equivalent test coverage in the
|
|
same file (see `TestPostfix_HappyPath`,
|
|
`TestPostfix_VerifyMismatch_Rollback`,
|
|
`TestPostfix_ReloadFails_Rollback`).
|
|
|
|
## Related docs
|
|
|
|
- [Connector index](index.md) — interface contract, registry, deploy primitive
|
|
- [NGINX](nginx.md) — comparable file-based deploy with explicit reload
|
|
- [Apache](apache.md) — comparable file-based deploy with `apachectl configtest`
|