Browse Source

Postfix: Split TLSPol companion app into separate container (#6688)

* postfix: split postfix-tlspol service into new container

* postfix-tls-pol: added debug mode

* pf-tlspol: removed obsoleted standalone conf from Dockerfiles

* pf-tlspol: use git instead of wget
DerLinkman 1 week ago
parent
commit
1cb38bacdb

+ 49 - 0
data/Dockerfiles/postfix-tlspol/Dockerfile

@@ -0,0 +1,49 @@
+FROM golang:1.25-bookworm AS builder
+WORKDIR /src
+
+ENV CGO_ENABLED=0 \
+    GO111MODULE=on \
+    VERSION=1.8.14
+
+RUN git clone --branch v${VERSION} https://github.com/Zuplu/postfix-tlspol && \
+    cd /src/postfix-tlspol && \
+    scripts/build.sh build-only
+
+
+FROM debian:bookworm-slim
+LABEL maintainer="The Infrastructure Company GmbH <info@servercow.de>"
+
+ARG DEBIAN_FRONTEND=noninteractive
+ENV LC_ALL=C
+
+RUN apt-get update && apt-get install -y --no-install-recommends \
+	ca-certificates \
+	dirmngr \
+  	dnsutils \
+	iputils-ping \
+	sudo \
+	supervisor \
+	redis-tools \
+	syslog-ng \
+	syslog-ng-core \
+	syslog-ng-mod-redis \
+  	tzdata \
+	&& rm -rf /var/lib/apt/lists/* \
+	&& touch /etc/default/locale
+
+COPY supervisord.conf /etc/supervisor/supervisord.conf
+COPY syslog-ng.conf /etc/syslog-ng/syslog-ng.conf
+COPY syslog-ng-redis_slave.conf /etc/syslog-ng/syslog-ng-redis_slave.conf
+COPY postfix-tlspol.sh /opt/postfix-tlspol.sh
+COPY stop-supervisor.sh /usr/local/sbin/stop-supervisor.sh
+COPY docker-entrypoint.sh /docker-entrypoint.sh
+COPY --from=builder /src/postfix-tlspol/build/postfix-tlspol /usr/local/bin/postfix-tlspol
+
+RUN chmod +x /opt/postfix-tlspol.sh \
+  /usr/local/sbin/stop-supervisor.sh \
+  /docker-entrypoint.sh
+RUN rm -rf /tmp/* /var/tmp/*
+
+ENTRYPOINT ["/docker-entrypoint.sh"]
+
+CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf"]

+ 7 - 0
data/Dockerfiles/postfix-tlspol/docker-entrypoint.sh

@@ -0,0 +1,7 @@
+#!/bin/bash
+
+if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
+  cp /etc/syslog-ng/syslog-ng-redis_slave.conf /etc/syslog-ng/syslog-ng.conf
+fi
+
+exec "$@"

+ 52 - 0
data/Dockerfiles/postfix-tlspol/postfix-tlspol.sh

@@ -0,0 +1,52 @@
+#!/bin/bash
+
+LOGLVL=info
+
+if [ ${DEV_MODE} != "n" ]; then
+  echo -e "\e[31mEnabling debug mode\e[0m"
+  set -x
+  LOGLVL=debug
+fi
+
+[[ ! -d /etc/postfix-tlspol ]] && mkdir -p /etc/postfix-tlspol
+[[ ! -d /var/lib/postfix-tlspol ]] && mkdir -p /var/lib/postfix-tlspol
+
+until dig +short mailcow.email > /dev/null; do
+  echo "Waiting for DNS..."
+  sleep 1
+done
+
+# Do not attempt to write to slave
+if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
+  export REDIS_CMDLINE="redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT} -a ${REDISPASS} --no-auth-warning"
+else
+  export REDIS_CMDLINE="redis-cli -h redis -p 6379 -a ${REDISPASS} --no-auth-warning"
+fi
+
+until [[ $(${REDIS_CMDLINE} PING) == "PONG" ]]; do
+  echo "Waiting for Redis..."
+  sleep 2
+done
+
+echo "Waiting for Postfix..."
+until ping postfix -c1 > /dev/null; do
+  sleep 1
+done
+echo "Postfix OK"
+
+cat <<EOF > /etc/postfix-tlspol/config.yaml
+server:
+  address: 0.0.0.0:8642
+
+  log-level: ${LOGLVL}
+
+  prefetch: true
+
+  cache-file: /var/lib/postfix-tlspol/cache.db
+
+dns:
+  # must support DNSSEC
+  address: 127.0.0.11:53
+EOF
+
+/usr/local/bin/postfix-tlspol -config /etc/postfix-tlspol/config.yaml

+ 8 - 0
data/Dockerfiles/postfix-tlspol/stop-supervisor.sh

@@ -0,0 +1,8 @@
+#!/bin/bash
+
+printf "READY\n";
+
+while read line; do
+  echo "Processing Event: $line" >&2;
+  kill -3 $(cat "/var/run/supervisord.pid")
+done < /dev/stdin

+ 25 - 0
data/Dockerfiles/postfix-tlspol/supervisord.conf

@@ -0,0 +1,25 @@
+[supervisord]
+pidfile=/var/run/supervisord.pid
+nodaemon=true
+user=root
+
+[program:syslog-ng]
+command=/usr/sbin/syslog-ng --foreground  --no-caps
+stdout_logfile=/dev/stdout
+stdout_logfile_maxbytes=0
+stderr_logfile=/dev/stderr
+stderr_logfile_maxbytes=0
+autostart=true
+
+[program:postfix-tlspol]
+startsecs=10
+autorestart=true
+command=/opt/postfix-tlspol.sh
+stdout_logfile=/dev/stdout
+stdout_logfile_maxbytes=0
+stderr_logfile=/dev/stderr
+stderr_logfile_maxbytes=0
+
+[eventlistener:processes]
+command=/usr/local/sbin/stop-supervisor.sh
+events=PROCESS_STATE_STOPPED, PROCESS_STATE_EXITED, PROCESS_STATE_FATAL

+ 45 - 0
data/Dockerfiles/postfix-tlspol/syslog-ng-redis_slave.conf

@@ -0,0 +1,45 @@
+@version: 3.38
+@include "scl.conf"
+options {
+  chain_hostnames(off);
+  flush_lines(0);
+  use_dns(no);
+  dns_cache(no);
+  use_fqdn(no);
+  owner("root"); group("adm"); perm(0640);
+  stats_freq(0);
+  bad_hostname("^gconfd$");
+};
+source s_src {
+  unix-stream("/dev/log");
+  internal();
+};
+destination d_stdout { pipe("/dev/stdout"); };
+destination d_redis_ui_log {
+  redis(
+    host("`REDIS_SLAVEOF_IP`")
+    persist-name("redis1")
+    port(`REDIS_SLAVEOF_PORT`)
+    auth("`REDISPASS`")
+    command("LPUSH" "POSTFIX_MAILLOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
+  );
+};
+filter f_mail { facility(mail); };
+# start
+# overriding warnings are still displayed when the entrypoint runs its initial check
+# warnings logged by postfix-mailcow to syslog are hidden to reduce repeating msgs
+# Some other warnings are ignored
+filter f_ignore {
+  not match("overriding earlier entry" value("MESSAGE"));
+  not match("TLS SNI from checks.mailcow.email" value("MESSAGE"));
+  not match("no SASL support" value("MESSAGE"));
+  not facility (local0, local1, local2, local3, local4, local5, local6, local7);
+};
+# end
+log {
+  source(s_src);
+  filter(f_ignore);
+  destination(d_stdout);
+  filter(f_mail);
+  destination(d_redis_ui_log);
+};

+ 45 - 0
data/Dockerfiles/postfix-tlspol/syslog-ng.conf

@@ -0,0 +1,45 @@
+@version: 3.38
+@include "scl.conf"
+options {
+  chain_hostnames(off);
+  flush_lines(0);
+  use_dns(no);
+  dns_cache(no);
+  use_fqdn(no);
+  owner("root"); group("adm"); perm(0640);
+  stats_freq(0);
+  bad_hostname("^gconfd$");
+};
+source s_src {
+  unix-stream("/dev/log");
+  internal();
+};
+destination d_stdout { pipe("/dev/stdout"); };
+destination d_redis_ui_log {
+  redis(
+    host("redis-mailcow")
+    persist-name("redis1")
+    port(6379)
+    auth("`REDISPASS`")
+    command("LPUSH" "POSTFIX_MAILLOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
+  );
+};
+filter f_mail { facility(mail); };
+# start
+# overriding warnings are still displayed when the entrypoint runs its initial check
+# warnings logged by postfix-mailcow to syslog are hidden to reduce repeating msgs
+# Some other warnings are ignored
+filter f_ignore {
+  not match("overriding earlier entry" value("MESSAGE"));
+  not match("TLS SNI from checks.mailcow.email" value("MESSAGE"));
+  not match("no SASL support" value("MESSAGE"));
+  not facility (local0, local1, local2, local3, local4, local5, local6, local7);
+};
+# end
+log {
+  source(s_src);
+  filter(f_ignore);
+  destination(d_stdout);
+  filter(f_mail);
+  destination(d_redis_ui_log);
+};

+ 0 - 11
data/Dockerfiles/postfix/Dockerfile

@@ -1,13 +1,3 @@
-FROM golang:1.25-bookworm AS builder
-WORKDIR /src
-
-ENV CGO_ENABLED=0 \
-    GO111MODULE=on
-
-RUN git clone https://github.com/Zuplu/postfix-tlspol.git && \
-	cd postfix-tlspol && \
-	scripts/build.sh build-only
-
 FROM debian:bookworm-slim
 
 LABEL maintainer="The Infrastructure Company GmbH <info@servercow.de>"
@@ -58,7 +48,6 @@ COPY rspamd-pipe-spam /usr/local/bin/rspamd-pipe-spam
 COPY whitelist_forwardinghosts.sh /usr/local/bin/whitelist_forwardinghosts.sh
 COPY stop-supervisor.sh /usr/local/sbin/stop-supervisor.sh
 COPY docker-entrypoint.sh /docker-entrypoint.sh
-COPY --from=builder /src/postfix-tlspol/build/postfix-tlspol /usr/local/bin/postfix-tlspol
 
 RUN chmod +x /opt/postfix.sh \
   /usr/local/bin/rspamd-pipe-ham \

+ 0 - 23
data/Dockerfiles/postfix/postfix.sh

@@ -3,9 +3,6 @@
 trap "postfix stop" EXIT
 
 [[ ! -d /opt/postfix/conf/sql/ ]] && mkdir -p /opt/postfix/conf/sql/
-[[ ! -d /opt/postfix/conf/postfix-tlspol ]] && mkdir -p /opt/postfix/conf/postfix-tlspol
-[[ ! -d /etc/postfix-tlspol ]] && mkdir -p /etc/postfix-tlspol
-[[ ! -d /var/lib/postfix-tlspol ]] && mkdir -p /var/lib/postfix-tlspol
 
 # Wait for MySQL to warm-up
 while ! mariadb-admin status --ssl=false --socket=/var/run/mysqld/mysqld.sock -u${DBUSER} -p${DBPASS} --silent; do
@@ -506,26 +503,6 @@ if [[ ! -f /opt/postfix/conf/custom_postscreen_whitelist.cidr ]]; then
 EOF
 fi
 
-cat <<EOF > /opt/postfix/conf/postfix-tlspol/config.yaml
-server:
-  address: 127.0.0.1:8642
-
-  log-level: info
-
-  prefetch: true
-
-  cache-file: /var/lib/postfix-tlspol/cache.db
-
-dns:
-  # must support DNSSEC
-  address: 127.0.0.11:53
-EOF
-
-# Fixing local command execution of postfix-tlspol with symlink to config
-if [ ! -L /etc/postfix-tlspol/config.yaml ]; then
-  ln -s /opt/postfix/conf/postfix-tlspol/config.yaml /etc/postfix-tlspol/config.yaml
-fi
-
 # Fix Postfix permissions
 chown -R root:postfix /opt/postfix/conf/sql/ /opt/postfix/conf/custom_transport.pcre
 chmod 640 /opt/postfix/conf/sql/*.cf /opt/postfix/conf/custom_transport.pcre

+ 0 - 9
data/Dockerfiles/postfix/supervisord.conf

@@ -11,15 +11,6 @@ stderr_logfile=/dev/stderr
 stderr_logfile_maxbytes=0
 autostart=true
 
-[program:postfix-tlspol]
-startsecs=10
-autorestart=true
-command=/usr/local/bin/postfix-tlspol -config /opt/postfix/conf/postfix-tlspol/config.yaml
-stdout_logfile=/dev/stdout
-stdout_logfile_maxbytes=0
-stderr_logfile=/dev/stderr
-stderr_logfile_maxbytes=0
-
 [program:postfix]
 command=/opt/postfix.sh
 stdout_logfile=/dev/stdout

+ 1 - 1
data/conf/postfix/main.cf

@@ -152,7 +152,7 @@ smtp_sasl_auth_enable = yes
 smtp_sasl_password_maps = proxy:mysql:/opt/postfix/conf/sql/mysql_sasl_passwd_maps_sender_dependent.cf
 smtp_sasl_security_options =
 smtp_sasl_mechanism_filter = plain, login
-smtp_tls_policy_maps = proxy:mysql:/opt/postfix/conf/sql/mysql_tls_policy_override_maps.cf socketmap:inet:127.0.0.1:8642:QUERY
+smtp_tls_policy_maps = proxy:mysql:/opt/postfix/conf/sql/mysql_tls_policy_override_maps.cf socketmap:inet:postfix-tlspol:8642:QUERY
 smtp_header_checks = pcre:/opt/postfix/conf/anonymize_headers.pcre
 mail_name = Postcow
 # local_transport map catches local destinations and prevents routing local dests when the next map would route "*"

+ 25 - 0
docker-compose.yml

@@ -378,6 +378,30 @@ services:
           aliases:
             - postfix
 
+    postfix-tlspol-mailcow:
+      image: ghcr.io/mailcow/postfix-tlspol:1.0
+      depends_on:
+        unbound-mailcow:
+          condition: service_healthy
+        postfix-mailcow:
+          condition: service_started
+      volumes:
+        - postfix-tlspol-vol-1:/var/lib/postfix-tlspol
+      environment:
+        - LOG_LINES=${LOG_LINES:-9999}
+        - TZ=${TZ}
+        - REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-}
+        - REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-}
+        - REDISPASS=${REDISPASS}
+        - DEV_MODE=${DEV_MODE:-n}
+      restart: always
+      dns:
+        - ${IPV4_NETWORK:-172.22.1}.254
+      networks:
+        mailcow-network:
+          aliases:
+            - postfix-tlspol
+
     memcached-mailcow:
       image: memcached:alpine
       restart: always
@@ -649,6 +673,7 @@ volumes:
   redis-vol-1:
   rspamd-vol-1:
   postfix-vol-1:
+  postfix-tlspol-vol-1:
   crypt-vol-1:
   sogo-web-vol-1:
   sogo-userdata-backup-vol-1: