From ce35b0be2ef540f30c80e271c802ad4792ad6e33 Mon Sep 17 00:00:00 2001
From: Sheogorath <sheogorath@shivering-isles.com>
Date: Wed, 29 Jun 2022 23:50:05 +0200
Subject: [PATCH] feat(postfix): Add ability to utilise proxy-protocol

This patch should enable the postfix setup in MoK to utilise the
proxy-protocol and therefore gather required IP information from
connecting clients.

It's implemented based on some documentation regard the topic and is
useful for reverse-proxy setups e.g. behind haproxy.

References:
https://www.haproxy.com/blog/efficient-smtp-relay-infrastructure-with-postfix-and-load-balancers/
---
 charts/mok/Chart.yaml                      |  2 +-
 charts/mok/README.md                       |  4 ++-
 charts/mok/templates/networkpolicy.yaml    |  8 ++++++
 charts/mok/templates/postfix.yaml          |  9 ++++++
 charts/mok/tests/networkpolicies_test.yaml | 33 ++++++++++++++++++++++
 charts/mok/tests/postfix_test.yaml         | 22 +++++++++++++++
 charts/mok/values.yaml                     |  8 +++++-
 images/postfix/.release                    |  2 +-
 images/postfix/Containerfile               |  9 +++---
 images/postfix/config/main.cf              |  2 ++
 images/postfix/config/master.cf            |  2 +-
 11 files changed, 92 insertions(+), 9 deletions(-)

diff --git a/charts/mok/Chart.yaml b/charts/mok/Chart.yaml
index 87bf6ee34..4d6a7bb5d 100644
--- a/charts/mok/Chart.yaml
+++ b/charts/mok/Chart.yaml
@@ -3,7 +3,7 @@ name: mok
 description: |
   Mail on Kubernetes (MoK) is a project to deploy a functional mailserver that runs without a database server on Kubernetes, taking advantage of configmaps and secret.
 type: application
-version: 0.2.0
+version: 0.3.0
 sources:
   - https://de.postfix.org/ftpmirror/index.html
   - https://github.com/dovecot/core
diff --git a/charts/mok/README.md b/charts/mok/README.md
index 859672563..9e168e817 100644
--- a/charts/mok/README.md
+++ b/charts/mok/README.md
@@ -1,6 +1,6 @@
 # mok
 
-![Version: 0.2.0](https://img.shields.io/badge/Version-0.2.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square)
+![Version: 0.3.0](https://img.shields.io/badge/Version-0.3.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square)
 
 Mail on Kubernetes (MoK) is a project to deploy a functional mailserver that runs without a database server on Kubernetes, taking advantage of configmaps and secret.
 
@@ -60,6 +60,8 @@ Mail on Kubernetes (MoK) is a project to deploy a functional mailserver that run
 | postfix.nodeSelector | object | `{}` |  |
 | postfix.podAnnotations | object | `{}` |  |
 | postfix.podSecurityContext | object | `{}` |  |
+| postfix.postscreen.cidr | string | `"127.0.0.1/32"` | CIDR that is allowed to use Proxy protocol on port 10025 |
+| postfix.postscreen.enabled | bool | `false` | Enable proxy protocol support |
 | postfix.replicaCount | int | `1` | Number of postfix pods. |
 | postfix.resources.limits.cpu | string | `"500m"` |  |
 | postfix.resources.limits.memory | string | `"512Mi"` |  |
diff --git a/charts/mok/templates/networkpolicy.yaml b/charts/mok/templates/networkpolicy.yaml
index 3c8b3a314..84806d622 100644
--- a/charts/mok/templates/networkpolicy.yaml
+++ b/charts/mok/templates/networkpolicy.yaml
@@ -60,6 +60,14 @@ spec:
       protocol: TCP
     - port: 587
       protocol: TCP
+  {{- if .Values.postfix.postscreen.enabled }}
+  - from:
+    - ipBlock:
+        cidr: {{ .Values.postfix.postscreen.cidr }}
+    ports:
+    - port: 10025
+      protocol: TCP
+  {{- end }}
   podSelector:
     matchLabels:
       {{- include "mok.selectorLabels" . | nindent 6 }}
diff --git a/charts/mok/templates/postfix.yaml b/charts/mok/templates/postfix.yaml
index c22e9ddf1..d9607a981 100644
--- a/charts/mok/templates/postfix.yaml
+++ b/charts/mok/templates/postfix.yaml
@@ -18,6 +18,11 @@ spec:
   - port: 587
     name: submission
     protocol: TCP
+  {{- if .Values.postfix.postscreen.enabled }}
+  - port: 10025
+    name: postscreen
+    protocol: TCP
+  {{- end }}
   selector:
     {{- include "mok.selectorLabels" . | nindent 4 }}
     app.kubernetes.io/component: postfix
@@ -119,6 +124,10 @@ spec:
               name: submissions
             - containerPort: 587
               name: submission
+            {{- if .Values.postfix.postscreen.enabled }}
+            - containerPort: 10025
+              name: postscreen
+            {{- end }}
           resources:
             {{- toYaml .Values.postfix.resources | nindent 12 }}
           securityContext:
diff --git a/charts/mok/tests/networkpolicies_test.yaml b/charts/mok/tests/networkpolicies_test.yaml
index e086b306d..2f2aa564b 100644
--- a/charts/mok/tests/networkpolicies_test.yaml
+++ b/charts/mok/tests/networkpolicies_test.yaml
@@ -218,6 +218,39 @@ tests:
             app.kubernetes.io/name: mok
         documentIndex: 1
         template: networkpolicy.yaml
+  - it: allows postfix's postscreen from reverse-proxy
+    release:
+      name: "test-suite"
+    set:
+      postfix:
+        postscreen:
+          enabled: true
+          cidr: 127.0.123.123/32
+    asserts:
+      - equal:
+          path: spec.ingress[1].from[0].ipBlock.cidr
+          value: 127.0.123.123/32
+        documentIndex: 1
+        template: networkpolicy.yaml
+      - isEmpty:
+          path: spec.ingress[1].from[0].ipBlock.except
+        documentIndex: 1
+        template: networkpolicy.yaml
+      - contains:
+          path: spec.ingress[1].ports
+          content:
+            port: 10025
+            protocol: TCP
+        documentIndex: 1
+        template: networkpolicy.yaml
+      - equal:
+          path: spec.podSelector.matchLabels
+          value:
+            app.kubernetes.io/component: postfix
+            app.kubernetes.io/instance: test-suite
+            app.kubernetes.io/name: mok
+        documentIndex: 1
+        template: networkpolicy.yaml
   - it: matches snapshot
     asserts:
       - matchSnapshot: {}
diff --git a/charts/mok/tests/postfix_test.yaml b/charts/mok/tests/postfix_test.yaml
index 2246fefa8..b85c8d39d 100644
--- a/charts/mok/tests/postfix_test.yaml
+++ b/charts/mok/tests/postfix_test.yaml
@@ -48,6 +48,28 @@ tests:
             name: smtp
         documentIndex: 1
         template: postfix.yaml
+  - it: has postscreen port if enabled
+    set:
+      postfix:
+        postscreen:
+          enabled: true
+          cidr: 127.0.123.123/32
+    asserts:
+      - contains:
+          path: spec.ports
+          content:
+            port: 10025
+            name: postscreen
+            protocol: TCP
+        documentIndex: 0
+        template: postfix.yaml
+      - contains:
+          path: spec.template.spec.containers[0].ports
+          content:
+            containerPort: 10025
+            name: postscreen
+        documentIndex: 1
+        template: postfix.yaml
   - it: has config hash for auto-reload
     set:
       dovecot:
diff --git a/charts/mok/values.yaml b/charts/mok/values.yaml
index b0cc7a10c..c32172f75 100644
--- a/charts/mok/values.yaml
+++ b/charts/mok/values.yaml
@@ -44,7 +44,7 @@ postfix:
     repository: quay.io/shivering-isles/postfix
     pullPolicy: IfNotPresent
     # -- Overrides the image tag whose default is "latest"
-    tag: "0.1.1"
+    tag: "0.2.0"
 
   imagePullSecrets: []
 
@@ -52,6 +52,12 @@ postfix:
 
   podSecurityContext: {}
 
+  postscreen:
+    # -- Enable proxy protocol support
+    enabled: false
+    # -- CIDR that is allowed to use Proxy protocol on port 10025
+    cidr: 127.0.0.1/32
+
   securityContext:
     # -- prevent any process in the container to regain capabilities once dropped
     allowPrivilegeEscalation: false
diff --git a/images/postfix/.release b/images/postfix/.release
index 30d504277..9990762bd 100644
--- a/images/postfix/.release
+++ b/images/postfix/.release
@@ -1 +1 @@
-release=0.1.1
+release=0.2.0
diff --git a/images/postfix/Containerfile b/images/postfix/Containerfile
index 9f7b2db3c..03ac284e4 100644
--- a/images/postfix/Containerfile
+++ b/images/postfix/Containerfile
@@ -17,9 +17,10 @@ COPY docker/rsyslog.conf /etc/
 COPY docker/start.sh /usr/local/libexec/start.sh
 RUN chmod +x /usr/local/libexec/start.sh
 
-#   25: SMTP (Server2Server)
-#  465: SUBMISSIONS (SSL)
-#  587: SMTP (StartTLS)
-EXPOSE 25 465 587
+#    25: SMTP (Server2Server)
+#   465: SUBMISSIONS (SSL)
+#   587: SMTP (StartTLS)
+# 10025: Postscreen for HAProxy
+EXPOSE 25 465 587 10025
 
 ENTRYPOINT [ "sh" , "/usr/local/libexec/start.sh" ]
diff --git a/images/postfix/config/main.cf b/images/postfix/config/main.cf
index ecfb7b7ac..f493d0d74 100644
--- a/images/postfix/config/main.cf
+++ b/images/postfix/config/main.cf
@@ -181,3 +181,5 @@ maximal_queue_lifetime = 1d
 bounce_queue_lifetime = 1d
 unverified_recipient_reject_code = 577
 compatibility_level = 2
+
+postscreen_upstream_proxy_protocol = haproxy
diff --git a/images/postfix/config/master.cf b/images/postfix/config/master.cf
index 8c2e8ab8a..082af700a 100644
--- a/images/postfix/config/master.cf
+++ b/images/postfix/config/master.cf
@@ -2,7 +2,7 @@
 # service type  private unpriv  chroot  wakeup  maxproc command + args
 #               (yes)   (yes)   (yes)   (never) (100)
 # ==========================================================================
-#smtp      inet  n       -       -       -       1       postscreen
+10025      inet  n       -       -       -       1       postscreen
 #smtpd     pass  -       -       -       -       -       smtpd
 #dnsblog   unix  -       -       -       -       0       dnsblog
 #tlsproxy  unix  -       -       -       -       0       tlsproxy
-- 
GitLab