Skip to content

Commit 36a68db

Browse files
authored
Merge branch 'docker-mailserver:master' into master
2 parents c1ea707 + 7e1f3b5 commit 36a68db

File tree

8 files changed

+189
-146
lines changed

8 files changed

+189
-146
lines changed

.github/workflows/on-push-lint-charts.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ on:
1313

1414
env:
1515
KUBE_SCORE_VERSION: 1.17.0
16-
HELM_VERSION: v3.13.2
16+
HELM_VERSION: v3.19.0
1717

1818
concurrency:
1919
group: ${{ github.ref }}
@@ -29,7 +29,7 @@ jobs:
2929
fetch-depth: 0
3030

3131
- name: Set up Helm
32-
uses: azure/setup-helm@v3
32+
uses: azure/setup-helm@v4.3.0
3333
with:
3434
version: ${{ env.HELM_VERSION }}
3535

@@ -64,7 +64,7 @@ jobs:
6464
strategy:
6565
matrix:
6666
# Choose from https://hub.docker.com/r/kindest/node/tags
67-
KubeVersion: [ 1.30.10, 1.31.6, 1.32.2]
67+
KubeVersion: [ 1.32.8, 1.33.4, 1.34.0]
6868

6969
steps:
7070
- name: Checkout

TESTING.md

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,6 @@ To run locally:
3434

3535
*ct* can also test a chart by deploying it to a temporary namespace in a Kubernetes cluster, and waiting for indications that the deployment has been successful. This is a good way to test how the deployment behaves "for real".
3636

37-
38-
39-
4037
ct lint --config=.ci/ct-config.yaml
4138

4239
Create a KinD cluster, by running `kind create cluster`:

charts/docker-mailserver/Chart.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
apiVersion: v2
2-
appVersion: "15.0.2"
2+
appVersion: "15.1.0"
33
description: A fullstack but simple mailserver (smtp, imap, antispam, antivirus, ssl...) using Docker.
44
name: docker-mailserver
5-
version: 4.2.1
5+
version: 5.1.0
66
sources:
77
- https://github.com/docker-mailserver/docker-mailserver-helm
88
maintainers:

charts/docker-mailserver/README.md

Lines changed: 82 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -37,17 +37,68 @@ Kubernetes cluster. docker-mailserver is a production-ready, fullstack mail serv
3737
- A [Kubernetes](https://kubernetes.io/releases/) cluster with persistent storage and access to email [ports](https://docker-mailserver.github.io/docker-mailserver/latest/config/security/understanding-the-ports/#overview-of-email-ports)
3838
- A custom domain name (for example, example.com)
3939
- Correctly configured [DNS](https://docker-mailserver.github.io/docker-mailserver/latest/usage/#minimal-dns-setup)
40+
- [Cert Manager](https://cert-manager.io/docs/) or a similar tool to create and renew TLS certificates
4041

4142
## Getting Started
4243

4344
Setting up docker-mailserver requires generating a number of configuration [files](https://docker-mailserver.github.io/docker-mailserver/latest/config/advanced/optional-config/). To make this easier, docker-mailserver includes a `setup` command that can generate these files.
4445

45-
To get started, first add the helm repo and install docker-mailserver:
46+
To get started, first configure the firewall on your cluster to allow connections to ports 25 (imap), 465 (submissions), 587 (submission) and 993 (imaps) from any IP address.
4647

48+
If you have a LoadBalancer service routing traffic to your ingress controller, configure it to pass through the mail ports.
49+
50+
Then, configure your ingress controller (or Gateway) to [pass through the email ports](https://docker-mailserver.github.io/docker-mailserver/latest/config/advanced/kubernetes/#using-the-proxy-protocol).
51+
52+
Next, manually create a TLS Certificate, setting `metadata.name` and `spec.secretName` to the same value. Also set the fully-qualified domain name for your mail server in `spec.dnsNames` and `spec.issuerRef.name` to the name of an Issuer or ClusterIssuer, and `spec.issuerRef.kind` to `Issuer` or `ClusterIssuer`.
53+
```yaml
54+
apiVersion: cert-manager.io/v1
55+
kind: Certificate
56+
57+
metadata:
58+
name: mail-tls-certificate-rsa
59+
60+
spec:
61+
secretName: mail-tls-certificate-rsa
62+
isCA: false
63+
privateKey:
64+
algorithm: RSA
65+
encoding: PKCS1
66+
size: 2048
67+
dnsNames: [mail.example.com]
68+
issuerRef:
69+
name: letsencrypt-production
70+
kind: Issuer
71+
```
72+
```console
73+
kubectl apply -f certificate.yaml --namespace mail
74+
```
75+
76+
Then add the helm repo:
4777
```console
4878
helm repo add docker-mailserver https://docker-mailserver.github.io/docker-mailserver-helm
79+
```
80+
81+
Create a Helm values file. See the comments in [values.yaml](https://github.com/docker-mailserver/docker-mailserver-helm/blob/master/charts/docker-mailserver/values.yaml) to understand all the options, or create a minimal file like this (where `mail-tls-certificate-rsa` is the name of the certificate you previously created and `example.com` is the name of your domain):
82+
```yaml
83+
## Specify the name of a TLS secret that contains a certificate and private key for your email domain.
84+
## See https://kubernetes.io/docs/concepts/configuration/secret/#tls-secrets
85+
certificate: mail-tls-certificate-rsa
4986

50-
helm upgrade --install docker-mailserver docker-mailserver/docker-mailserver --namespace mail --create-namespace
87+
deployment:
88+
env:
89+
OVERRIDE_HOSTNAME: example.com # You must OVERRIDE this!
90+
```
91+
If you're using the HAProxy ingress controller, configure it to send PROXY Protocol to the docker-mailserver ports, by appending this to your values file:
92+
```yaml
93+
service:
94+
annotations:
95+
haproxy.org/send-proxy-protocol: proxy-v2
96+
```
97+
98+
Then install docker-mailserver using the values file:
99+
100+
```console
101+
helm upgrade --install docker-mailserver docker-mailserver/docker-mailserver --namespace mail --create-namespace -f values.yaml
51102
```
52103

53104
Next open a command prompt to the running container.
@@ -78,6 +129,8 @@ cat /tmp/docker-mailserver/postfix-accounts.cf
78129

79130
This path is [mapped](#persistence) to a Kubernetes Volume.
80131

132+
Optionally (but reccomended), create a [`NetworkPolicy`](https://kubernetes.io/docs/concepts/services-networking/network-policies/) that only allows appropriate pods to connect to the DMS pod.
133+
81134
## Configuration
82135

83136
Assuming you still have a command prompt [open](#getting-started) in the running container, run the setup command to see additional configuration options:
@@ -148,38 +201,50 @@ Once you acquire a certificate, you will need to store it in a TLS secret in the
148201
certificate: my-certificate-secret
149202
```
150203
151-
The chart will then automatically copy the certificate and private key to the `/tmp/dms/custom-certs` director in the container and correctly set the `SSL_CERT_PATH` and `SSL_KEY_PATH` environment variables.
204+
The chart will then automatically copy the certificate and private key to the `/tmp/dms/custom-certs` directory in the container and correctly set the `SSL_CERT_PATH` and `SSL_KEY_PATH` environment variables.
152205

153206
## Ports
154207

155-
If you are running on a bare-metal Kubernetes cluster, you will have to expose ports to the internet to receive and send emails. In addition, you need to make sure that `docker-mailserver`` receives the correct client IP address so that spam filtering works.
208+
If you are running on a bare-metal Kubernetes cluster, you will have to expose ports to the internet to receive and send emails. In addition, you need to make sure that `docker-mailserver` receives the correct client IP address so that spam filtering works.
156209

157-
This can get a bit complicated, as explained in the `docker-mailserver` [documentation](https://docker-mailserver.github.io/docker-mailserver/latest/config/advanced/kubernetes/#exposing-your-mail-server-to-the-outside-world).
210+
This can get a bit complicated, as explained in the `docker-mailserver` [documentation][dms-docs::k8s::network-config].
158211

159-
One approach to preserving the client IP address is to use the PROXY protocol, which is explained in the [documentation](https://docker-mailserver.github.io/docker-mailserver/latest/config/advanced/kubernetes/#proxy-port-to-service-via-proxy-protocol).
212+
One approach to preserving the client IP address is to [use the PROXY protocol][dms-docs::k8s::proxy-protocol].
160213

161-
The Helm chart supports the use of the proxy protocol via the `proxyProtocol` key. To enable it set the `proxyProtocol.enable` key to true. You will also want to set the `trustedNetworks` key.
214+
The Helm chart supports the use of the proxy protocol via the `proxyProtocol` key. By default `proxyProtocol.enable` is true, and `trustedNetworks` is set to the private IP network ranges, as are typically used inside a cluster.
162215

163216
```yaml
164217
proxyProtocol:
165218
enabled: true
166219
# List of sources (in CIDR format, space-separated) to permit PROXY protocol from
167-
trustedNetworks: "10.0.0.0/8 192.168.0.0/16 172.16.0.0/16"
220+
trustedNetworks: "10.0.0.0/8 192.168.0.0/16 172.16.0.0/12"
168221
```
169222

223+
Additionally, you will need to enable `proxyProtocol` for your loadbalancer.
224+
- If you are using a cloud service they will most likely have documentation on how to do this for their loadbalancer.
225+
- If you are using k3s then this is [currently impossible][k3s-klipperlb-pp] with the default components.
226+
227+
For security, you should narrow `trustedNetworks` to the actual range of IP addresses used by your ingress controller pods, and be certain to exclude any IP ranges gatewayed from IPv6 to v4 or vice versa.
228+
Also note that any compromised container in the cluster could use the PROXY protocol to evade some security measures, so set a `NetworkPolicy` that only allows the appropriate pods to connect to the DMS pod.
229+
170230
Enabling the PROXY protocol will create an additional port for each protocol (by adding 10,000 to the standard port value) that is configured to understand the PROXY protocol. Thus:
171231

172-
| Protocol | Port | PROXY Port |
173-
| ---------- | ------- | ----------- |
174-
| submissions | 465 | 10465 |
175-
| submission | 587 | 10587 |
176-
| imap | 143 | 10143 |
177-
| imaps | 993 | 10993 |
178-
| pop3 | 110 | 10110 |
179-
| pop3s | 995 | 10995 |
232+
| Protocol | Regular Port | PROXY Protocol Port |
233+
| ---------- |--------------|---------------------|
234+
| smtp | 25 | 12525 |
235+
| submissions | 465 | 10465 |
236+
| submission | 587 | 10587 |
237+
| imap | 143 | 10143 |
238+
| imaps | 993 | 10993 |
239+
| pop3 | 110 | 10110 |
240+
| pop3s | 995 | 10995 |
180241

181242
If you do not enable the PROXY protocol and your mail server is not exposed using a load-balancer service with an external traffic policy in "Local" mode, then all incoming mail traffic will look like it comes from a local Kubernetes cluster IP.
182243

244+
[dms-docs::k8s::network-config]: https://docker-mailserver.github.io/docker-mailserver/latest/config/advanced/kubernetes/#exposing-your-mail-server-to-the-outside-world
245+
[dms-docs::k8s::proxy-protocol]: https://docker-mailserver.github.io/docker-mailserver/latest/config/advanced/kubernetes/#proxy-port-to-service-via-proxy-protocol
246+
[k3s-klipperlb-pp]: https://github.com/docker-mailserver/docker-mailserver-helm/issues/176#issuecomment-3097915161
247+
183248
## Persistence
184249

185250
Docker-mailserver assumes there are [four](https://docker-mailserver.github.io/docker-mailserver/latest/config/advanced/optional-config/#volumes) mounted volumes:
@@ -231,7 +296,7 @@ DMS utilizes neither group-only chown as nfsnobody/root, fsGroup applied to all
231296
Quirks from the generic section also apply to NFS-backed PersistentVolumes.
232297

233298
## Upgrading to Version 5
234-
Version 5.0 upgrades docker-mailserver to version 15. This version of the chart *does* include backwards incompatible changes
299+
Version 5.0 of the chart *does* include backwards incompatible changes.
235300

236301
### PersistentVolumeClaims
237302

charts/docker-mailserver/templates/deployment.yaml

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,10 @@ spec:
128128

129129
resources:
130130
{{ toYaml .Values.deployment.resources | indent 12 }}
131+
{{- if and .Values.deployment.resizePolicy (semverCompare ">=1.33-0" .Capabilities.KubeVersion.Version) }}
132+
resizePolicy:
133+
{{ toYaml .Values.deployment.resizePolicy | indent 12 }}
134+
{{- end }}
131135
securityContext:
132136
{{- if eq .Values.deployment.env.ENABLE_FAIL2BAN 1.0 }}
133137
capabilities:
@@ -250,7 +254,7 @@ spec:
250254
- name: managesieve
251255
containerPort: 4190
252256
{{- if .Values.proxyProtocol.enabled }}
253-
- name: managesieve-proxy
257+
- name: msieve-proxy
254258
containerPort: 14190
255259
{{- end }}
256260
{{- end }}
@@ -268,10 +272,14 @@ spec:
268272

269273
ports:
270274
- containerPort: 9154
271-
name: http
275+
name: metrics
272276
protocol: TCP
273277
resources:
274-
{{ toYaml .Values.metrics.resources | indent 12 }}
278+
{{ toYaml .Values.metrics.resources | indent 12 }}
279+
{{- if and .Values.metrics.resizePolicy (semverCompare ">=1.33-0" .Capabilities.KubeVersion.Version) }}
280+
resizePolicy:
281+
{{ toYaml .Values.metrics.resizePolicy | indent 12 }}
282+
{{- end }}
275283
securityContext:
276284
{{ toYaml .Values.deployment.containerSecurityContext | indent 12 }}
277285

charts/docker-mailserver/templates/service.yaml

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -129,25 +129,22 @@ spec:
129129
targetPort: managesieve
130130
port: 4190
131131
{{- if .Values.proxyProtocol.enabled }}
132-
- name: managesieve-proxy
133-
targetPort: managesieve-proxy
132+
- name: msieve-proxy
133+
targetPort: msieve-proxy
134134
port: 14190
135135
{{- end }}
136136
{{- end }}
137137

138138
{{- if .Values.metrics.enabled }}
139139
- name: metrics
140-
port: 9154
141-
targetPort: 9154
140+
port: {{ .Values.monitoring.service.port }}
141+
targetPort: metrics
142142
{{- end }}
143143

144144
type: {{ default "ClusterIP" .Values.service.type }}
145-
{{- if eq .Values.service.type "LoadBalancer" }}
146-
{{- if .Values.service.loadBalancer.publicIp }}
147-
loadBalancerIP: {{ .Values.service.loadBalancer.publicIp }}
148-
{{- if .Values.service.loadBalancer.allowedIps }}
149-
loadBalancerSourceRanges:
150-
{{ .Values.service.loadBalancer.allowedIps | toYaml | indent 4 }}
151-
{{- end }}
152-
{{- end }}
145+
{{- if .Values.service.clusterIp }}
146+
clusterIP: {{ .Values.service.clusterIp }}
147+
{{- end }}
148+
{{- if .Values.service.trafficDistribution }}
149+
trafficDistribution: {{ .Values.service.trafficDistribution }}
153150
{{- end }}

charts/docker-mailserver/tests/__snapshot__/configmap_test.yaml.snap

Lines changed: 21 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ manifest should match snapshot:
22
1: |
33
apiVersion: v1
44
data:
5-
dovecot.cf: |2
5+
dovecot.cf: |
66
haproxy_trusted_networks = 10.0.0.0/8 192.168.0.0/16 172.16.0.0/12
77
service imap-login {
88
inet_listener imap {
@@ -14,13 +14,13 @@ manifest should match snapshot:
1414
ssl = yes
1515
}
1616

17-
inet_listener imap_proxy {
17+
inet_listener imap_proxyprotocol {
1818
haproxy = yes
1919
port = 10143
2020
ssl = no
2121
}
2222

23-
inet_listener imaps_proxy {
23+
inet_listener imaps_proxyprotocol {
2424
haproxy = yes
2525
port = 10993
2626
ssl = yes
@@ -51,47 +51,27 @@ manifest should match snapshot:
5151
data:
5252
user-patches.sh: |
5353
#!/bin/bash
54-
# Make sure to keep this file in sync with https://github.com/docker-mailserver/docker-mailserver/blob/master/target/postfix/master.cf!
55-
cat <<EOS >> /etc/postfix/master.cf
54+
# NOTE: Keep in sync with upstream advice:
55+
# https://github.com/docker-mailserver/docker-mailserver/blob/v15.0.0/docs/content/examples/tutorials/mailserver-behind-proxy.md?plain=1#L238-L268
5656

57-
# Submission with proxy
58-
10587 inet n - n - - smtpd
59-
-o syslog_name=postfix/submission
60-
-o smtpd_tls_security_level=encrypt
61-
-o smtpd_sasl_auth_enable=yes
62-
-o smtpd_sasl_type=dovecot
63-
-o smtpd_reject_unlisted_recipient=no
64-
-o smtpd_sasl_authenticated_header=yes
65-
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
66-
-o smtpd_relay_restrictions=permit_sasl_authenticated,reject
67-
-o smtpd_sender_restrictions=\$mua_sender_restrictions
68-
-o smtpd_discard_ehlo_keywords=
69-
-o milter_macro_daemon_name=ORIGINATING
70-
-o cleanup_service_name=sender-cleanup
71-
-o smtpd_upstream_proxy_protocol=haproxy
57+
# Duplicate the config for the submission(s) service ports (587 / 465) with adjustments for the PROXY ports (10587 / 10465) and `syslog_name` setting:
58+
postconf -Mf submission/inet | sed -e s/^submission/10587/ -e 's/submission/submission-proxyprotocol/' >> /etc/postfix/master.cf
59+
postconf -Mf submissions/inet | sed -e s/^submissions/10465/ -e 's/submissions/submissions-proxyprotocol/' >> /etc/postfix/master.cf
60+
# Enable PROXY Protocol support for these new service variants:
61+
postconf -P 10587/inet/smtpd_upstream_proxy_protocol=haproxy
62+
postconf -P 10465/inet/smtpd_upstream_proxy_protocol=haproxy
7263

73-
# Submissions with proxy
74-
10465 inet n - n - - smtpd
75-
-o syslog_name=postfix/submissions
76-
-o smtpd_tls_wrappermode=yes
77-
-o smtpd_sasl_auth_enable=yes
78-
-o smtpd_sasl_type=dovecot
79-
-o smtpd_reject_unlisted_recipient=no
80-
-o smtpd_sasl_authenticated_header=yes
81-
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
82-
-o smtpd_relay_restrictions=permit_sasl_authenticated,reject
83-
-o smtpd_sender_restrictions=\$mua_sender_restrictions
84-
-o smtpd_discard_ehlo_keywords=
85-
-o milter_macro_daemon_name=ORIGINATING
86-
-o cleanup_service_name=sender-cleanup
87-
-o smtpd_upstream_proxy_protocol=haproxy
64+
# Create a variant for port 25 too (NOTE: Port 10025 is already assigned in DMS to Amavis):
65+
postconf -Mf smtp/inet | sed -e s/^smtp/12525/ >> /etc/postfix/master.cf
66+
# Enable PROXY Protocol support:
67+
# - Uses a different setting as port 25 is handled via the postscreen service
68+
# - Optionally configure a `syslog_name` to distinguish in logs:
69+
postconf -P \
70+
12525/inet/postscreen_upstream_proxy_protocol=haproxy \
71+
12525/inet/syslog_name=postfix/smtpd-proxyprotocol
8872

89-
# Smtp with proxy
90-
12525 inet n - n - 1 postscreen
91-
-o syslog_name=postfix/smtp-proxy
92-
-o postscreen_upstream_proxy_protocol=haproxy
93-
-o postscreen_cache_map=btree:$data_directory/postscreen_10025_cache
94-
EOS
73+
# Add the `proxy:` prefix to share this cache between each running postscreen service via `proxymap`:
74+
postconf 'postscreen_cache_map = proxy:btree:$data_directory/postscreen_cache'
9575
kind: ConfigMap
9676
metadata:
9777
labels:

0 commit comments

Comments
 (0)