## Context
docker-mailserver 15.0.0's default Postfix config does NOT set
`smtpd_tls_auth_only = yes`. Clients that skip STARTTLS on port 587
(or 25 with AUTH) can send PLAIN/LOGIN creds in cleartext. CrowdSec
and rate limiting don't catch this — it's an auth-path leak, not a
bruteforce. Addresses bd code-vnw.
## This change
Adds `smtpd_tls_auth_only = yes` to `postfix_cf` (applied via the
`postfix-main.cf` ConfigMap key consumed by docker-mailserver).
Rolled the pod to pick up the new ConfigMap.
### Deviation from task spec
code-vnw's fix field cited `smtpd_sasl_auth_only = yes`. That is NOT
a real Postfix parameter — attempting it gets
`postconf: warning: smtpd_sasl_auth_only: unknown parameter`. The
acceptance test (reject PLAIN auth before STARTTLS) is satisfied by
`smtpd_tls_auth_only`, which is the correct knob. Added an inline
comment noting the common confusion.
## What is NOT in this change
- Per-service override in master.cf (smtpd_tls_auth_only applied
globally, which is safe because port 25 doesn't accept AUTH here)
- Other Postfix hardening (sender_restrictions, etc.)
## Test Plan
### Automated
```
$ kubectl exec -n mailserver -c docker-mailserver deployment/mailserver -- \
postconf smtpd_tls_auth_only
smtpd_tls_auth_only = yes
$ kubectl rollout status deployment/mailserver -n mailserver
deployment "mailserver" successfully rolled out
```
### Manual Verification
1. `openssl s_client -connect mail.viktorbarzin.me:587 -starttls smtp`
2. At prompt, send `AUTH PLAIN <base64>` BEFORE `STARTTLS`
3. Expected: Postfix rejects with `503 5.5.1 Error: authentication not enabled`
4. Follow-up: STARTTLS first, then `AUTH PLAIN <base64>` — succeeds for valid creds
## Reproduce locally
1. From a shell with `kubectl` access to the cluster:
2. `kubectl exec -n mailserver -c docker-mailserver deployment/mailserver -- postconf smtpd_tls_auth_only`
3. Expected: `smtpd_tls_auth_only = yes`
Closes: code-vnw
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
46 lines
2.8 KiB
HCL
46 lines
2.8 KiB
HCL
# this is appended and merged to the main postfix.cf
|
|
# see defaults - https://github.com/docker-mailserver/docker-mailserver/blob/master/target/postfix/main.cf
|
|
variable "postfix_cf" {
|
|
default = <<EOT
|
|
#relayhost = [smtp.sendgrid.net]:587
|
|
relayhost = [smtp-relay.brevo.com]:587
|
|
smtp_sasl_auth_enable = yes
|
|
smtp_sasl_password_maps = hash:/etc/postfix/sasl/passwd
|
|
smtp_sasl_security_options = noanonymous
|
|
smtp_sasl_tls_security_options = noanonymous
|
|
smtp_tls_security_level = encrypt
|
|
smtpd_tls_cert_file=/tmp/ssl/tls.crt
|
|
smtpd_tls_key_file=/tmp/ssl/tls.key
|
|
smtpd_use_tls=yes
|
|
# Require STARTTLS before any AUTH command on the SMTPD listener.
|
|
# Without this, a misconfigured client that skips STARTTLS would send
|
|
# PLAIN/LOGIN creds in the clear. docker-mailserver's default does NOT
|
|
# enforce this at the main.cf level for submission (587).
|
|
# Note: smtpd_sasl_auth_only (sometimes cited) is NOT a real Postfix
|
|
# parameter — only smtpd_tls_auth_only is. Addresses code-vnw.
|
|
smtpd_tls_auth_only = yes
|
|
header_size_limit = 4096000
|
|
|
|
# Debug mail tls
|
|
smtpd_tls_loglevel = 1
|
|
#smtpd_tls_ciphers = TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:!aNULL:!SEED:!CAMELLIA:!RSA+AES:!SHA1
|
|
#tls_medium_cipherlist = ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:!aNULL:!SEED:!CAMELLIA:!RSA+AES:!SHA1
|
|
|
|
# Rate limiting (brute-force protection)
|
|
smtpd_client_connection_rate_limit = 10
|
|
smtpd_client_message_rate_limit = 30
|
|
anvil_rate_time_unit = 60s
|
|
|
|
# Disable the postscreen decision cache. The default (btree) driver
|
|
# requires an exclusive file lock for every access, and with postscreen
|
|
# re-spawning per connection (master.cf: maxproc=1) that produces thousands
|
|
# of 'unable to get exclusive lock' fatals per day — stalling SMTP
|
|
# acceptance and starving inbound delivery. lmdb would avoid the lock but
|
|
# isn't compiled into docker-mailserver 15.0.0's Postfix build
|
|
# (postconf -m → no lmdb). Proxy:btree is unsafe because postscreen does
|
|
# its own locking. An empty value disables the cache entirely — legitimate
|
|
# clients pay the greet/bare-newline re-check on every new TCP session,
|
|
# which is trivial at our volume (~100 deliveries/day).
|
|
postscreen_cache_map =
|
|
EOT
|
|
}
|