diff options
Diffstat (limited to 'roles/MX')
-rw-r--r-- | roles/MX/files/etc/opendmarc.conf | 116 | ||||
-rw-r--r-- | roles/MX/files/etc/postfix/reject-unknown-client-hostname.cf | 10 | ||||
-rw-r--r-- | roles/MX/files/etc/postfix/virtual/alias.cf | 2 | ||||
-rw-r--r-- | roles/MX/files/etc/postfix/virtual/alias_domains.cf | 2 | ||||
-rw-r--r-- | roles/MX/files/etc/postfix/virtual/catchall.cf | 2 | ||||
-rw-r--r-- | roles/MX/files/etc/postfix/virtual/domains.cf | 2 | ||||
-rw-r--r-- | roles/MX/files/etc/postfix/virtual/list.cf | 2 | ||||
-rw-r--r-- | roles/MX/files/etc/postfix/virtual/mailbox.cf | 2 | ||||
-rw-r--r-- | roles/MX/files/etc/postfix/virtual/reserved_alias.pcre | 3 | ||||
-rw-r--r-- | roles/MX/files/etc/systemd/system/opendmarc.service.d/override.conf | 17 | ||||
-rw-r--r-- | roles/MX/files/etc/systemd/system/opendmarc.socket | 10 | ||||
-rw-r--r-- | roles/MX/handlers/main.yml | 9 | ||||
-rw-r--r-- | roles/MX/tasks/main.yml | 88 | ||||
-rw-r--r-- | roles/MX/templates/etc/postfix/access-list.cidr.j2 | 16 | ||||
-rw-r--r-- | roles/MX/templates/etc/postfix/main.cf.j2 | 115 | ||||
l--------- | roles/MX/templates/etc/postfix/master.cf.j2 | 1 | ||||
-rw-r--r-- | roles/MX/templates/etc/postfix/virtual/transport.j2 | 13 |
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 }} |