Closed denysvitali closed 3 years ago
Hi Thank you for this patch!
I think implementing this seems totally reasonable, and much appreciate your patch for it.
I have a few suggestions/comments on the approach itself, I will leave some comments on the patch, but I'm also happy to just make the changes myself if you don't have time for it, totally up to you.
Thanks again!
I'm all ears for your suggestions, in the meantime this solution is being tested with my personal mail server (based on chasquid + dovecot), https://github.com/denysvitali/docker-chasquid
I ended up writing an experimental commit since as I was reviewing it, it wasn't clear how my suggestions were going to look, and didn't want to send you on a false path. Sorry for not doing a normal review of this, as I'd usually do, it got a bit quirky in the end.
What do you think about commit 4ad4c3d4bcdb, on the (temporary) branch haproxy
?
It's a similar approach in principle to yours, but has a few key differences:
I also added a few tests since I don't have a haproxy setup at hand, but of course nothing replaces real world testing :)
Please let me know what you think!
Thanks!
Your version is definitely better and I really like it more over mine, plus it has unit tests and also an integration test with haproxy. I guess I can't say anything more: impressive.
Thank you!
Thanks a lot for your kind words!
As usual, I've merged the patch in the next
branch, it will sit there for a little in case there are some last minute adjustments, and then I'll move it to master
. It will be included in the next release, of course :)
Thanks again for your patch and help implementing this!
I'm actually testing it already on my mail server, and so far it seems to work perfectly (:
Thank you very much for this project and your improvement over my patch! ✌️
Sorry for posting on a resolved PR, I just wanted to note that with a Kubernetes LoadBalencer service you can use service.spec.externalTrafficPolicy: Local
(docs) to preserve the packet's source IP.
I found out about this feature this week-end for a different use-case, but thought I'd mention it here in case someone find this thread.
Thanks @ThinkChaos , but for me it doesn't work since I'm using MetalLB and I'm already forwarding the traffic to another service (Traefik) 👍
Thanks to both!
If you send me a bit more details (can be privately), I can try expand the documentation with your examples. It might take a bit of back and forth since I'm not familiar with Kubernetes LB/Metal LB though :)
My use case was for a totally separate project, I'm not using chasquid with k8s so I'm afraid I can't help put together a complete example. I just remembered this PR and thought it might be a step in the right direction for someone finding this later on, or an alternate solution for @denysvitali.
chasquid.dep.yml
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: chasquid
name: chasquid
namespace: mail
spec:
replicas: 2
selector:
matchLabels:
app: chasquid
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: chasquid
spec:
initContainers:
- name: volume-permissions
image: busybox
command:
- sh
- -c
- chown -R 1001:1001 /srv/mail/mailboxes
volumeMounts:
- mountPath: /srv/mail/mailboxes
name: mail-data
subPath: mailboxes
- name: clamav-permissions
image: busybox
command:
- sh
- -c
- chown -R 100:101 /var/lib/clamav
volumeMounts:
- name: mail-data
mountPath: /var/lib/clamav
subPath: clamav
containers:
- image: dvitali/chasquid:0.0.0-17
name: chasquid
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: 1
memory: 2Gi
env:
- name: CSQ_HOSTNAME
value: mail.ded2.denv.it
- name: CSQ_DOVECOT_AUTH
value: "true"
- name: CSQ_MAIL_DELIVERY_AGENT_BIN
value: /usr/libexec/dovecot/dovecot-lda
- name: CSQ_MAIL_DELIVERY_AGENT_ARGS
value: "-f,%from%,-d,%to%"
- name: CSQ_MONITORING_ADDRESS
value: ":1099"
- name: CSQ_HAPROXY_INCOMING
value: "true"
- name: DKIM_SELECTOR
value: dkim
- name: DOVECOT_DB_HOST
value: mysql.mail.svc.cluster.local
- name: DOVECOT_DB_NAME
value: mail
- name: DOVECOT_DB_USER
valueFrom:
secretKeyRef:
name: mysql-dovecot-ro
key: username
- name: DOVECOT_DB_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-dovecot-ro
key: password
- name: RSPAMD_CONNECTION
value: rspamd.mail.svc.cluster.local:11334
- name: RSPAMD_PASSWORD
value: plaintext secret that I need to remove
readinessProbe:
tcpSocket:
port: 25
periodSeconds: 10
failureThreshold: 5
startupProbe:
tcpSocket:
port: 25
periodSeconds: 30
failureThreshold: 20
volumeMounts:
- name: mail-data
mountPath: /etc/chasquid/certs
subPath: chasquid-certs
- name: mail-data
mountPath: /etc/chasquid/domains
subPath: chasquid-domains
- name: mail-data
mountPath: /var/lib/clamav
subPath: clamav
- name: ssl-cert
mountPath: /etc/chasquid/certs/mail.ded2.denv.it
- name: dovecot-conf
mountPath: /etc/dovecot/conf.d/dovecot-debug.conf
subPath: dovecot-debug.conf
- name: dovecot-conf
mountPath: /etc/dovecot/conf.d/dovecot-inbox.conf
subPath: dovecot-inbox.conf
- name: mail-data
mountPath: /srv/mail/mailboxes
subPath: mailboxes
volumes:
- name: ssl-cert
secret:
secretName: mail-cert
items:
- key: tls.crt
path: ./fullchain.pem
- key: tls.key
path: ./privkey.pem
- name: dovecot-conf
configMap:
name: dovecot-additional-config
- name: mail-data
persistentVolumeClaim:
claimName: mail-data
status: {}
mail.svc.yml
apiVersion: v1
kind: Service
metadata:
name: mail-svc
namespace: mail
spec:
spec:
ports:
- name: smtp
port: 25
nodePort: 30025
- name: smtps
port: 587
nodePort: 30587
selector:
app: chasquid
type: NodePort
externalTrafficPolicy: Cluster
Add support for HAProxy's Proxy Protocol (opt-in).
By default Chasquid gets the remote IP address from the TCP connection to perform the SPF detection. Unfortunately when the SMTP server is behind a load balancer (e.g: Kubernetes' Load Balancer or a simple HA Proxy LB), the SPF check will fail because the Load Balancer IP address (e.g: 10.42.0.1 for Kubernetes kube-proxy) doesn't match the one specified in the SPF domain record.
For this reason with this PR HAProxy's Proxy Protocol support can be enabled using the
proxy_protocol
config element.This will therefore start to read on every new connection the PROXY line:
and will then replace the sourceIp with the one provided by HAProxy, so that the SPF check can succeed (if the remote IP address matches the SPF record).