From 7501dbca7dbc349fa767324310d975e9eef50093 Mon Sep 17 00:00:00 2001 From: unkin-agent Date: Mon, 12 Oct 2026 21:33:42 +1100 Subject: [PATCH] Add postfix smarthost to the mail namespace --- apps/base/mail/kustomization.yaml | 16 +++ apps/base/mail/smarthost-pdb.yaml | 11 ++ apps/base/mail/smarthost-service.yaml | 39 ++++++++ apps/base/mail/smarthost-statefulset.yaml | 116 ++++++++++++++++++++++ apps/base/mail/smarthost/gateways.cidr | 2 + apps/base/mail/smarthost/main.cf | 42 ++++++++ apps/base/mail/smarthost/master.cf | 38 +++++++ apps/base/mail/smarthost/milter.cidr | 1 + apps/base/mail/smarthost/relay_domains | 1 + apps/base/mail/smarthost/transport | 1 + 10 files changed, 267 insertions(+) create mode 100644 apps/base/mail/smarthost-pdb.yaml create mode 100644 apps/base/mail/smarthost-service.yaml create mode 100644 apps/base/mail/smarthost-statefulset.yaml create mode 100644 apps/base/mail/smarthost/gateways.cidr create mode 100644 apps/base/mail/smarthost/main.cf create mode 100644 apps/base/mail/smarthost/master.cf create mode 100644 apps/base/mail/smarthost/milter.cidr create mode 100644 apps/base/mail/smarthost/relay_domains create mode 100644 apps/base/mail/smarthost/transport diff --git a/apps/base/mail/kustomization.yaml b/apps/base/mail/kustomization.yaml index ebe64ef..6b7f837 100644 --- a/apps/base/mail/kustomization.yaml +++ b/apps/base/mail/kustomization.yaml @@ -6,4 +6,20 @@ resources: - cnpg_backup.yaml - cnpg_cluster.yaml - namespace.yaml + - smarthost-pdb.yaml + - smarthost-service.yaml + - smarthost-statefulset.yaml - stalwart-blobs-bucket.yaml + +configMapGenerator: + - name: smarthost-config + namespace: mail + options: + disableNameSuffixHash: true + files: + - smarthost/main.cf + - smarthost/master.cf + - smarthost/relay_domains + - smarthost/transport + - smarthost/gateways.cidr + - smarthost/milter.cidr diff --git a/apps/base/mail/smarthost-pdb.yaml b/apps/base/mail/smarthost-pdb.yaml new file mode 100644 index 0000000..272d9cf --- /dev/null +++ b/apps/base/mail/smarthost-pdb.yaml @@ -0,0 +1,11 @@ +--- +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: smarthost + namespace: mail +spec: + maxUnavailable: 1 + selector: + matchLabels: + app.kubernetes.io/name: smarthost diff --git a/apps/base/mail/smarthost-service.yaml b/apps/base/mail/smarthost-service.yaml new file mode 100644 index 0000000..025947a --- /dev/null +++ b/apps/base/mail/smarthost-service.yaml @@ -0,0 +1,39 @@ +--- +apiVersion: v1 +kind: Service +metadata: + name: smarthost + namespace: mail +spec: + type: ClusterIP + selector: + app.kubernetes.io/name: smarthost + ports: + - name: smtp + port: 25 + targetPort: smtp + - name: submission + port: 587 + targetPort: submission +--- +# Gateways and lab networks; Local keeps client IPs for the postfix CIDR checks. +apiVersion: v1 +kind: Service +metadata: + name: smarthost-lb + namespace: mail + annotations: + purelb.io/addresses: 198.18.200.16 + purelb.io/service-group: common +spec: + type: LoadBalancer + externalTrafficPolicy: Local + selector: + app.kubernetes.io/name: smarthost + ports: + - name: smtp + port: 25 + targetPort: smtp + - name: submission + port: 587 + targetPort: submission diff --git a/apps/base/mail/smarthost-statefulset.yaml b/apps/base/mail/smarthost-statefulset.yaml new file mode 100644 index 0000000..224184e --- /dev/null +++ b/apps/base/mail/smarthost-statefulset.yaml @@ -0,0 +1,116 @@ +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: smarthost + namespace: mail + annotations: + configmap.reloader.stakater.com/reload: "smarthost-config" +spec: + serviceName: smarthost + replicas: 2 + selector: + matchLabels: + app.kubernetes.io/name: smarthost + template: + metadata: + labels: + app.kubernetes.io/name: smarthost + spec: + topologySpreadConstraints: + - maxSkew: 1 + topologyKey: kubernetes.io/hostname + whenUnsatisfiable: DoNotSchedule + labelSelector: + matchLabels: + app.kubernetes.io/name: smarthost + securityContext: + seccompProfile: + type: RuntimeDefault + containers: + - name: postfix + image: artifactapi.k8s.syd1.au.unkin.net/docker-internal/postfix:0.1.0 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 25 + name: smtp + protocol: TCP + - containerPort: 587 + name: submission + protocol: TCP + readinessProbe: + tcpSocket: + port: smtp + initialDelaySeconds: 5 + periodSeconds: 10 + livenessProbe: + exec: + command: ["postfix", "status"] + initialDelaySeconds: 30 + periodSeconds: 30 + # postfix master runs as root and drops to the postfix user per service. + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + add: + - CHOWN + - DAC_OVERRIDE + - FOWNER + - SETUID + - SETGID + - NET_BIND_SERVICE + resources: + requests: + cpu: 50m + memory: 128Mi + limits: + cpu: 500m + memory: 512Mi + volumeMounts: + - name: spool + mountPath: /var/spool/postfix + - name: tls + mountPath: /etc/postfix/tls + readOnly: true + - name: config + mountPath: /etc/postfix/main.cf + subPath: main.cf + readOnly: true + - name: config + mountPath: /etc/postfix/master.cf + subPath: master.cf + readOnly: true + - name: config + mountPath: /etc/postfix/relay_domains + subPath: relay_domains + readOnly: true + - name: config + mountPath: /etc/postfix/transport + subPath: transport + readOnly: true + - name: config + mountPath: /etc/postfix/gateways.cidr + subPath: gateways.cidr + readOnly: true + - name: config + mountPath: /etc/postfix/milter.cidr + subPath: milter.cidr + readOnly: true + volumes: + - name: config + configMap: + name: smarthost-config + - name: tls + secret: + secretName: wildcard-unkin-net-tls + volumeClaimTemplates: + - metadata: + name: spool + spec: + accessModes: [ReadWriteOnce] + storageClassName: cephrbd-fast-delete + resources: + requests: + storage: 5Gi diff --git a/apps/base/mail/smarthost/gateways.cidr b/apps/base/mail/smarthost/gateways.cidr new file mode 100644 index 0000000..de93a9b --- /dev/null +++ b/apps/base/mail/smarthost/gateways.cidr @@ -0,0 +1,2 @@ +# DMZ gateways (mx1/mx2) over WireGuard. +10.10.12.0/24 OK diff --git a/apps/base/mail/smarthost/main.cf b/apps/base/mail/smarthost/main.cf new file mode 100644 index 0000000..9945223 --- /dev/null +++ b/apps/base/mail/smarthost/main.cf @@ -0,0 +1,42 @@ +compatibility_level = 3.5 +myhostname = smarthost.unkin.net +myorigin = unkin.net +mydestination = +alias_maps = +local_recipient_maps = +inet_interfaces = all +inet_protocols = ipv4 +maillog_file = /dev/stdout +message_size_limit = 52428800 + +# Pod CIDR (Stalwart) plus the lab networks from bind-internal acl-main/acl-common/acl-nomad-jobs. +pod_networks = 10.42.0.0/16 +mynetworks = $pod_networks + 10.10.12.200/32 198.18.1.10/32 + 198.18.2.160/27 198.18.2.192/27 198.18.21.160/27 198.18.21.192/27 + 198.18.13.0/24 198.18.14.0/24 198.18.15.0/24 198.18.16.0/24 198.18.17.0/24 198.18.18.0/24 + 198.18.19.0/24 198.18.20.0/24 198.18.21.0/24 198.18.22.0/24 198.18.23.0/24 + 198.18.25.0/24 198.18.26.0/24 198.18.27.0/24 198.18.28.0/24 198.18.29.0/24 + 198.18.64.0/24 198.18.65.0/24 198.18.66.0/24 198.18.67.0/24 198.18.68.0/24 198.18.69.0/24 + +relay_domains = texthash:/etc/postfix/relay_domains +transport_maps = texthash:/etc/postfix/transport +relayhost = [mx1.wg.unkin.net]:25 +smtp_fallback_relay = [mx2.wg.unkin.net]:25 +smtpd_relay_restrictions = permit_mynetworks, reject_unauth_destination +unverified_recipient_reject_code = 550 + +milter_default_action = tempfail +rspamd_milter = inet:rspamd.mail.svc:11332 + +# Referenced from master.cf per listener. +inbound_client_restrictions = permit_mynetworks, check_client_access cidr:/etc/postfix/gateways.cidr, reject +inbound_recipient_restrictions = permit_mynetworks, reject_unverified_recipient +submission_client_restrictions = permit_mynetworks, reject + +smtpd_tls_security_level = may +smtpd_tls_cert_file = /etc/postfix/tls/tls.crt +smtpd_tls_key_file = /etc/postfix/tls/tls.key +smtpd_tls_received_header = yes +smtp_tls_security_level = may +lmtp_tls_security_level = none diff --git a/apps/base/mail/smarthost/master.cf b/apps/base/mail/smarthost/master.cf new file mode 100644 index 0000000..ed18250 --- /dev/null +++ b/apps/base/mail/smarthost/master.cf @@ -0,0 +1,38 @@ +# inbound-relay: gateways (no milter) and Stalwart's outbound relay (pod CIDR, rspamd milter). +25 inet n - n - - smtpd + -o syslog_name=postfix/inbound-relay + -o mynetworks=$pod_networks + -o smtpd_client_restrictions=$inbound_client_restrictions + -o smtpd_recipient_restrictions=$inbound_recipient_restrictions + -o smtpd_milters= + -o smtpd_milter_maps=cidr:/etc/postfix/milter.cidr +# submission-internal: lab networks and pods, always through rspamd. +587 inet n - n - - smtpd + -o syslog_name=postfix/submission-internal + -o smtpd_client_restrictions=$submission_client_restrictions + -o smtpd_milters=$rspamd_milter +pickup unix n - n 60 1 pickup +cleanup unix n - n - 0 cleanup +qmgr unix n - n 300 1 qmgr +tlsmgr unix - - n 1000? 1 tlsmgr +rewrite unix - - n - - trivial-rewrite +bounce unix - - n - 0 bounce +defer unix - - n - 0 bounce +trace unix - - n - 0 bounce +verify unix - - n - 1 verify +flush unix n - n 1000? 0 flush +proxymap unix - - n - - proxymap +proxywrite unix - - n - 1 proxymap +smtp unix - - n - - smtp +relay unix - - n - - smtp + -o syslog_name=postfix/$service_name +showq unix n - n - - showq +error unix - - n - - error +retry unix - - n - - error +discard unix - - n - - discard +local unix - n n - - local +virtual unix - n n - - virtual +lmtp unix - - n - - lmtp +anvil unix - - n - 1 anvil +scache unix - - n - 1 scache +postlog unix-dgram n - n - 1 postlogd diff --git a/apps/base/mail/smarthost/milter.cidr b/apps/base/mail/smarthost/milter.cidr new file mode 100644 index 0000000..3f75361 --- /dev/null +++ b/apps/base/mail/smarthost/milter.cidr @@ -0,0 +1 @@ +10.42.0.0/16 inet:rspamd.mail.svc:11332 diff --git a/apps/base/mail/smarthost/relay_domains b/apps/base/mail/smarthost/relay_domains new file mode 100644 index 0000000..59818b2 --- /dev/null +++ b/apps/base/mail/smarthost/relay_domains @@ -0,0 +1 @@ +unkin.net OK diff --git a/apps/base/mail/smarthost/transport b/apps/base/mail/smarthost/transport new file mode 100644 index 0000000..828306f --- /dev/null +++ b/apps/base/mail/smarthost/transport @@ -0,0 +1 @@ +unkin.net lmtp:[stalwart.mail.svc.cluster.local]:24