From 0aa6e3ef6ad2659193893a94edbf89b79026213f Mon Sep 17 00:00:00 2001 From: WhatTheMike Date: Sat, 27 Sep 2025 17:46:35 +0000 Subject: [PATCH] Added role for authenticated postfix relay server --- roles/postfix_relay/files/aliases | 2 + roles/postfix_relay/files/master.cf | 127 +++++++++++++++++++ roles/postfix_relay/files/saslauthd-postfix | 62 +++++++++ roles/postfix_relay/files/smtpd.conf | 2 + roles/postfix_relay/handlers/main.yaml | 26 ++++ roles/postfix_relay/tasks/main.yaml | 95 ++++++++++++++ roles/postfix_relay/templates/mailname.j2 | 1 + roles/postfix_relay/templates/main.cf.j2 | 82 ++++++++++++ roles/postfix_relay/templates/sasl_passwd.j2 | 1 + roles/postfix_relay/vars/example.txt | 19 +++ 10 files changed, 417 insertions(+) create mode 100644 roles/postfix_relay/files/aliases create mode 100644 roles/postfix_relay/files/master.cf create mode 100644 roles/postfix_relay/files/saslauthd-postfix create mode 100644 roles/postfix_relay/files/smtpd.conf create mode 100644 roles/postfix_relay/handlers/main.yaml create mode 100644 roles/postfix_relay/tasks/main.yaml create mode 100644 roles/postfix_relay/templates/mailname.j2 create mode 100644 roles/postfix_relay/templates/main.cf.j2 create mode 100644 roles/postfix_relay/templates/sasl_passwd.j2 create mode 100644 roles/postfix_relay/vars/example.txt diff --git a/roles/postfix_relay/files/aliases b/roles/postfix_relay/files/aliases new file mode 100644 index 0000000..425273c --- /dev/null +++ b/roles/postfix_relay/files/aliases @@ -0,0 +1,2 @@ +# See man 5 aliases for format +postmaster: root \ No newline at end of file diff --git a/roles/postfix_relay/files/master.cf b/roles/postfix_relay/files/master.cf new file mode 100644 index 0000000..199d3e3 --- /dev/null +++ b/roles/postfix_relay/files/master.cf @@ -0,0 +1,127 @@ +# +# Postfix master process configuration file. For details on the format +# of the file, see the master(5) manual page (command: "man 5 master" or +# on-line: http://www.postfix.org/master.5.html). +# +# Do not forget to execute "postfix reload" after editing this file. +# +# ========================================================================== +# service type private unpriv chroot wakeup maxproc command + args +# (yes) (yes) (no) (never) (100) +# ========================================================================== +smtp inet n - y - - smtpd +#smtp inet n - y - 1 postscreen +#smtpd pass - - y - - smtpd +#dnsblog unix - - y - 0 dnsblog +#tlsproxy unix - - y - 0 tlsproxy +submission inet n - y - - smtpd +# -o syslog_name=postfix/submission +# -o smtpd_tls_security_level=encrypt +# -o smtpd_sasl_auth_enable=yes +# -o smtpd_tls_auth_only=yes +# -o smtpd_reject_unlisted_recipient=no +# -o smtpd_client_restrictions=$mua_client_restrictions +# -o smtpd_helo_restrictions=$mua_helo_restrictions +# -o smtpd_sender_restrictions=$mua_sender_restrictions +# -o smtpd_recipient_restrictions= +# -o smtpd_relay_restrictions=permit_sasl_authenticated,reject +# -o milter_macro_daemon_name=ORIGINATING +#smtps inet n - y - - smtpd +# -o syslog_name=postfix/smtps +# -o smtpd_tls_wrappermode=yes +# -o smtpd_sasl_auth_enable=yes +# -o smtpd_reject_unlisted_recipient=no +# -o smtpd_client_restrictions=$mua_client_restrictions +# -o smtpd_helo_restrictions=$mua_helo_restrictions +# -o smtpd_sender_restrictions=$mua_sender_restrictions +# -o smtpd_recipient_restrictions= +# -o smtpd_relay_restrictions=permit_sasl_authenticated,reject +# -o milter_macro_daemon_name=ORIGINATING +#628 inet n - y - - qmqpd +pickup unix n - y 60 1 pickup +cleanup unix n - y - 0 cleanup +qmgr unix n - n 300 1 qmgr +#qmgr unix n - n 300 1 oqmgr +tlsmgr unix - - y 1000? 1 tlsmgr +rewrite unix - - y - - trivial-rewrite +bounce unix - - y - 0 bounce +defer unix - - y - 0 bounce +trace unix - - y - 0 bounce +verify unix - - y - 1 verify +flush unix n - y 1000? 0 flush +proxymap unix - - n - - proxymap +proxywrite unix - - n - 1 proxymap +smtp unix - - y - - smtp +relay unix - - y - - smtp + -o syslog_name=postfix/$service_name +# -o smtp_helo_timeout=5 -o smtp_connect_timeout=5 +showq unix n - y - - showq +error unix - - y - - error +retry unix - - y - - error +discard unix - - y - - discard +local unix - n n - - local +virtual unix - n n - - virtual +lmtp unix - - y - - lmtp +anvil unix - - y - 1 anvil +scache unix - - y - 1 scache +postlog unix-dgram n - n - 1 postlogd +# +# ==================================================================== +# Interfaces to non-Postfix software. Be sure to examine the manual +# pages of the non-Postfix software to find out what options it wants. +# +# Many of the following services use the Postfix pipe(8) delivery +# agent. See the pipe(8) man page for information about ${recipient} +# and other message envelope options. +# ==================================================================== +# +# maildrop. See the Postfix MAILDROP_README file for details. +# Also specify in main.cf: maildrop_destination_recipient_limit=1 +# +maildrop unix - n n - - pipe + flags=DRhu user=vmail argv=/usr/bin/maildrop -d ${recipient} +# +# ==================================================================== +# +# Recent Cyrus versions can use the existing "lmtp" master.cf entry. +# +# Specify in cyrus.conf: +# lmtp cmd="lmtpd -a" listen="localhost:lmtp" proto=tcp4 +# +# Specify in main.cf one or more of the following: +# mailbox_transport = lmtp:inet:localhost +# virtual_transport = lmtp:inet:localhost +# +# ==================================================================== +# +# Cyrus 2.1.5 (Amos Gouaux) +# Also specify in main.cf: cyrus_destination_recipient_limit=1 +# +#cyrus unix - n n - - pipe +# user=cyrus argv=/cyrus/bin/deliver -e -r ${sender} -m ${extension} ${user} +# +# ==================================================================== +# Old example of delivery via Cyrus. +# +#old-cyrus unix - n n - - pipe +# flags=R user=cyrus argv=/cyrus/bin/deliver -e -m ${extension} ${user} +# +# ==================================================================== +# +# See the Postfix UUCP_README file for configuration details. +# +uucp unix - n n - - pipe + flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient) +# +# Other external delivery methods. +# +ifmail unix - n n - - pipe + flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient) +bsmtp unix - n n - - pipe + flags=Fq. user=bsmtp argv=/usr/lib/bsmtp/bsmtp -t$nexthop -f$sender $recipient +scalemail-backend unix - n n - 2 pipe + flags=R user=scalemail argv=/usr/lib/scalemail/bin/scalemail-store ${nexthop} ${user} ${extension} +mailman unix - n n - - pipe + flags=FR user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py + ${nexthop} ${user} + diff --git a/roles/postfix_relay/files/saslauthd-postfix b/roles/postfix_relay/files/saslauthd-postfix new file mode 100644 index 0000000..010ef0a --- /dev/null +++ b/roles/postfix_relay/files/saslauthd-postfix @@ -0,0 +1,62 @@ +# +# Settings for saslauthd daemon +# Please read /usr/share/doc/sasl2-bin/README.Debian for details. +# + +# Should saslauthd run automatically on startup? (default: no) +START=yes + +# Description of this saslauthd instance. Recommended. +# (suggestion: SASL Authentication Daemon) +DESC="SASL Authentication Daemon" + +# Short name of this saslauthd instance. Strongly recommended. +# (suggestion: saslauthd) +NAME="saslauthd-postf" + +# Which authentication mechanisms should saslauthd use? (default: pam) +# +# Available options in this Debian package: +# getpwent -- use the getpwent() library function +# kerberos5 -- use Kerberos 5 +# pam -- use PAM +# rimap -- use a remote IMAP server +# shadow -- use the local shadow password file +# sasldb -- use the local sasldb database file +# ldap -- use LDAP (configuration is in /etc/saslauthd.conf) +# +# Only one option may be used at a time. See the saslauthd man page +# for more information. +# +# Example: MECHANISMS="pam" +MECHANISMS="sasldb" + +# Additional options for this mechanism. (default: none) +# See the saslauthd man page for information about mech-specific options. +MECH_OPTIONS="" + +# How many saslauthd processes should we run? (default: 5) +# A value of 0 will fork a new process for each connection. +THREADS=5 + +# Other options (default: -c -m /var/run/saslauthd) +# Note: You MUST specify the -m option or saslauthd won't run! +# +# WARNING: DO NOT SPECIFY THE -d OPTION. +# The -d option will cause saslauthd to run in the foreground instead of as +# a daemon. This will PREVENT YOUR SYSTEM FROM BOOTING PROPERLY. If you wish +# to run saslauthd in debug mode, please run it by hand to be safe. +# +# See /usr/share/doc/sasl2-bin/README.Debian for Debian-specific information. +# See the saslauthd man page and the output of 'saslauthd -h' for general +# information about these options. +# +# Example for chroot Postfix users: "-c -m /var/spool/postfix/var/run/saslauthd" +# Example for non-chroot Postfix users: "-c -m /var/run/saslauthd" +# +# To know if your Postfix is running chroot, check /etc/postfix/master.cf. +# If it has the line "smtp inet n - y - - smtpd" or "smtp inet n - - - - smtpd" +# then your Postfix is running in a chroot. +# If it has the line "smtp inet n - n - - smtpd" then your Postfix is NOT +# running in a chroot. +OPTIONS="-c -m /var/spool/postfix/var/run/saslauthd" # postfix/smtp in chroot() diff --git a/roles/postfix_relay/files/smtpd.conf b/roles/postfix_relay/files/smtpd.conf new file mode 100644 index 0000000..769a751 --- /dev/null +++ b/roles/postfix_relay/files/smtpd.conf @@ -0,0 +1,2 @@ +pwcheck_method: saslauthd +mech_list: LOGIN PLAIN diff --git a/roles/postfix_relay/handlers/main.yaml b/roles/postfix_relay/handlers/main.yaml new file mode 100644 index 0000000..70f6d07 --- /dev/null +++ b/roles/postfix_relay/handlers/main.yaml @@ -0,0 +1,26 @@ +--- +- name: remap_sasl_passwd + ansible.builtin.command: + cmd: /usr/sbin/postmap /etc/postfix/sasl_passwd + become: true + become_method: sudo + +- name: remap_aliases + ansible.builtin.command: + cmd: /usr/sbin/postmap /etc/aliases + become: true + become_method: sudo + +- name: restart_postfix + ansible.builtin.service: + name: postfix + state: restarted + become: true + become_method: sudo + +- name: restart_fail2ban + ansible.builtin.service: + name: fail2ban + state: restarted + become: true + become_method: sudo \ No newline at end of file diff --git a/roles/postfix_relay/tasks/main.yaml b/roles/postfix_relay/tasks/main.yaml new file mode 100644 index 0000000..ffa646f --- /dev/null +++ b/roles/postfix_relay/tasks/main.yaml @@ -0,0 +1,95 @@ +--- +- name: Ensure required packages are up to date + ansible.builtin.apt: + name: + - postfix + - libsasl2-modules + - sasl2-bin + state: latest + become: true + become_method: sudo + +- name: Ensure configuration files are up to date + ansible.builtin.copy: + src: "{{ item.file }}" + dest: "{{ item.path }}/{{ item.file }}" + with_items: + - file: master.cf + path: /etc/postfix + - file: smtpd.conf + path: /etc/postfix/sasl + - file: saslauthd-postfix + path: /etc/default + - file: aliases + path: /etc + notify: restart_postfix + become: true + become_method: sudo + +- name: Ensure configuration templates are up to date + ansible.builtin.template: + src: "{{ item.file }}.j2" + dest: "{{ item.path }}/{{ item.file }}" + with_items: + - file: main.cf + path: /etc/postfix + - file: sasl_passwd + path: /etc/postfix + - file: mailname + path: /etc + notify: + - remap_aliases + - remap_sasl_passwd + - restart_postfix + become: true + become_method: sudo + +- name: Ensure postfix user is in sasl group + ansible.builtin.user: + name: postfix + groups: sasl + append: true + create_home: false + become: true + become_method: sudo + +- name: Check if fail2ban is installed + ansible.builtin.stat: + path: /etc/fail2ban/jail.d/defaults-debian.conf + register: fail2ban_check + +- name: Add postfix & sasl2 to fail2ban if fail2ban installed + ansible.builtin.blockinfile: + path: /etc/fail2ban/jail.d/defaults-debian.conf + block: | + [postfix] + enabled = true + + [postfix-sasl] + enabled = true + when: fail2ban_check.stat.exists is defined and fail2ban_check.stat.exists + notify: restart_fail2ban + become: true + become_method: sudo + +# - You can list users on the server by running: sudo sasldblistusers2 +# - saslpasswd2 won't create duplicate users so we can safely run this +# as many times as we want with the same user list. +- name: Ensure local smtp users are configured (will always change) + ansible.builtin.shell: + executable: /bin/bash + cmd: ' echo {{ item.password }} | saslpasswd2 -p -c -u {{ local_smtp_relay_hostname }} -a smtpauth {{ item.username }}' + with_items: "{{ smtp_users }}" + become: true + become_method: sudo + +- name: Ensure services are started & enabled + ansible.builtin.service: + name: "{{ item }}" + state: started + enabled: true + with_items: + - postfix + - saslauthd + become: true + become_method: sudo \ No newline at end of file diff --git a/roles/postfix_relay/templates/mailname.j2 b/roles/postfix_relay/templates/mailname.j2 new file mode 100644 index 0000000..6ef40bc --- /dev/null +++ b/roles/postfix_relay/templates/mailname.j2 @@ -0,0 +1 @@ +{{ local_smtp_relay_hostname }} \ No newline at end of file diff --git a/roles/postfix_relay/templates/main.cf.j2 b/roles/postfix_relay/templates/main.cf.j2 new file mode 100644 index 0000000..cbe2bbb --- /dev/null +++ b/roles/postfix_relay/templates/main.cf.j2 @@ -0,0 +1,82 @@ +# See /usr/share/postfix/main.cf.dist for a commented, more complete version + + +# Debian specific: Specifying a file name will cause the first +# line of that file to be used as the name. The Debian default +# is /etc/mailname. +#myorigin = /etc/mailname + +# smtpd_banner = $myhostname ESMTP $mail_name (Ubuntu) +smtpd_banner = {{ local_smtpd_banner }} +biff = no + +# appending .domain is the MUA's job. +append_dot_mydomain = no + +# Uncomment the next line to generate "delayed mail" warnings +#delay_warning_time = 4h + +readme_directory = no + +# See http://www.postfix.org/COMPATIBILITY_README.html -- default to 2 on +# fresh installs. +compatibility_level = 2 + +# TLS parameters +smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem +smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key +smtpd_use_tls=yes +smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache +smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache + +# See /usr/share/doc/postfix/TLS_README.gz in the postfix-doc package for +# information on enabling SSL in the smtp client. + +smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination +myhostname = {{ local_smtp_relay_hostname }} +alias_maps = hash:/etc/aliases +alias_database = hash:/etc/aliases +myorigin = /etc/mailname +mydestination = $myhostname, localhost +relayhost = [{{ upstream_smtp_relay_server }}]:{{ upstream_smtp_relay_port }} +mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 +mailbox_size_limit = 0 +recipient_delimiter = + +# inet_interfaces = loopback-only +inet_interfaces = all +inet_protocols = all + +# http://www.postfix.org/SASL_README.html + +smtpd_sasl_type = cyrus +smtpd_sasl_auth_enable = yes +smtpd_sasl_path = smtpd + +# https://wiki.debian.org/PostfixAndSASL +# smtpd authenticates users into aperture postfix + +cyrus_sasl_config_path = /etc/postfix/sasl +smtpd_sasl_local_domain = $myhostname +smtpd_sasl_auth_enable = yes +broken_sasl_auth_clients = yes +smtpd_sasl_security_options = noanonymous +smtpd_recipient_restrictions = permit_sasl_authenticated, permit_mynetworks, reject_unauth_destination + +# https://www.linode.com/docs/email/postfix/postfix-smtp-debian7/ + +# smtp authenticates aperture postfix oubound/upstream to smtp2go + +# enable SASL authentication +smtp_sasl_auth_enable = yes +# disallow methods that allow anonymous authentication. +smtp_sasl_security_options = noanonymous +# where to find sasl_passwd +smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd +# Enable STARTTLS encryption +smtp_use_tls = yes +# where to find CA certificates +smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt + + +# Add users by using saslpasswd2 +# https://www.planetcobalt.net/patrick.koetter/smtpauth/sasldb_configuration.html diff --git a/roles/postfix_relay/templates/sasl_passwd.j2 b/roles/postfix_relay/templates/sasl_passwd.j2 new file mode 100644 index 0000000..b8466b9 --- /dev/null +++ b/roles/postfix_relay/templates/sasl_passwd.j2 @@ -0,0 +1 @@ +[{{ upstream_smtp_relay_server }}]:{{ upstream_smtp_relay_port }} {{ upstream_smtp_relay_username }}:{{ upstream_smtp_relay_password}} diff --git a/roles/postfix_relay/vars/example.txt b/roles/postfix_relay/vars/example.txt new file mode 100644 index 0000000..38abc77 --- /dev/null +++ b/roles/postfix_relay/vars/example.txt @@ -0,0 +1,19 @@ +My variables for this role are configured in the host_vars +folder for my smtp relay host specifically. If you wish to +use this role yourself, you will need to define the +following variables: + +--- +upstream_smtp_relay_server: your.relay.example.com +upstream_smtp_relay_port: '587' +upstream_smtp_relay_username: upstream-relay-username +upstream_smtp_relay_password: upstream-relay-password + +local_smtp_relay_hostname: your.local.relay.hostname +local_smtpd_banner: your-smtp-banner-can-be-anything + +smtp_users: + - username: user1 + password: password1 + - username: user2 + password: password2 \ No newline at end of file