Initial commit

Signed-off-by: René Jochum <rene@jochum.dev>
master
René Jochum 4 years ago
commit 4bfdcee246

@ -0,0 +1,17 @@
FROM registry.jochum.dev/library/debian:buster-slim
LABEL maintainer "René Jochum <rene@jochum.dev>"
RUN echo "postfix postfix/mailname string mail.example.com" | debconf-set-selections && \
echo "postfix postfix/main_mailer_type string 'No configuration'" | debconf-set-selections && \
apt-get update --allow-releaseinfo-change && \
apt-get install -qy -o 'DPkg::Options::=--force-confold' -o 'DPkg::Options::=--force-confdef' postfix postfix-pgsql postfix-mysql postfix-pcre python3-minimal python3-jinja2
COPY conf /conf
COPY start.py /start.py
EXPOSE 25/tcp 465/tcp 587/tcp
VOLUME ["/data", "/overrides", "/cert"]
CMD /start.py

@ -0,0 +1,28 @@
# Postfix
## Create Readonly PostgreSQL user
```sql
USE postfixadmin;
GRANT CONNECT ON DATABASE postfixadmin TO postfix;
GRANT USAGE ON SCHEMA public TO postfix;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO postfix;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO postfix;
```
## Environment variables
- MYDOMAIN
- SUBNET
- RELAYNETS
- SQL_TYPE - either `pgsql` or `mysql`
- SQL_USER - readonly Database user
- SQL_PASSWORD
- SQL_HOST
- SQL_DATABASE
- MESSAGE_SIZE_LIMIT - defaults to 52428800
- REJECT_UNLISTED_RECIPIENT - "yes" or "no"
## Links
- [HOWTO this is based on](https://kuther.net/2011/11/15/soho-mailserver-with-postfix-postgresql-dovecot-spamassassin-roundcube/)

@ -0,0 +1,57 @@
# basic domain settings
myhostname = {{ HOSTNAME }}
mydomain = {{ MYDOMAIN }}
mydestination = $myhostname, localhost
# mynetworks = 192.168.1.0/24, 127.0.0.0/8
mynetworks = 127.0.0.1/32 [::1]/128 {{ SUBNET }} {{ RELAYNETS }}
myorigin = $mydomain
relay_domains = proxy:{{ SQL_TYPE }}:/etc/postfix/sql/relay_domains.cf
# In kube we don't often don't have a stable outgoing IP Address, use a relayhost for this.
relayhost = {{ RELAYHOST }}
# enable auth via Dovecot
smtpd_sasl_auth_enable = yes
smtpd_sasl_path = inet:{{ DOVECOT_HOST }}:2525
smtpd_sasl_type = dovecot
message_size_limit = 52428800
# virtual mail setup for Postgresql and Dovecot transport
virtual_mailbox_limit = 0
virtual_mailbox_domains = proxy:{{ SQL_TYPE }}:/etc/postfix/sql/virtual_domains_maps.cf
virtual_mailbox_maps = proxy:{{ SQL_TYPE }}:/etc/postfix/sql/virtual_mailbox_maps.cf
virtual_alias_maps = proxy:{{ SQL_TYPE }}:/etc/postfix/sql/virtual_alias_maps.cf
virtual_uid_maps = static:8
virtual_gid_maps = static:8
virtual_minimum_uid = 8
virtual_transport=lmtp:inet:{{ DOVECOT_HOST }}:2525
dovecot_destination_recipient_limit = 1
# also local accounts are handled via virtual users, configure aliases for those in PostfixAdmin
local_transport = virtual
local_recipient_maps = $virtual_mailbox_maps
# TLS server (receiving)
smtpd_tls_auth_only = yes
smtpd_tls_security_level = encrypt
smtpd_tls_key_file = /cert/tls.key
smtpd_tls_cert_file = /cert/tls.crt
smtpd_tls_CAfile = /cert/ca.crt
smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3
# TLS client (sending)
smtp_tls_security_level = encrypt
# security and basic spam protection
smtpd_recipient_restrictions =
permit_sasl_authenticated
permit_mynetworks
reject_unauth_destination
smtpd_relay_restrictions =
permit_mynetworks
permit_sasl_authenticated
defer_unauth_destination
smtpd_client_restrictions =
permit_sasl_authenticated

@ -0,0 +1,40 @@
# service type private unpriv chroot wakeup maxproc command + args
# (yes) (yes) (yes) (never) (100)
# Exposed SMTP service
smtp inet n - n - - smtpd
# Expose 587
submission inet n - n - - smtpd
-o smtpd_enforce_tls=yes
-o smtpd_sasl_auth_enable=yes
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
# Expose 465
smtps inet n - y - - smtpd
-o smtpd_tls_wrappermode=yes
outclean unix n - n - 0 cleanup
-o header_checks=pcre:/etc/postfix/outclean_header_filter.cf
# Internal postfix services
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
smtp unix - - n - - smtp
relay unix - - n - - smtp
error unix - - n - - error
retry unix - - n - - error
discard unix - - n - - discard
lmtp unix - - n - - lmtp
anvil unix - - n - 1 anvil
scache unix - - n - 1 scache
postlog unix-dgram n - n - 1 postlogd

@ -0,0 +1,5 @@
user = {{ SQL_USER }}
password = {{ SQL_PASSWORD }}
hosts = {{ SQL_HOST }}
dbname = {{ SQL_DATABASE }}
query = SELECT domain FROM domain WHERE domain='%s' and backupmx = true

@ -0,0 +1,5 @@
user = {{ SQL_USER }}
password = {{ SQL_PASSWORD }}
hosts = {{ SQL_HOST }}
dbname = {{ SQL_DATABASE }}
query = SELECT goto FROM alias WHERE address='%s' AND active = true

@ -0,0 +1,5 @@
user = {{ SQL_USER }}
password = {{ SQL_PASSWORD }}
hosts = {{ SQL_HOST }}
dbname = {{ SQL_DATABASE }}
query = SELECT domain FROM domain WHERE domain='%s' and backupmx = false and active = true

@ -0,0 +1,5 @@
user = {{ SQL_USER }}
password = {{ SQL_PASSWORD }}
hosts = {{ SQL_HOST }}
dbname = {{ SQL_DATABASE }}
query = SELECT quota FROM mailbox WHERE username='%s'

@ -0,0 +1,5 @@
user = {{ SQL_USER }}
password = {{ SQL_PASSWORD }}
hosts = {{ SQL_HOST }}
dbname = {{ SQL_DATABASE }}
query = SELECT maildir FROM mailbox WHERE username='%s' AND active = true

@ -0,0 +1,58 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import os
import shutil
import sys
import glob
import jinja2
def jinja_render_file(in_path, data, out_path):
render_environment = jinja2.Environment(loader=jinja2.FileSystemLoader(os.path.dirname(in_path)))
output = render_environment.get_template(os.path.basename(in_path)).render(**data)
with open(out_path, 'w', encoding='utf-8') as rf:
rf.write(output)
def is_valid_postconf_line(line):
return not line.startswith("#") \
and not line == ''
if "MESSAGE_SIZE_LIMIT" not in os.environ:
os.environ["MESSAGE_SIZE_LIMIT"] = 52428800
if "DOVECOT_HOST" not in os.environ:
os.environ['DOVECOT_HOST'] = 'dovecot'
for postfix_file in glob.glob("/conf/*.cf"):
destination = os.path.join("/etc/postfix", os.path.basename(postfix_file))
shutil.copyfile(postfix_file, destination)
os.chmod(destination, 600)
for postfix_file in glob.glob("/conf/*.cf.jinja"):
out_path = os.path.join("/etc/postfix", os.path.basename(postfix_file))
out_path = out_path[0:-6] # Remove .jinja from the output path
jinja_render_file(postfix_file, os.environ, out_path)
os.chmod(out_path, 600)
if os.path.exists("/overrides/postfix.cf"):
for line in open("/overrides/postfix.cf").read().strip().split("\n"):
if is_valid_postconf_line(line):
os.system('postconf -e "{}"'.format(line))
if os.path.exists("/overrides/postfix.master"):
for line in open("/overrides/postfix.master").read().strip().split("\n"):
if is_valid_postconf_line(line):
os.system('postconf -Me "{}"'.format(line))
os.system("/bin/mkdir -p /data/vmail")
os.system("/bin/chmod u=rwX,g=rX,o=rX /data")
os.system("/bin/chown -R mail: /data/vmail")
os.system("/bin/chmod -R u=rwX,g=rX,o= /data/vmail")
os.system("/usr/libexec/postfix/post-install meta_directory=/etc/postfix create-missing")
# Before starting postfix, we need to check permissions on /queue
# in the event that postfix,postdrop id have changed
os.system("postfix set-permissions")
os.system("postfix start-fg")
Loading…
Cancel
Save