diff options
Diffstat (limited to 'roles/MSA')
-rw-r--r-- | roles/MSA/files/etc/postfix/anonymize_sender.pcre | 5 | ||||
-rw-r--r-- | roles/MSA/files/etc/postfix/check_sender_access | 1 | ||||
-rw-r--r-- | roles/MSA/files/etc/systemd/system/postfix-sender-login.service | 25 | ||||
-rw-r--r-- | roles/MSA/files/etc/systemd/system/postfix-sender-login.socket | 8 | ||||
-rwxr-xr-x | roles/MSA/files/usr/local/bin/postfix-sender-login.pl | 196 | ||||
-rw-r--r-- | roles/MSA/handlers/main.yml | 3 | ||||
-rw-r--r-- | roles/MSA/tasks/main.yml | 106 | ||||
-rw-r--r-- | roles/MSA/templates/etc/postfix-policyd-spf-python/policyd-spf.conf.j2 | 18 | ||||
-rw-r--r-- | roles/MSA/templates/etc/postfix/main.cf.j2 | 71 | ||||
l--------- | roles/MSA/templates/etc/postfix/master.cf.j2 | 1 | ||||
l--------- | roles/MSA/templates/etc/postfix/smtp_tls_policy.j2 | 1 |
11 files changed, 393 insertions, 42 deletions
diff --git a/roles/MSA/files/etc/postfix/anonymize_sender.pcre b/roles/MSA/files/etc/postfix/anonymize_sender.pcre index bd3d5f1..b91b981 100644 --- a/roles/MSA/files/etc/postfix/anonymize_sender.pcre +++ b/roles/MSA/files/etc/postfix/anonymize_sender.pcre @@ -1,7 +1,8 @@ -/^Received:\s+from\s+(?:\S+\s+\(\S+\s+\[[[:xdigit:].:]{3,39}\]\)) - (\s+\(using\s+(?:TLS|SSL)(?:v\S+)?\s+with\s+cipher\s+\S+\s+\(\S+\s+bits\)\)\s+).* +/^Received:\s+from\s+(?:\S+\s+\(\S+\s+\[(?:IPv6:)?[[:xdigit:].:]{3,39}\]\)) + (\s+\(using\s+(?:TLS|SSL)(?:v\S+)?\s+with\s+cipher\s+\S+\s+\(\S+\s+bits\) + (?:\s+key-exchange\s+\S+\s+(?:\([^)]+\)\s+)?server-signature\s+\S+\s+\(\d+\s+bits\)(?:\s+server-[[:alnum:]]+\s+\S+)*)?\)\s+).* (\bby\s+(?:\S+\.)?fripost\.org\s+\([^)]+\) \s+with\s+E?SMTPS?A\s+id\s+[[:xdigit:]]+;?\s.*)/x REPLACE Received: from [127.0.0.1] (localhost [127.0.0.1])${1}${2} /^X-Originating-IP:/ IGNORE diff --git a/roles/MSA/files/etc/postfix/check_sender_access b/roles/MSA/files/etc/postfix/check_sender_access new file mode 100644 index 0000000..07d2874 --- /dev/null +++ b/roles/MSA/files/etc/postfix/check_sender_access @@ -0,0 +1 @@ +<> REJECT Null sender not allowed diff --git a/roles/MSA/files/etc/systemd/system/postfix-sender-login.service b/roles/MSA/files/etc/systemd/system/postfix-sender-login.service new file mode 100644 index 0000000..d652f75 --- /dev/null +++ b/roles/MSA/files/etc/systemd/system/postfix-sender-login.service @@ -0,0 +1,25 @@ +[Unit] +Description=Postfix sender login socketmap +After=mail-transport-agent.target +Requires=postfix-sender-login.socket + +[Service] +User=_postfix-sender-login +StandardInput=null +SyslogFacility=mail +ExecStart=/usr/local/bin/postfix-sender-login.pl + +# Hardening +NoNewPrivileges=yes +PrivateDevices=yes +PrivateNetwork=yes +ProtectHome=yes +ProtectSystem=strict +ProtectControlGroups=yes +ProtectKernelModules=yes +ProtectKernelTunables=yes +RestrictAddressFamilies=AF_UNIX + +[Install] +WantedBy=multi-user.target +Also=postfix-sender-login.socket diff --git a/roles/MSA/files/etc/systemd/system/postfix-sender-login.socket b/roles/MSA/files/etc/systemd/system/postfix-sender-login.socket new file mode 100644 index 0000000..e8d99b5 --- /dev/null +++ b/roles/MSA/files/etc/systemd/system/postfix-sender-login.socket @@ -0,0 +1,8 @@ +[Socket] +SocketUser=postfix +SocketGroup=postfix +SocketMode=0600 +ListenStream=/var/spool/postfix-msa/private/sender-login + +[Install] +WantedBy=sockets.target diff --git a/roles/MSA/files/usr/local/bin/postfix-sender-login.pl b/roles/MSA/files/usr/local/bin/postfix-sender-login.pl new file mode 100755 index 0000000..a37f872 --- /dev/null +++ b/roles/MSA/files/usr/local/bin/postfix-sender-login.pl @@ -0,0 +1,196 @@ +#!/usr/bin/perl -T + +#---------------------------------------------------------------------- +# socketmap lookup table returning the SASL login name(s) owning a given +# sender address +# Copyright © 2017,2020 Guilhem Moulin <guilhem@fripost.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +#---------------------------------------------------------------------- + +use warnings; +use strict; + +use Errno 'EINTR'; + +use Net::LDAPI (); +use Net::LDAP::Util qw/ldap_explode_dn escape_dn_value escape_filter_value/; +use Net::LDAP::Constant qw/LDAP_NO_SUCH_OBJECT/; +use Authen::SASL (); + +# clean up PATH +$ENV{PATH} = join ':', qw{/usr/bin /bin}; +delete @ENV{qw/IFS CDPATH ENV BASH_ENV/}; + +my $nProc = 2; # number of pre-forked servers +my $maxRequests = 32; # maximum number of requests per worker +my $POSTMASTER = 'postmaster@fripost.org'; # returned for forbidden envelope sender addresses + +my $BASEDN = "ou=virtual,dc=fripost,dc=org"; +my $BUFSIZE = 65536; # try to read that many bytes at the time +my $LDAPI = "ldapi://"; +sub server(); + + +# fdopen(3) the file descriptor FD +die "This service must be socket-activated.\n" + unless defined $ENV{LISTEN_PID} and $ENV{LISTEN_PID} == $$ + and defined $ENV{LISTEN_FDS} and $ENV{LISTEN_FDS} == 1; +open my $S, '+<&=', 3 or die "fdopen: $!"; + +my @CHILDREN; +for (my $i = 0; $i < $nProc-1; $i++) { + my $pid = fork() // die "fork: $!"; + if ($pid) { + push @CHILDREN, $pid; + } else { + server(); # child, never return + exit; + } +} +server(); +waitpid $_ => 0 foreach @CHILDREN; +exit $?; + + +############################################################################# + +sub server() { + for (my $n = 0; $n < $maxRequests; $n++) { + accept(my $conn, $S) or do { + next if $! == EINTR; + die "accept: $!"; + }; + my $reply = process_request($conn); + + # encode the reply as a netstring and send it back + # https://cr.yp.to/proto/netstrings.txt + $reply = length($reply).':'.$reply.','; + my $len = length($reply); + + for (my $i = 0; $i < $len;) { + my $n = syswrite($conn, $reply, $len-$i, $i) // do { + next if $! == EINTR; + warn "Can't write: $!"; + last; + }; + $i += $n; + } + close $conn or warn "Can't close: $!"; + } +} + +sub process_request($) { + my $conn = shift; + my ($buf, $offset) = (undef, 0); + + # keep reading until the request length is determined + do { + my $n = sysread($conn, $buf, $BUFSIZE, $offset) // do { + next if $! == EINTR; + return "TEMP can't read: $!"; + }; + return "TEMP EOF" if $n == 0; + $offset += $n; + } until ($buf =~ /\A(0|[1-9][0-9]*):/); + + # keep reading until the whole request is buffered + my $strlen = length("$1") + 1; # [len]":" + my $len = $strlen + $1 + 1; # [len]":"[string]"," + while ($offset < $len) { + my $n = sysread($conn, $buf, $BUFSIZE, $offset) // do { + next if $! == EINTR; + return "TEMP can't read: $!"; + }; + return "TEMP EOF" if $n == 0; + $offset += $n; + } + + # requests are of the form $name <space> $key, cf. socketmap_table(5) + my $i = index($buf, ' ', $strlen); + return "TEMP invalid input: $buf" unless $i > $strlen and substr($buf,-1) eq ','; + my $name = substr($buf, $strlen, $i-$strlen); + my $key = substr($buf, $i, -1); + return "TEMP invalid name: $name" unless $name eq 'sender_login'; + + $key =~ /\A(.+)@([^\@]+)\z/ or return "NOTFOUND "; # invalid sender address + my ($localpart, $domainpart) = ($1, $2); + $localpart =~ s/\+.*//; # strip extension, cf. postconf(5)'s $recipient_delimiter + + my $ldap = Net::LDAPI::->new( $LDAPI ) // + return "TEMP couldn't create Net::LDAPI object"; + $ldap->bind( undef, sasl => Authen::SASL::->new(mechanism => 'EXTERNAL') ) or + return "TEMP LDAP: couldn't bind"; + + my $reply = lookup_sender($ldap, $localpart, $domainpart); + $ldap->unbind(); + return $reply; +} + +sub lookup_sender($$$) { + my ($ldap, $l, $d) = @_; + + my $filter = '(&(objectClass=FripostVirtualDomain)(fvd='.escape_filter_value($d).'))'; + my $mesg = $ldap->search( base => $BASEDN, scope => 'one', deref => 'never' + , filter => $filter + , attrs => [qw/objectClass fripostOwner fripostPostmaster/] + ); + return "TEMP LDAP error: ".$mesg->error() if $mesg->code; + my $entry = $mesg->pop_entry() // return "NOTFOUND "; # not a domain we know + return "TEMP LDAP error: multiple entry founds" if defined $mesg->pop_entry(); # sanity check + + # domain postmasters are allowed to use any sender address + my @logins = $entry->get_value('fripostPostmaster', asref => 0); + my @owners = $entry->get_value('fripostOwner', asref => 0); + + if (grep { $_ eq 'FripostVirtualAliasDomain' } $entry->get_value('objectClass', asref => 0)) { + # so are alias domain owners + push @logins, @owners; + } else { + my $dn = 'fvd='.escape_dn_value($d).','.$BASEDN; + my $filter = '(&(|(objectClass=FripostVirtualAlias)(objectClass=FripostVirtualList)(objectClass=FripostVirtualUser))(fvl='.escape_filter_value($l).'))'; + my $mesg = $ldap->search( base => $dn, scope => 'one', deref => 'never' + , filter => $filter + , attrs => [qw/objectClass fripostOwner/] + ); + unless ($mesg->code == 0 and defined ($entry = $mesg->pop_entry())) { + # domains owners are allowed to use any unkwown localpart as sender address + push @logins, @owners; + } else { + return "TEMP LDAP error: multiple entry founds" if defined $mesg->pop_entry(); # sanity check + if (grep { $_ eq 'FripostVirtualUser' } $entry->get_value('objectClass', asref => 0)) { + push @logins, $entry->dn(); + } else { + # alias/list owners can use the address as sender, and so are the domains owners + push @logins, @owners, $entry->get_value('fripostOwner', asref => 0); + } + } + } + + # convert DNs to SASL login names + my %logins; + foreach my $dn (@logins) { + next unless defined $dn; + $dn = ldap_explode_dn($dn, casefold => 'lower'); + next unless defined $dn and $#$dn == 4; + my $l = $dn->[0]->{fvl} // next; + my $d = $dn->[1]->{fvd} // next; + $logins{$l.'@'.$d} = 1; + } + + # if the entry is found in LDAP but doesn't have an owner, only + # $POSTMASTER is allowed to use it as sender address + my $reply = %logins ? join(',', keys %logins) : $POSTMASTER; + return "OK $reply"; +} diff --git a/roles/MSA/handlers/main.yml b/roles/MSA/handlers/main.yml index 9edf610..a3db0f8 100644 --- a/roles/MSA/handlers/main.yml +++ b/roles/MSA/handlers/main.yml @@ -1,6 +1,9 @@ --- +- name: systemctl daemon-reload + command: /bin/systemctl daemon-reload + - name: Reload Postfix service: name=postfix state=reloaded - name: Restart munin-node service: name=munin-node state=restarted diff --git a/roles/MSA/tasks/main.yml b/roles/MSA/tasks/main.yml index 6b1551f..bf17702 100644 --- a/roles/MSA/tasks/main.yml +++ b/roles/MSA/tasks/main.yml @@ -1,46 +1,144 @@ - name: Install Postfix - apt: pkg={{ item }} - with_items: + apt: pkg={{ packages }} + vars: + packages: - postfix + - postfix-lmdb - postfix-pcre + - postfix-policyd-spf-python + +- name: Install Net::LDAP and Authen::SASL + apt: pkg={{ packages }} + vars: + packages: + - libnet-ldap-perl + - libauthen-sasl-perl + +- name: Copy Postfix sender login socketmap + copy: src=usr/local/bin/postfix-sender-login.pl + dest=/usr/local/bin/postfix-sender-login.pl + owner=root group=staff + mode=0755 + +- name: Create '_postfix-sender-login' user + user: name=_postfix-sender-login system=yes + group=nogroup + createhome=no + home=/nonexistent + shell=/usr/sbin/nologin + password=! + state=present + +- name: Copy Postfix sender login socketmap systemd unit files + copy: src=etc/systemd/system/{{ item }} + dest=/etc/systemd/system/{{ item }} + owner=root group=root + mode=0644 + with_items: + - postfix-sender-login.service + - postfix-sender-login.socket + notify: + - systemctl daemon-reload + +- name: Copy the SMTP TLS policy maps + template: src=etc/postfix/smtp_tls_policy.j2 + dest=/etc/postfix-{{ postfix_instance[inst].name }}/smtp_tls_policy + owner=root group=root + mode=0644 + +- name: Compile the SMTP TLS policy maps + postmap: cmd=postmap src=/etc/postfix-{{ postfix_instance[inst].name }}/smtp_tls_policy db=lmdb + owner=root group=root + mode=0644 + notify: + - Reload Postfix + +- meta: flush_handlers + +- name: Enable Postfix sender login socketmap + service: name=postfix-sender-login.socket state=started enabled=yes - name: Configure Postfix - template: src=etc/postfix/main.cf.j2 - dest=/etc/postfix-{{ postfix_instance[inst].name }}/main.cf + template: src=etc/postfix/{{ item }}.j2 + dest=/etc/postfix-{{ postfix_instance[inst].name }}/{{ item }} owner=root group=root mode=0644 + with_items: + - main.cf + - master.cf notify: - Reload Postfix - name: Copy the Regex to anonymize senders # no need to reload upon change, as cleanup(8) is short-running copy: src=etc/postfix/anonymize_sender.pcre dest=/etc/postfix-{{ postfix_instance[inst].name }}/anonymize_sender.pcre owner=root group=root mode=0644 +- name: Copy the check_sender_access map + copy: src=etc/postfix/check_sender_access + dest=/etc/postfix-{{ postfix_instance[inst].name }}/check_sender_access + owner=root group=root + mode=0644 + +- name: Compile the check_sender_access map + # no need to reload upon change, as cleanup(8) is short-running + postmap: cmd=postmap src=/etc/postfix-{{ postfix_instance[inst].name }}/check_sender_access db=lmdb + owner=root group=root + mode=0644 + notify: + - Reload Postfix + +- name: Configure policyd-spf + template: src=etc/postfix-policyd-spf-python/policyd-spf.conf.j2 + dest=/etc/postfix-policyd-spf-python/policyd-spf.conf + owner=root group=root + mode=0644 + # Reload Postifx to terminate spawn(8) daemon children + notify: + - Reload Postfix + +- name: Create directory /etc/postfix/ssl + file: path=/etc/postfix-{{ postfix_instance[inst].name }}/ssl + state=directory + owner=root group=root + mode=0755 + tags: + - genkey + - meta: flush_handlers - name: Start Postfix service: name=postfix state=started +- name: Fetch Postfix's X.509 certificate + # Ensure we don't fetch private data + become: False + # `/usr/sbin/postmulti -i msa -x /usr/sbin/postconf -xh smtpd_tls_cert_file` + fetch_cmd: cmd="openssl x509 -noout -pubkey" + stdin=/etc/postfix-{{ postfix_instance[inst].name }}/ssl/smtp.fripost.org.pem + dest=certs/public/smtp.fripost.org.pub + tags: + - genkey + - name: Install 'postfix_mailqueue_' Munin wildcard plugin file: src=/usr/local/share/munin/plugins/postfix_mailqueue_ dest=/etc/munin/plugins/postfix_mailqueue_postfix-{{ postfix_instance[inst].name }} owner=root group=root state=link force=yes tags: - munin - munin-node notify: - Restart munin-node - name: Install 'postfix_stats_' Munin wildcard plugin file: src=/usr/local/share/munin/plugins/postfix_stats_ dest=/etc/munin/plugins/postfix_stats_{{ item }}_postfix-{{ postfix_instance[inst].name }} owner=root group=root state=link force=yes with_items: - smtpd - qmgr diff --git a/roles/MSA/templates/etc/postfix-policyd-spf-python/policyd-spf.conf.j2 b/roles/MSA/templates/etc/postfix-policyd-spf-python/policyd-spf.conf.j2 new file mode 100644 index 0000000..2cc1074 --- /dev/null +++ b/roles/MSA/templates/etc/postfix-policyd-spf-python/policyd-spf.conf.j2 @@ -0,0 +1,18 @@ +# {{ ansible_managed }} +# Do NOT edit this file directly! + +debugLevel = 1 +TestOnly = 1 + +HELO_reject = Softfail +Mail_From_reject = Softfail + +PermError_reject = False +TempError_Defer = False + +# We're just trying to keep our outgoing IPs clean of SPF violations, +# not seeking 100% accurate reports. While it's possible that the +# message is routed through a different IP (eg, IPv4 vs v6), giving a +# potentially inaccurate prospective report, it's quite unlikely in +# practice. +Prospective = {{ lookup('pipe', 'dig outgoing.fripost.org A +short | sort | head -n1') }} diff --git a/roles/MSA/templates/etc/postfix/main.cf.j2 b/roles/MSA/templates/etc/postfix/main.cf.j2 index efcebef..6a544ac 100644 --- a/roles/MSA/templates/etc/postfix/main.cf.j2 +++ b/roles/MSA/templates/etc/postfix/main.cf.j2 @@ -1,128 +1,127 @@ ######################################################################## -# MSA configuration +# Mail Submission Agent (MSA) configuration # # {{ ansible_managed }} # Do NOT edit this file directly! -smtpd_banner = $myhostname ESMTP $mail_name (Debian/GNU) -biff = no -readme_directory = no -mail_owner = postfix +smtpd_banner = $myhostname ESMTP $mail_name (Debian/GNU) +biff = no +readme_directory = no +compatibility_level = 2 +smtputf8_enable = no delay_warning_time = 4h maximal_queue_lifetime = 5d myorigin = /etc/mailname myhostname = smtp{{ msano | default('') }}.$mydomain mydomain = fripost.org append_dot_mydomain = no -# Turn off all TCP/IP listener ports except that necessary for the MSA. -master_service_disable = !submission.inet inet +mynetworks = 127.0.0.0/8, [::1]/128 +{%- for h in groups.webmail | difference([inventory_hostname]) | sort -%} + , {{ ipsec[ hostvars[h].inventory_hostname_short ] | ansible.utils.ipaddr }} +{% endfor %} queue_directory = /var/spool/postfix-{{ postfix_instance[inst].name }} data_directory = /var/lib/postfix-{{ postfix_instance[inst].name }} multi_instance_group = {{ postfix_instance[inst].group | default('') }} multi_instance_name = postfix-{{ postfix_instance[inst].name }} multi_instance_enable = yes -# This server is a Mail Submission Agent -mynetworks_style = host -inet_interfaces = all - # No local delivery mydestination = local_transport = error:5.1.1 Mailbox unavailable alias_maps = alias_database = local_recipient_maps = message_size_limit = 67108864 recipient_delimiter = + # Forward everything to our internal outgoing proxy -{% if 'out' in group_names %} -relayhost = [127.0.0.1]:{{ postfix_instance.out.port }} -{% else %} -relayhost = [outgoing.fripost.org]:{{ postfix_instance.out.port }} -{% endif %} +relayhost = [{{ postfix_instance.out.addr | ansible.utils.ipaddr }}]:{{ postfix_instance.out.port }} relay_domains = # Don't rewrite remote headers local_header_rewrite_clients = # Avoid splitting the envelope and scanning messages multiple times smtp_destination_recipient_limit = 1000 # Tolerate occasional high latency smtp_data_done_timeout = 1200s +policyd-spf_time_limit = $ipc_timeout # Anonymize the (authenticated) sender; pass the mail to the antivirus header_checks = pcre:$config_directory/anonymize_sender.pcre #content_filter = amavisfeed:unix:public/amavisfeed-antivirus # TLS -{% if 'out' in group_names %} smtp_tls_security_level = none -smtp_bind_address = 127.0.0.1 -{% else %} -smtp_tls_security_level = encrypt -smtp_tls_cert_file = /etc/postfix/ssl/{{ ansible_fqdn }}.pem -smtp_tls_key_file = /etc/postfix/ssl/{{ ansible_fqdn }}.key -smtp_tls_session_cache_database = btree:$data_directory/smtp_tls_session_cache -smtp_tls_policy_maps = cdb:/etc/postfix/tls_policy -smtp_tls_fingerprint_digest = sha256 -{% endif %} - smtpd_tls_security_level = encrypt -smtpd_tls_cert_file = /etc/postfix/ssl/smtp.fripost.org.pem -smtpd_tls_key_file = /etc/postfix/ssl/private/smtp.fripost.org.key -smtpd_tls_dh1024_param_file = /etc/ssl/private/dhparams.pem -smtpd_tls_session_cache_database= btree:$data_directory/smtpd_tls_session_cache +smtpd_tls_mandatory_ciphers = high +smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1 +smtpd_tls_cert_file = $config_directory/ssl/smtp.fripost.org.pem +smtpd_tls_key_file = $config_directory/ssl/smtp.fripost.org.key +smtpd_tls_dh1024_param_file = /etc/ssl/dhparams.pem +smtpd_tls_session_cache_database= smtpd_tls_received_header = yes -smtpd_tls_ask_ccert = yes +tls_high_cipherlist = ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384 # SASL smtpd_sasl_auth_enable = yes smtpd_sasl_authenticated_header = no smtpd_sasl_local_domain = smtpd_sasl_exceptions_networks = $mynetworks smtpd_sasl_security_options = noanonymous, noplaintext smtpd_sasl_tls_security_options = noanonymous broken_sasl_auth_clients = yes smtpd_sasl_type = dovecot smtpd_sasl_path = unix:private/dovecot-auth strict_rfc821_envelopes = yes smtpd_delay_reject = yes disable_vrfy_command = yes -address_verify_sender = $double_bounce_sender@$mydomain -unverified_recipient_defer_code = 250 -unverified_recipient_reject_code = 550 +address_verify_sender = $double_bounce_sender@noreply.$mydomain +address_verify_poll_count = 3 +address_verify_relayhost = +address_verify_sender_ttl = 8069m +address_verify_negative_refresh_time = 5m +unverified_recipient_defer_code = 250 +unverified_recipient_reject_code = 550 +address_verify_map = lmdb:$data_directory/verify_cache +address_verify_default_transport = smtp_verify smtpd_client_restrictions = permit_sasl_authenticated reject smtpd_helo_required = yes smtpd_helo_restrictions = reject_invalid_helo_hostname +smtpd_sender_login_maps = socketmap:unix:private/sender-login:sender_login smtpd_sender_restrictions = reject_non_fqdn_sender reject_unknown_sender_domain + check_sender_access lmdb:$config_directory/check_sender_access + check_policy_service unix:private/policyd-spf + reject_known_sender_login_mismatch smtpd_relay_restrictions = reject_non_fqdn_recipient reject_unknown_recipient_domain reject_unverified_recipient - permit_mynetworks permit_sasl_authenticated reject smtpd_data_restrictions = reject_unauth_pipelining +smtpd_forbid_bare_newline = normalize +smtpd_forbid_bare_newline_exclusions = $mynetworks + # vim: set filetype=pfmain : diff --git a/roles/MSA/templates/etc/postfix/master.cf.j2 b/roles/MSA/templates/etc/postfix/master.cf.j2 new file mode 120000 index 0000000..011f8e0 --- /dev/null +++ b/roles/MSA/templates/etc/postfix/master.cf.j2 @@ -0,0 +1 @@ +../../../../common/templates/etc/postfix/master.cf.j2
\ No newline at end of file diff --git a/roles/MSA/templates/etc/postfix/smtp_tls_policy.j2 b/roles/MSA/templates/etc/postfix/smtp_tls_policy.j2 new file mode 120000 index 0000000..b40876f --- /dev/null +++ b/roles/MSA/templates/etc/postfix/smtp_tls_policy.j2 @@ -0,0 +1 @@ +../../../../out/templates/etc/postfix/smtp_tls_policy.j2
\ No newline at end of file |