summaryrefslogtreecommitdiffstats
path: root/roles/MX
diff options
context:
space:
mode:
Diffstat (limited to 'roles/MX')
-rw-r--r--roles/MX/files/etc/opendmarc.conf116
-rw-r--r--roles/MX/files/etc/postfix/reject-unknown-client-hostname.cf10
-rw-r--r--roles/MX/files/etc/postfix/virtual/alias.cf2
-rw-r--r--roles/MX/files/etc/postfix/virtual/alias_domains.cf2
-rw-r--r--roles/MX/files/etc/postfix/virtual/catchall.cf2
-rw-r--r--roles/MX/files/etc/postfix/virtual/domains.cf2
-rw-r--r--roles/MX/files/etc/postfix/virtual/list.cf2
-rw-r--r--roles/MX/files/etc/postfix/virtual/mailbox.cf2
-rw-r--r--roles/MX/files/etc/postfix/virtual/reserved_alias.pcre3
-rw-r--r--roles/MX/files/etc/systemd/system/opendmarc.service.d/override.conf17
-rw-r--r--roles/MX/files/etc/systemd/system/opendmarc.socket10
-rw-r--r--roles/MX/handlers/main.yml9
-rw-r--r--roles/MX/tasks/main.yml88
-rw-r--r--roles/MX/templates/etc/postfix/access-list.cidr.j216
-rw-r--r--roles/MX/templates/etc/postfix/main.cf.j2115
l---------roles/MX/templates/etc/postfix/master.cf.j21
-rw-r--r--roles/MX/templates/etc/postfix/virtual/transport.j213
17 files changed, 323 insertions, 87 deletions
diff --git a/roles/MX/files/etc/opendmarc.conf b/roles/MX/files/etc/opendmarc.conf
new file mode 100644
index 0000000..ebbc850
--- /dev/null
+++ b/roles/MX/files/etc/opendmarc.conf
@@ -0,0 +1,116 @@
+# This is a basic configuration that can easily be adapted to suit a standard
+# installation. For more advanced options, see openmarc.conf(5) and/or
+# /usr/share/doc/opendmarc/examples/opendmarc.conf.sample.
+
+## AuthservID (string)
+## defaults to MTA name
+##
+## Sets the "authserv-id" to use when generating the Authentication-Results:
+## header field after verifying a message. If the string "HOSTNAME" is
+## provided, the name of the host running the filter (as returned by the
+## gethostname(3) function) will be used.
+#
+# AuthservID name
+
+## FailureReports { true | false }
+## default "false"
+##
+## Enables generation of failure reports when the DMARC test fails and the
+## purported sender of the message has requested such reports. Reports are
+## formatted per RFC6591.
+#
+# FailureReports false
+
+## PublicSuffixList path
+## default (none)
+##
+## Specifies the path to a file that contains top-level domains (TLDs) that
+## will be used to compute the Organizational Domain for a given domain name,
+## as described in the DMARC specification. If not provided, the filter will
+## not be able to determine the Organizational Domain and only the presented
+## domain will be evaluated.
+#
+PublicSuffixList /usr/share/publicsuffix/public_suffix_list.dat
+
+## RejectFailures { true | false }
+## default "false"
+##
+## If set, messages will be rejected if they fail the DMARC evaluation, or
+## temp-failed if evaluation could not be completed. By default, no message
+## will be rejected or temp-failed regardless of the outcome of the DMARC
+## evaluation of the message. Instead, an Authentication-Results header
+## field will be added.
+#
+RejectFailures false
+
+## Socket socketspec
+## default (none)
+##
+## Specifies the socket that should be established by the filter to receive
+## connections from sendmail(8) in order to provide service. socketspec is
+## in one of two forms: local:path, which creates a UNIX domain socket at
+## the specified path, or inet:port[@host] or inet6:port[@host] which creates
+## a TCP socket on the specified port for the appropriate protocol family.
+## If the host is not given as either a hostname or an IP address, the
+## socket will be listening on all interfaces. This option is mandatory
+## either in the configuration file or on the command line. If an IP
+## address is used, it must be enclosed in square brackets.
+#
+Socket local:/run/opendmarc/opendmarc.sock
+
+## Syslog { true | false }
+## default "false"
+##
+## Log via calls to syslog(3) any interesting activity.
+#
+Syslog true
+
+## SyslogFacility facility-name
+## default "mail"
+##
+## Log via calls to syslog(3) using the named facility. The facility names
+## are the same as the ones allowed in syslog.conf(5).
+#
+# SyslogFacility mail
+
+## TrustedAuthservIDs string
+## default HOSTNAME
+##
+## Specifies one or more "authserv-id" values to trust as relaying true
+## upstream DKIM and SPF results. The default is to use the name of
+## the MTA processing the message. To specify a list, separate each entry
+## with a comma. The key word "HOSTNAME" will be replaced by the name of
+## the host running the filter as reported by the gethostname(3) function.
+#
+# TrustedAuthservIDs HOSTNAME
+
+## SPFIgnoreResults { true | false }
+## default "false"
+##
+## Causes the filter to ignore any SPF results in the header of the message.
+## This is useful if you want the filter to perfrom SPF checks itself, or
+## because you don't trust the arriving header.
+#
+SPFIgnoreResults true
+
+## SPFSelfValidate { true | false }
+## default "false"
+##
+## Causes the filter to perform a fallback SPF check itself when it can
+## find no SPF results in the message header. If SPFIgnoreResults is also
+## set, it never looks for SPF results in headers and always performs the
+## SPF check itself when this is set.
+#
+SPFSelfValidate true
+
+## UMask mask
+## default (none)
+##
+## Requests a specific permissions mask to be used for file creation. This
+## only really applies to creation of the socket when Socket specifies a
+## UNIX domain socket, and to the HistoryFile and PidFile (if any); temporary
+## files are normally created by the mkstemp(3) function that enforces a
+## specific file mode on creation regardless of the process umask. See
+## umask(2) for more information.
+#
+UMask 0007
diff --git a/roles/MX/files/etc/postfix/reject-unknown-client-hostname.cf b/roles/MX/files/etc/postfix/reject-unknown-client-hostname.cf
new file mode 100644
index 0000000..1f61f4b
--- /dev/null
+++ b/roles/MX/files/etc/postfix/reject-unknown-client-hostname.cf
@@ -0,0 +1,10 @@
+server_host = ldapi://%2Fprivate%2Fldapi/
+version = 3
+search_base = fvd=%d,ou=virtual,dc=fripost,dc=org
+domain = static:all
+scope = one
+bind = sasl
+sasl_mechs = EXTERNAL
+query_filter = (&(objectClass=FripostVirtualList)(!(objectClass=FripostPendingEntry))(fvl=%u)(fripostIsStatusActive=TRUE))
+result_attribute = fvl
+result_format = reject_unknown_client_hostname
diff --git a/roles/MX/files/etc/postfix/virtual/alias.cf b/roles/MX/files/etc/postfix/virtual/alias.cf
index 1c104a9..2e846ca 100644
--- a/roles/MX/files/etc/postfix/virtual/alias.cf
+++ b/roles/MX/files/etc/postfix/virtual/alias.cf
@@ -1,9 +1,9 @@
-server_host = ldapi://%2Fvar%2Fspool%2Fpostfix-mx%2Fprivate%2Fldapi/
+server_host = ldapi://%2Fprivate%2Fldapi/
version = 3
search_base = fvd=%d,ou=virtual,dc=fripost,dc=org
domain = static:all
scope = one
bind = sasl
sasl_mechs = EXTERNAL
query_filter = (&(objectClass=FripostVirtualAlias)(fvl=%u)(fripostIsStatusActive=TRUE))
result_attribute = fripostMaildrop
diff --git a/roles/MX/files/etc/postfix/virtual/alias_domains.cf b/roles/MX/files/etc/postfix/virtual/alias_domains.cf
index 907166f..1108ea1 100644
--- a/roles/MX/files/etc/postfix/virtual/alias_domains.cf
+++ b/roles/MX/files/etc/postfix/virtual/alias_domains.cf
@@ -1,11 +1,11 @@
-server_host = ldapi://%2Fvar%2Fspool%2Fpostfix-mx%2Fprivate%2Fldapi/
+server_host = ldapi://%2Fprivate%2Fldapi/
version = 3
search_base = ou=virtual,dc=fripost,dc=org
domain = static:all
scope = one
bind = sasl
sasl_mechs = EXTERNAL
# The domain has already been validated (it's active and not pending)
query_filter = (&(objectClass=FripostVirtualAliasDomain)(fvd=%d))
result_attribute = fripostMaildrop
result_format = %U@%s
diff --git a/roles/MX/files/etc/postfix/virtual/catchall.cf b/roles/MX/files/etc/postfix/virtual/catchall.cf
index e0e6350..a67d39c 100644
--- a/roles/MX/files/etc/postfix/virtual/catchall.cf
+++ b/roles/MX/files/etc/postfix/virtual/catchall.cf
@@ -1,10 +1,10 @@
-server_host = ldapi://%2Fvar%2Fspool%2Fpostfix-mx%2Fprivate%2Fldapi/
+server_host = ldapi://%2Fprivate%2Fldapi/
version = 3
search_base = ou=virtual,dc=fripost,dc=org
domain = static:all
scope = one
bind = sasl
sasl_mechs = EXTERNAL
# The domain has already been validated (it's active and not pending)
query_filter = (&(objectClass=FripostVirtualDomain)(!(objectClass=FripostVirtualAliasDomain))(fvd=%d)(fripostOptionalMaildrop=*))
result_attribute = fripostOptionalMaildrop
diff --git a/roles/MX/files/etc/postfix/virtual/domains.cf b/roles/MX/files/etc/postfix/virtual/domains.cf
index f5a7f25..88e17e2 100644
--- a/roles/MX/files/etc/postfix/virtual/domains.cf
+++ b/roles/MX/files/etc/postfix/virtual/domains.cf
@@ -1,11 +1,9 @@
-# XXX: How come we use a socked relative to the chroot here? smtpd(8) is
-# not (can't be) chrooted...
server_host = ldapi://%2Fprivate%2Fldapi/
version = 3
search_base = ou=virtual,dc=fripost,dc=org
scope = one
bind = sasl
sasl_mechs = EXTERNAL
query_filter = (&(objectClass=FripostVirtualDomain)(!(objectClass=FripostPendingEntry))(fvd=%s)(fripostIsStatusActive=TRUE))
result_attribute = fvd
result_format = OK
diff --git a/roles/MX/files/etc/postfix/virtual/list.cf b/roles/MX/files/etc/postfix/virtual/list.cf
index 99e2147..e2df119 100644
--- a/roles/MX/files/etc/postfix/virtual/list.cf
+++ b/roles/MX/files/etc/postfix/virtual/list.cf
@@ -1,12 +1,12 @@
-server_host = ldapi://%2Fvar%2Fspool%2Fpostfix-mx%2Fprivate%2Fldapi/
+server_host = ldapi://%2Fprivate%2Fldapi/
version = 3
search_base = fvd=%d,ou=virtual,dc=fripost,dc=org
domain = static:all
scope = one
bind = sasl
sasl_mechs = EXTERNAL
query_filter = (&(objectClass=FripostVirtualList)(!(objectClass=FripostPendingEntry))(fvl=%u)(fripostIsStatusActive=TRUE))
result_attribute = fripostListManager
# Use a dedicated "virtual" domain to decongestion potential bottlenecks
# on trivial_rewrite(8) due to slow LDAP lookups in tranport_maps.
result_format = %D/%U@%s.fripost.org
diff --git a/roles/MX/files/etc/postfix/virtual/mailbox.cf b/roles/MX/files/etc/postfix/virtual/mailbox.cf
index 7289670..36862db 100644
--- a/roles/MX/files/etc/postfix/virtual/mailbox.cf
+++ b/roles/MX/files/etc/postfix/virtual/mailbox.cf
@@ -1,12 +1,12 @@
-server_host = ldapi://%2Fvar%2Fspool%2Fpostfix-mx%2Fprivate%2Fldapi/
+server_host = ldapi://%2Fprivate%2Fldapi/
version = 3
search_base = fvd=%d,ou=virtual,dc=fripost,dc=org
domain = static:all
scope = one
bind = sasl
sasl_mechs = EXTERNAL
query_filter = (&(objectClass=FripostVirtualUser)(fvl=%u)(fripostIsStatusActive=TRUE))
result_attribute = fvl
# Use a dedicated "virtual" domain to decongestion potential bottlenecks
# on trivial_rewrite(8) due to slow LDAP lookups in tranport_maps.
result_format = %D/%U@mda.fripost.org
diff --git a/roles/MX/files/etc/postfix/virtual/reserved_alias.pcre b/roles/MX/files/etc/postfix/virtual/reserved_alias.pcre
index 9fe60c8..eb17d65 100644
--- a/roles/MX/files/etc/postfix/virtual/reserved_alias.pcre
+++ b/roles/MX/files/etc/postfix/virtual/reserved_alias.pcre
@@ -1,6 +1,5 @@
/^(?:postmaster|abuse)(?:\+.*)?@fripost\.org$/ admin@fripost.org
# For other domains, RFC 822 section 6.3 and RFC 2142 section 4
# mandatory aliases are forwarded to OUR admin team and to the domain
# owner or postmaster, if there are any.
-/^(postmaster|abuse)(?:\+.*)?@(.*)/ $2/$1@reserved.fripost.org
-/^(double-bounce)(?:\+.*)?@(.*)/ $2/$1@discard.fripost.org
+/^(postmaster|abuse)(?:\+.*)?@(.*)/ $2/$1@reserved.fripost.org
diff --git a/roles/MX/files/etc/systemd/system/opendmarc.service.d/override.conf b/roles/MX/files/etc/systemd/system/opendmarc.service.d/override.conf
new file mode 100644
index 0000000..1fb5567
--- /dev/null
+++ b/roles/MX/files/etc/systemd/system/opendmarc.service.d/override.conf
@@ -0,0 +1,17 @@
+[Service]
+Type=simple
+User=opendmarc
+ExecStart=
+ExecStart=/usr/sbin/opendmarc -f -p fd:3
+StandardOutput=journal
+SyslogFacility=mail
+RuntimeDirectory=opendmarc
+
+# Hardening
+NoNewPrivileges=yes
+PrivateDevices=yes
+ProtectHome=yes
+ProtectSystem=strict
+ProtectControlGroups=yes
+ProtectKernelModules=yes
+ProtectKernelTunables=yes
diff --git a/roles/MX/files/etc/systemd/system/opendmarc.socket b/roles/MX/files/etc/systemd/system/opendmarc.socket
new file mode 100644
index 0000000..483ef60
--- /dev/null
+++ b/roles/MX/files/etc/systemd/system/opendmarc.socket
@@ -0,0 +1,10 @@
+[Unit]
+Description=OpenDMARC Milter activation socket
+
+[Socket]
+ListenStream=/var/spool/postfix-mx/public/opendmarc
+SocketUser=postfix
+SocketMode=0666
+
+[Install]
+WantedBy=sockets.target
diff --git a/roles/MX/handlers/main.yml b/roles/MX/handlers/main.yml
index 9edf610..00223a5 100644
--- a/roles/MX/handlers/main.yml
+++ b/roles/MX/handlers/main.yml
@@ -1,6 +1,15 @@
---
+- 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
+
+- name: Stop OpenDMARC
+ service: name=opendmarc.service state=stopped
+
+- name: Restart OpenDMARC
+ service: name=opendmarc.socket state=restarted
diff --git a/roles/MX/tasks/main.yml b/roles/MX/tasks/main.yml
index 4302502..57f17f8 100644
--- a/roles/MX/tasks/main.yml
+++ b/roles/MX/tasks/main.yml
@@ -1,36 +1,41 @@
- name: Install Postfix
- apt: pkg={{ item }}
- with_items:
+ apt: pkg={{ packages }}
+ vars:
+ packages:
- postfix
- postfix-pcre
- postfix-ldap
- - postfix-cdb
+ - postfix-lmdb
# The following is for reserved-alias.pl
- libnet-ldap-perl
- libauthen-sasl-perl
- 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
+ - access-list.cidr
notify:
- Reload Postfix
- name: Create directory /etc/postfix-.../virtual
file: path=/etc/postfix-{{ postfix_instance[inst].name }}/virtual
state=directory
owner=root group=root
mode=0755
# trivial-rewrite(8) runs in a chroot. We create an empty
# /usr/lib/sasl2 to avoid "No such file or directory" warnings.
# Cf. also #738989.
- name: Create directory /usr/lib/sasl2
file: path=/var/spool/postfix-{{ postfix_instance[inst].name }}/{{ item }}
state=directory
owner=root group=root
mode=0755
with_items:
- /usr/lib/sasl2
- /usr/lib/{{ ansible_architecture }}-linux-gnu/sasl2
@@ -41,68 +46,139 @@
copy: src=etc/postfix/virtual/{{ item }}
dest=/etc/postfix-{{ postfix_instance[inst].name }}/virtual/{{ item }}
owner=root group=root
mode=0644
with_items:
- domains.cf
# no need to reload upon change, as cleanup(8) is short-running
- reserved_alias.pcre
- alias.cf
- mailbox.cf
- list.cf
- alias_domains.cf
- catchall.cf
- name: Copy lookup tables (2)
template: src=etc/postfix/virtual/transport.j2
dest=/etc/postfix-{{ postfix_instance[inst].name }}/virtual/transport
owner=root group=root
mode=0644
+- name: Copy recipient access(5) map
+ copy: src=etc/postfix/reject-unknown-client-hostname.cf
+ dest=/etc/postfix-{{ postfix_instance[inst].name }}/reject-unknown-client-hostname.cf
+ owner=root group=root
+ mode=0644
+ notify:
+ - Reload Postfix
+
- name: Compile the Postfix transport maps
# trivial-rewrite(8) is a long-running process, so it's safer to reload
postmap: instance={{ postfix_instance[inst].name }}
- src=/etc/postfix-{{ postfix_instance[inst].name }}/virtual/transport db=cdb
+ src=/etc/postfix-{{ postfix_instance[inst].name }}/virtual/transport db=lmdb
owner=root group=root
mode=0644
notify:
- Reload Postfix
- name: Copy reserved-alias.pl
copy: src=usr/local/bin/reserved-alias.pl
dest=/usr/local/bin/reserved-alias.pl
+ owner=root group=staff
+ mode=0755
+
+- 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 mx -x /usr/sbin/postconf -xh smtpd_tls_cert_file`
+ fetch_cmd: cmd="openssl x509 -noout -pubkey"
+ stdin=/etc/postfix-{{ postfix_instance[inst].name }}/ssl/mx.fripost.org.pem
+ dest=certs/public/mx{{ mxno | default('') }}.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:
- postscreen
- smtpd
- qmgr
- smtp
- pipe
tags:
- munin
- munin-node
notify:
- Restart munin-node
+
+# XXX we probaly want SPF verification for domains without DMARC
+# policies
+- name: Install OpenDMARC
+ apt: pkg=opendmarc
+
+- name: Copy OpenDMARC configuration
+ copy: src=etc/opendmarc.conf
+ dest=/etc/opendmarc.conf
+ owner=root group=root
+ mode=0644
+ notify:
+ - Stop OpenDMARC
+
+- name: Create directory /etc/systemd/system/opendmarc.service.d
+ file: path=/etc/systemd/system/opendmarc.service.d
+ state=directory
+ owner=root group=root
+ mode=0755
+
+- name: Harden OpenDMARC service unit
+ copy: src=etc/systemd/system/opendmarc.service.d/override.conf
+ dest=/etc/systemd/system/opendmarc.service.d/override.conf
+ owner=root group=root
+ mode=0644
+ notify:
+ - systemctl daemon-reload
+ - Stop OpenDMARC
+
+- meta: flush_handlers
+
+- name: Copy OpenDMARC socket unit
+ copy: src=etc/systemd/system/opendmarc.socket
+ dest=/etc/systemd/system/opendmarc.socket
+ owner=root group=root
+ mode=0644
+ notify:
+ - systemctl daemon-reload
+ - Restart OpenDMARC
+
+- name: Disable OpenDMARC service
+ service: name=opendmarc.service enabled=false
+
+- name: Start OpenDMARC socket
+ service: name=opendmarc.socket state=started enabled=true
diff --git a/roles/MX/templates/etc/postfix/access-list.cidr.j2 b/roles/MX/templates/etc/postfix/access-list.cidr.j2
new file mode 100644
index 0000000..bd6e3d8
--- /dev/null
+++ b/roles/MX/templates/etc/postfix/access-list.cidr.j2
@@ -0,0 +1,16 @@
+########################################################################
+# Access list, see cidr_table(5)
+#
+# {{ ansible_managed }}
+# Do NOT edit this file directly!
+
+{% if ipsec_subnet is defined %}
+{{ ipsec_subnet }} permit
+{% endif %}
+
+{% for ip in lookup('pipe', 'dig +short outgoing.fripost.org A').splitlines() | sort -%}
+{{ ip }}/32 permit
+{% endfor %}
+{% for ip in lookup('pipe', 'dig +short outgoing.fripost.org AAAA').splitlines() | sort -%}
+{{ ip }}/128 permit
+{% endfor %}
diff --git a/roles/MX/templates/etc/postfix/main.cf.j2 b/roles/MX/templates/etc/postfix/main.cf.j2
index b9f7c09..d10f901 100644
--- a/roles/MX/templates/etc/postfix/main.cf.j2
+++ b/roles/MX/templates/etc/postfix/main.cf.j2
@@ -1,163 +1,156 @@
########################################################################
-# MX configuration
+# Mail eXchange (MX) 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 = mx{{ mxno | default('') }}.$mydomain
mydomain = fripost.org
append_dot_mydomain = no
-# Turn off all TCP/IP listener ports except that necessary for the mail
-# exchange.
-master_service_disable = !smtp.inet inet
+mynetworks_style = host
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 eXchange
-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 =
# Virtual transport
# We use a dedicated "virtual" domain to decongestion potential
# bottlenecks on trivial_rewrite(8) due to slow LDAP lookups in
# tranport_maps.
virtual_transport = error:5.1.1 Virtual transport unavailable
-virtual_alias_domains = !cdb:$config_directory/virtual/transport
+virtual_alias_domains = !lmdb:$config_directory/virtual/transport
ldap:$config_directory/virtual/domains.cf
virtual_alias_maps = pcre:$config_directory/virtual/reserved_alias.pcre
# unless there is a matching user/alias/list...
ldap:$config_directory/virtual/mailbox.cf
ldap:$config_directory/virtual/alias.cf
ldap:$config_directory/virtual/list.cf
# ...we resolve alias domains and catch alls
ldap:$config_directory/virtual/alias_domains.cf
ldap:$config_directory/virtual/catchall.cf
-transport_maps = cdb:$config_directory/virtual/transport
+transport_maps = lmdb:$config_directory/virtual/transport
# Don't rewrite remote headers
local_header_rewrite_clients =
# Pass the client information along to the content filter
smtp_send_xforward_command = yes
# Avoid splitting the envelope and scanning messages multiple times
smtp_destination_recipient_limit = 1000
reserved-alias_destination_recipient_limit = 1
# Tolerate occasional high latency
smtp_data_done_timeout = 1200s
-{% 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 = may
-smtpd_tls_exclude_ciphers = EXPORT, LOW, MEDIUM, aNULL, eNULL, DES, RC4, MD5
-smtpd_tls_cert_file = /etc/ssl/certs/ssl-cert-snakeoil.pem
-smtpd_tls_key_file = /etc/ssl/private/ssl-cert-snakeoil.key
-smtpd_tls_dh1024_param_file = /etc/ssl/private/dhparams.pem
+smtpd_tls_ciphers = medium
+smtpd_tls_protocols = !SSLv2, !SSLv3
+smtpd_tls_cert_file = $config_directory/ssl/mx.fripost.org.pem
+smtpd_tls_key_file = $config_directory/ssl/mx.fripost.org.key
+smtpd_tls_dh1024_param_file = /etc/ssl/dhparams.pem
smtpd_tls_CApath = /etc/ssl/certs/
-smtpd_tls_session_cache_database= btree:$data_directory/smtpd_tls_session_cache
+smtpd_tls_session_cache_database=
smtpd_tls_received_header = yes
-smtpd_tls_ask_ccert = yes
# http://en.linuxreviews.org/HOWTO_Stop_spam_using_Postfix
# http://www.howtoforge.com/block_spam_at_mta_level_postfix
strict_rfc821_envelopes = yes
smtpd_delay_reject = yes
disable_vrfy_command = yes
-# UCE control
-invalid_hostname_reject_code = 554
-multi_recipient_bounce_reject_code = 554
-non_fqdn_reject_code = 554
-relay_domains_reject_code = 554
-unknown_address_reject_code = 554
-unknown_client_reject_code = 554
-unknown_hostname_reject_code = 554
-unknown_local_recipient_reject_code = 554
-unknown_relay_recipient_reject_code = 554
-unknown_virtual_alias_reject_code = 554
-unknown_virtual_mailbox_reject_code = 554
+postscreen_access_list =
+ permit_mynetworks
+ cidr:$config_directory/access-list.cidr
+postscreen_dnsbl_whitelist_threshold = -1
+postscreen_cache_map = lmdb:$data_directory/postscreen_cache
postscreen_blacklist_action = drop
-postscreen_dnsbl_threshold = 3
+postscreen_dnsbl_threshold = 8
postscreen_dnsbl_action = enforce
postscreen_dnsbl_sites =
- zen.spamhaus.org*3
- swl.spamhaus.org*-4
- b.barracudacentral.org*2
- bl.spameatingmonkey.net*2
- bl.spamcop.net
- dnsbl.sorbs.net
- list.dnswl.org=127.[0..255].[0..255].0*-2
- list.dnswl.org=127.[0..255].[0..255].1*-3
- list.dnswl.org=127.[0..255].[0..255].[2..255]*-4
-
-postscreen_greet_action = enforce
-postscreen_whitelist_interfaces = !88.80.11.28 ![2a00:16b0:242:13::de30] static:all
+ zen.spamhaus.org=127.0.0.[10;11]*8
+ zen.spamhaus.org=127.0.0.[4..7]*6
+ zen.spamhaus.org=127.0.0.3*4
+ zen.spamhaus.org=127.0.0.2*3
+ #swl.spamhaus.org*-4
+ b.barracudacentral.org=127.0.0.2*7
+ bl.mailspike.net=127.0.0.2*5
+ bl.mailspike.net=127.0.0.[10..12]*4
+ wl.mailspike.net=127.0.0.[18..20]*-2
+ bl.spameatingmonkey.net=127.0.0.2*4
+ bl.spamcop.net=127.0.0.2*2
+ dnsbl.sorbs.net=127.0.0.10*8
+ dnsbl.sorbs.net=127.0.0.5*6
+ dnsbl.sorbs.net=127.0.0.7*3
+ dnsbl.sorbs.net=127.0.0.8*2
+ dnsbl.sorbs.net=127.0.0.6*2
+ dnsbl.sorbs.net=127.0.0.9*2
+ list.dnswl.org=127.0.[0..255].0*-2
+ list.dnswl.org=127.0.[0..255].1*-3
+ list.dnswl.org=127.0.[0..255].[2..3]*-4
+
+postscreen_greet_action = enforce
+postscreen_whitelist_interfaces = static:all
+
+smtpd_milters = { unix:public/opendmarc, protocol=6, default_action=accept }
smtpd_client_restrictions =
permit_mynetworks
smtpd_helo_required = yes
smtpd_helo_restrictions =
permit_mynetworks
reject_non_fqdn_helo_hostname
reject_invalid_helo_hostname
smtpd_sender_restrictions =
reject_non_fqdn_sender
+ reject_unknown_sender_domain
smtpd_relay_restrictions =
reject_non_fqdn_recipient
permit_mynetworks
reject_unauth_destination
reject_unlisted_recipient
+smtpd_recipient_restrictions =
+ check_client_access cidr:$config_directory/access-list.cidr
+ check_recipient_access ldap:$config_directory/reject-unknown-client-hostname.cf
+ reject_rhsbl_reverse_client dbl.spamhaus.org=127.0.1.[2..99]
+ reject_rhsbl_sender dbl.spamhaus.org=127.0.1.[2..99]
+
smtpd_data_restrictions =
reject_unauth_pipelining
# vim: set filetype=pfmain :
diff --git a/roles/MX/templates/etc/postfix/master.cf.j2 b/roles/MX/templates/etc/postfix/master.cf.j2
new file mode 120000
index 0000000..011f8e0
--- /dev/null
+++ b/roles/MX/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/MX/templates/etc/postfix/virtual/transport.j2 b/roles/MX/templates/etc/postfix/virtual/transport.j2
index 49f3696..536748a 100644
--- a/roles/MX/templates/etc/postfix/virtual/transport.j2
+++ b/roles/MX/templates/etc/postfix/virtual/transport.j2
@@ -1,30 +1,21 @@
# Each valid address user@example.org is aliased (on the MX) into some
# example.org/user@xxx.fripost.org, and non-defaults next-hop:port are
# chosen here in that table, depending on 'xxx'. The reason for such
# indirection is that there is only one qmgr(8) daemon, which delegate
# the routing strategy to the trivial-rewrite(8), which in turns queries
# transport_maps. Hence high latency maps such as LDAP or SQL would
# congestion the queue manager. On the other hand, virtual aliasing is
# performed by cleanup(8), multiples instances of which can run in
# parallel. See http://www.postfix.org/ADDRESS_REWRITING_README.html .
#
# /!\ WARNING: xxx.fripost.org should NOT be in the list of valid
# domains ($virtual_alias_domains)! Otherwise at the next iteration of
# the alias resolution loop the domain will be validated but not the
# address, and the MTA will reply with "Recipient address rejected: User
# unknown in virtual alias table".
reserved.fripost.org reserved-alias:
discard.fripost.org discard:
-{% if 'LDA' in group_names %}
-mda.fripost.org smtpl:[127.0.0.1]:{{ postfix_instance.IMAP.port }}
-{% else %}
-mda.fripost.org smtp:[mda.fripost.org]:{{ postfix_instance.IMAP.port }}
-{% endif %}
-
-{% if 'lists' in group_names %}
-sympa.fripost.org smtpl:[127.0.0.1]:{{ postfix_instance.lists.port }}
-{% else %}
-sympa.fripost.org smtp:[lists.fripost.org]:{{ postfix_instance.lists.port }}
-{% endif %}
+mda.fripost.org smtp:[{{ postfix_instance.IMAP.addr | ansible.utils.ipaddr }}]:{{ postfix_instance.IMAP.port }}
+sympa.fripost.org smtp:[{{ postfix_instance.lists.addr | ansible.utils.ipaddr }}]:{{ postfix_instance.lists.port }}