diff --git a/.woodpecker/build-cli.yml b/.woodpecker/build-cli.yml index 44081d4c..1936d0d8 100644 --- a/.woodpecker/build-cli.yml +++ b/.woodpecker/build-cli.yml @@ -26,8 +26,5 @@ steps: dockerfile: cli/Dockerfile context: cli auto_tag: true - cache_images: registry.viktorbarzin.lan:5050/infra:buildcache - buildkit_config: | - [registry."registry.viktorbarzin.lan:5050"] - http = true - insecure = true + insecure: true + buildkit_config: "[registry.\"registry.viktorbarzin.lan:5050\"]\n http = true\n insecure = true\n" diff --git a/docs/plans/2026-02-23-mailserver-hardening-design.md b/docs/plans/2026-02-23-mailserver-hardening-design.md new file mode 100644 index 00000000..33657c20 --- /dev/null +++ b/docs/plans/2026-02-23-mailserver-hardening-design.md @@ -0,0 +1,62 @@ +# Mail Server Lightweight Hardening Design + +**Date**: 2026-02-23 +**Scope**: Security, reliability, and hygiene improvements to the docker-mailserver stack + +## Current State + +- docker-mailserver 15.0.0 on K8s (single replica, Recreate strategy) +- Roundcubemail webmail (MySQL-backed, debug logging on, unpinned :latest tag) +- Outbound relay via Mailgun, inbound MX via ForwardEmail +- OpenDKIM for DKIM signing, no spam filtering (SpamAssassin/ClamAV/Amavis disabled) +- DMARC policy `none` (monitoring only) +- No brute-force protection, no mailserver-down alert +- Dovecot exporter sidecar (unpinned), stale SendGrid DNS records + +## Changes + +### 1. Enable Rspamd (replace OpenDKIM as DKIM signer) + +Add to `mailserver_env_config`: +- `ENABLE_RSPAMD = "1"` (spam filtering, DKIM verification, phishing detection, Oletools) +- `ENABLE_OPENDKIM = "0"` (Rspamd handles DKIM signing natively) +- `RSPAMD_LEARN = "1"` (learn from Junk folder movements) + +Existing OpenDKIM key mounts stay — Rspamd reads them from the same paths. +Resource impact: ~150-200MB additional RAM. + +### 2. DMARC DNS enforcement + +Update `_dmarc` TXT record: `p=none` -> `p=quarantine`. Can tighten to `p=reject` after validation. + +### 3. Postfix rate limiting + +Add to `postfix_cf`: +``` +smtpd_client_connection_rate_limit = 10 +smtpd_client_message_rate_limit = 30 +anvil_rate_time_unit = 60s +``` + +Service already uses `externalTrafficPolicy: Local`, so real client IPs are visible to Postfix. +ForwardEmail IPs on port 25 are subject to same limits but 10 conn/min is generous. + +### 4. Prometheus alert + +Uncomment the existing mailserver-down alert in `prometheus_chart_values.tpl`. + +### 5. Roundcubemail cleanup + +- Pin image: `roundcube/roundcubemail:latest` -> `roundcube/roundcubemail:1.6-apache` +- Disable debug: `ROUNDCUBEMAIL_SMTP_DEBUG = "false"`, `ROUNDCUBEMAIL_DEBUG_LEVEL = "1"` + +### 6. SendGrid DNS cleanup + +Remove stale CNAME records: `em7107`, `s1._domainkey`, `s2._domainkey`. + +## Not Changing + +- Roundcubemail stays (user preference) +- ForwardEmail/Mailgun relay stays (practical dependency) +- ClamAV stays disabled (Rspamd Oletools covers malicious attachments) +- Single replica (HA email requires significant additional complexity) diff --git a/docs/plans/2026-02-23-mailserver-hardening-plan.md b/docs/plans/2026-02-23-mailserver-hardening-plan.md new file mode 100644 index 00000000..b555017f --- /dev/null +++ b/docs/plans/2026-02-23-mailserver-hardening-plan.md @@ -0,0 +1,315 @@ +# Mail Server Lightweight Hardening Implementation Plan + +> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. + +**Goal:** Harden the mail server with spam filtering (Rspamd), DMARC enforcement, rate limiting, monitoring alerts, and hygiene cleanup. + +**Architecture:** All changes are to the existing docker-mailserver 15.0.0 deployment managed by Terraform. Rspamd replaces OpenDKIM for DKIM signing and adds spam filtering. DMARC moves from `none` to `quarantine` in Cloudflare DNS. Postfix gets rate-limiting parameters. Prometheus gets a mailserver-down alert. Roundcubemail debug logging is disabled and image pinned. + +**Tech Stack:** Terraform/HCL, docker-mailserver, Rspamd, Cloudflare DNS, Prometheus + +--- + +### Task 1: Enable Rspamd and disable OpenDKIM + +**Files:** +- Modify: `stacks/platform/modules/mailserver/main.tf:39-62` (env ConfigMap) + +**Step 1: Add Rspamd env vars to the ConfigMap** + +In `stacks/platform/modules/mailserver/main.tf`, in the `kubernetes_config_map.mailserver_env_config` resource `data` block, add these entries and modify existing ones: + +```hcl + data = { + DMS_DEBUG = "0" + ENABLE_CLAMAV = "0" + ENABLE_AMAVIS = "0" + ENABLE_FAIL2BAN = "0" + ENABLE_FETCHMAIL = "0" + ENABLE_POSTGREY = "0" + ENABLE_SASLAUTHD = "0" + ENABLE_SPAMASSASSIN = "0" + ENABLE_SRS = "1" + ENABLE_RSPAMD = "1" + ENABLE_OPENDKIM = "0" + ENABLE_OPENDMARC = "0" + RSPAMD_LEARN = "1" + FETCHMAIL_POLL = "120" + ONE_DIR = "1" + OVERRIDE_HOSTNAME = "mail.viktorbarzin.me" + POSTFIX_MESSAGE_SIZE_LIMIT = 1024 * 1024 * 200 # 200 MB + POSTFIX_REJECT_UNKNOWN_CLIENT_HOSTNAME = "1" + DEFAULT_RELAY_HOST = "[smtp.eu.mailgun.org]:587" + SPOOF_PROTECTION = "1" + SSL_TYPE = "manual" + SSL_CERT_PATH = "/tmp/ssl/tls.crt" + SSL_KEY_PATH = "/tmp/ssl/tls.key" + } +``` + +The key additions are: `ENABLE_RSPAMD = "1"`, `ENABLE_OPENDKIM = "0"`, `ENABLE_OPENDMARC = "0"`, `RSPAMD_LEARN = "1"`. + +**Note:** The existing OpenDKIM volume mounts (KeyTable, SigningTable, TrustedHosts, opendkim keys) should stay mounted. docker-mailserver's Rspamd integration reads the DKIM key from the same path (`/tmp/docker-mailserver/opendkim/keys/`) to configure Rspamd's DKIM signing module automatically. + +**Step 2: Commit** + +```bash +git add stacks/platform/modules/mailserver/main.tf +git commit -m "[ci skip] mailserver: enable Rspamd, disable OpenDKIM" +``` + +--- + +### Task 2: Add Postfix rate limiting + +**Files:** +- Modify: `stacks/platform/modules/mailserver/variables.tf:3-22` (postfix_cf variable) + +**Step 1: Add rate limiting parameters to postfix_cf** + +In `stacks/platform/modules/mailserver/variables.tf`, append these lines to the `postfix_cf` default value, before the `EOT`: + +``` +smtpd_client_connection_rate_limit = 10 +smtpd_client_message_rate_limit = 30 +anvil_rate_time_unit = 60s +``` + +The full `postfix_cf` variable should become: + +```hcl +variable "postfix_cf" { + default = <