diff --git a/package-postfix_access/defaults/main.yml b/package-postfix_access/defaults/main.yml new file mode 100644 index 0000000..c4d182e --- /dev/null +++ b/package-postfix_access/defaults/main.yml @@ -0,0 +1,37 @@ +--- +# Default configurations +# I populate these from external configs; I indicate what they are as inline comments + +domain: "{{ blsedomains_admindomain }}" # Base domain name +postmaster: "root@{{ blsedomains_rootdomain }}" # Postmaster email address + +# Roundcube +smtp_host: "{{ blsecluster_smtphost }}" # The hostname for SMTP access, usually the public name of your mail server +support_url: "https://www.{{ blsedomains_webdomain }}" # Some website address for Roundcube support +logo_filename: "bl-logo-roundcube.png" # The Roundcube logo under files/ +roundcube_deskey: "{{ passwd_roundcube_deskey }}" # The Roundcube DES key + +# Postfix +banner_hostname: "{{ ansible_hostname }}.{{ domain }}" # Public hostname of *this* mail host +myhostname: "{{ banner_hostname }}" # Hostname for Postfix myhostame +mydomain: "{{ domain }}" # Domain for Postfix mydomain +mynetworks: "{{ blsecluster_remote1v4 }} {{ blsecluster_remote2v4 }} {{ blsecluster_remote3v4 }} {{ blsecluster_hostsubnetv4 }}" # IP addresses for Postfix mynetworks + +# Dovecot +# Note: SSL listeners aren't provided; HAProxy is expected to do SSL termination for us +trusted_networks: "{{ blsecluster_hostsubnetv4 }} {{ blsecluster_hostsubnetv6 }}" # Trusted network ranges for Dovecot +haproxy: yes # Enable HAProxy-specific (Proxy protocol) listeners on ports 10143 and 10110 + +# LDAP integration (Postfix, Dovecot, Roundcube) +ldap_host: "{{ blsecluster_ldaphost }}" # The hostname for LDAP access +ldap_port: 389 # The LDAP port (always non-SSL) +ldap_basedn: "o=domains,dc=bonilan,dc=net" # The LDAP base DN +ldap_bind_username: "{{ username_ldap_admin }}" # The LDAP bind user name (usually cn=admin) +ldap_bind_password: "{{ passwd_ldap_admin }}" # The LDAP bind user password + +# MySQL integration (Roundcube) +mysql_host: "{{ blsecluster_sqlhost }}" # The hostname for MySQL access +mysql_port: "{{ mysql_client['mail'].port }}" # The port for MySQL access +mysql_database: "{{ mysql_client['mail'].database }}" # The database name +mysql_username: "{{ mysql_client['mail'].username }}" # The database user +mysql_password: "{{ mysql_client['mail'].passwd }}" # The database password diff --git a/package-postfix_access/files/bl-logo-roundcube.png b/package-postfix_access/files/bl-logo-roundcube.png new file mode 100644 index 0000000..d47c557 Binary files /dev/null and b/package-postfix_access/files/bl-logo-roundcube.png differ diff --git a/package-postfix_access/handlers/main.yml b/package-postfix_access/handlers/main.yml new file mode 100644 index 0000000..fb24197 --- /dev/null +++ b/package-postfix_access/handlers/main.yml @@ -0,0 +1,23 @@ +--- +- name: postmap transport + command: "postmap /etc/postfix/transport" +- name: restart amavis + service: + name: "amavis" + state: "restarted" +- name: restart saslauthd + service: + name: "saslauthd" + state: "restarted" +- name: restart postfix + service: + name: "postfix" + state: "restarted" +- name: restart dovecot + service: + name: "dovecot" + state: "restarted" +- name: restart apache2 + service: + name: "apache2" + state: "restarted" diff --git a/package-postfix_access/tasks/main.yml b/package-postfix_access/tasks/main.yml new file mode 100644 index 0000000..617ccd8 --- /dev/null +++ b/package-postfix_access/tasks/main.yml @@ -0,0 +1,222 @@ +--- +- name: install filtering packages and monitoring components + apt: + name: + - postfix + - postfix-ldap + - postfix-pcre + - dovecot-core + - dovecot-imapd + - dovecot-pop3d + - dovecot-lmtpd + - dovecot-sieve + - dovecot-managesieved + - dovecot-ldap + - dovecot-mysql + - apache2 + - libapache2-mod-php + - roundcube + - roundcube-plugins + - php-ldap + - php-net-sieve + - mailgraph + - amavis + - spamassassin + - clamav-daemon + - libnet-dns-perl + - libmail-spf-perl + - pyzor + - razor + - pfqueue + state: latest + +- name: install compression algorithms for scanning + apt: + name: + - p7zip-full + - arj + - bzip2 + - cabextract + - cpio + - file + - gzip + - lhasa + - liblz4-tool + - lrzip + - lzop + - nomarch + - pax + - rar + - rpm + - unrar-free + - unzip + - xz-utils + - zip + state: latest + +# ClamAV +- name: ensure clamav is in amavis group + user: + name: "clamav" + append: "yes" + groups: "amavis" + +- name: ensure amavis is in clamav group + user: + name: "amavis" + append: "yes" + groups: "clamav" + +# Amavis +- name: install Amavis configs + template: + src: "{{ item }}.j2" + dest: "/etc/amavis/conf.d/{{ item }}" + notify: + - restart amavis + with_items: + - 15-content_filter_mode + - 50-user + +# Postfix +- name: install Postfix main configs + template: + src: "{{ item }}.j2" + dest: "/etc/postfix/{{ item }}" + notify: + - restart postfix + with_items: + - main.cf + - master.cf + - helo_access.pcre + - transport + +- name: map transport + command: postmap /etc/postfix/transport + +- name: create LDAP config dir + file: + name: "/etc/postfix/ldap" + state: "directory" + +- name: install Postfix LDAP configs + template: + src: "postfix-ldap/{{ item }}.j2" + dest: "/etc/postfix/ldap/{{ item }}" + mode: "640" + group: "postfix" + notify: + - restart postfix + with_items: + - catchall_maps.cf + - recipient_bcc_maps_domain.cf + - recipient_bcc_maps_user.cf + - relay_domains.cf + - sender_bcc_maps_domain.cf + - sender_bcc_maps_user.cf + - sender_login_maps.cf + - transport_maps_domain.cf + - transport_maps_user.cf + - virtual_alias_maps.cf + - virtual_group_maps.cf + - virtual_group_members_maps.cf + - virtual_mailbox_domains.cf + - virtual_mailbox_maps.cf + +- name: link /etc/mailname to /etc/hostname + file: + dest: "/etc/mailname" + src: "/etc/hostname" + state: "link" + force: "yes" + +# Dovecot +- name: install Dovecot main configs + template: + src: "{{ item }}.j2" + dest: "/etc/dovecot/{{ item }}" + notify: + - restart dovecot + with_items: + - dovecot.conf + - dovecot-ldap.conf + +- name: add vmail group + group: + name: "vmail" + gid: "2000" + state: "present" + +- name: add vmail user + user: + name: "vmail" + home: "/srv/vmail" + shell: "/bin/false" + uid: "2000" + group: "vmail" + state: "present" + +- name: ensure log ownership + file: + dest: "/var/log/{{ item }}" + owner: "vmail" + group: "adm" + mode: "644" + state: "touch" + with_items: + - dovecot.log + - dovecot-lmtp.log + +# Roundcube +- name: Install roundcube PHP configs + template: + src: "{{ item }}.j2" + dest: "/etc/roundcube/{{ item }}" + mode: "640" + group: "www-data" + with_items: + - debian-db.php + - config.inc.php + +- name: Remove default apache2 config + file: + name: "/etc/apache2/sites-enabled/000-default.conf" + state: "absent" + notify: + - restart apache2 + +- name: Install roundcube ports config + template: + src: "ports.conf.j2" + dest: "/etc/apache2/ports.conf" + notify: + - restart apache2 + +- name: Install roundcube apache2 config + template: + src: "roundcube.conf.j2" + dest: "/etc/roundcube/apache.conf" + notify: + - restart apache2 + +- name: create logo dir + file: + dest: "/var/lib/roundcube/images" + state: "directory" + +- name: install Roundcube logo + copy: + src: "{{ logo_filename }}" + dest: "/var/lib/roundcube/images/{{ logo_filename }}" + +# General +- name: ensure services are running (and enabled at boot) + service: + name: "{{ item }}" + state: "started" + enabled: "yes" + with_items: + - postfix + - amavis + - clamav-daemon + - dovecot diff --git a/package-postfix_access/templates/15-content_filter_mode.j2 b/package-postfix_access/templates/15-content_filter_mode.j2 new file mode 100644 index 0000000..8ea341f --- /dev/null +++ b/package-postfix_access/templates/15-content_filter_mode.j2 @@ -0,0 +1,12 @@ +use strict; + +# Amavis filter configuration +# {{ ansible_managed }} + +@bypass_virus_checks_maps = ( + \%bypass_virus_checks, \@bypass_virus_checks_acl, \$bypass_virus_checks_re); + +@bypass_spam_checks_maps = ( + \%bypass_spam_checks, \@bypass_spam_checks_acl, \$bypass_spam_checks_re); + +1; # ensure a defined return diff --git a/package-postfix_access/templates/50-user.j2 b/package-postfix_access/templates/50-user.j2 new file mode 100644 index 0000000..3f9136a --- /dev/null +++ b/package-postfix_access/templates/50-user.j2 @@ -0,0 +1,12 @@ +use strict; + +@local_domains_acl = ( "." ); +$sa_tag_level_deflt = -9999; +$sa_tag2_level_deflt = 4.5; +$sa_kill_level_deflt = 4.5; +$sa_spam_subject_tag = '*** SPAM *** '; + +$forward_method = 'smtp:[::1]:10025'; + +#------------ Do not modify anything below this line ------------- +1; # ensure a defined return diff --git a/package-postfix_access/templates/config.inc.php.j2 b/package-postfix_access/templates/config.inc.php.j2 new file mode 100644 index 0000000..a6bd5af --- /dev/null +++ b/package-postfix_access/templates/config.inc.php.j2 @@ -0,0 +1,111 @@ + "/images/logo_login_small.png", + "elastic:login" => "/images/logo_login.png", + "elastic:*[small]" => "/images/logo_small.png", + "larry:*" => "/images/larry.png", + "login" => "/images/logo_login.png", + "[print]" => "/images/logo_print.png", +); +$config['skin_logo'] = 'images/{{ logo_filename }}'; + +$config['des_key'] = '{{ roundcube_deskey }}'; + +// ---------------------------------- +// PLUGINS +// ---------------------------------- +$config['plugins'] = array('managesieve'); +$config['create_default_folders'] = true; +$config['quota_zero_as_unlimited'] = true; +$config['ldap_public'] = array ( + 'global_ldap_abook' => + array ( + 'name' => 'Global LDAP Address Book', + 'hosts' => + array ( + 0 => '{{ ldap_host }}', + ), + 'port' => {{ ldap_port }}, + 'use_tls' => false, + 'ldap_version' => '3', + 'network_timeout' => 10, + 'user_specific' => true, + 'base_dn' => '{{ ldap_basedn }}', + 'bind_dn' => 'mail=%u@%d,ou=Users,domainName=%d,{{ ldap_basedn }}', + 'hidden' => false, + 'searchonly' => false, + 'writable' => false, + 'search_fields' => + array ( + 0 => 'mail', + 1 => 'cn', + 2 => 'sn', + 3 => 'givenName', + 4 => 'street', + 5 => 'telephoneNumber', + 6 => 'mobile', + 7 => 'stree', + 8 => 'postalCode', + ), + 'fieldmap' => + array ( + 'name' => 'cn', + 'surname' => 'sn', + 'firstname' => 'givenName', + 'title' => 'title', + 'email' => 'mail:*', + 'phone:work' => 'telephoneNumber', + 'phone:mobile' => 'mobile', + 'street' => 'street', + 'zipcode' => 'postalCode', + 'locality' => 'l', + 'department' => 'departmentNumber', + 'notes' => 'description', + 'phone:workfax' => 'facsimileTelephoneNumber', + 'photo' => 'jpegPhoto', + ), + 'sort' => 'cn', + 'scope' => 'sub', + 'filter' => '(&(enabledService=mail)(enabledService=deliver)(enabledService=displayedInGlobalAddressBook)(|(objectClass=mailList)(objectClass=mailAlias)(objectClass=mailUser)))', + 'fuzzy_search' => true, + 'vlv' => false, + 'sizelimit' => '0', + 'timelimit' => '0', + 'referrals' => false, + 'group_filters' => + array ( + 'departments' => + array ( + 'name' => 'Mailing Lists', + 'scope' => 'sub', + 'base_dn' => '{{ ldap_basedn }}', + 'filter' => '(&(objectclass=mailList)(accountStatus=active)(enabledService=displayedInGlobalAddressBook))', + 'name_attr' => 'cn', + 'email' => 'mail', + ), + ), + ), +); +$config['autocomplete_addressbooks'] = array('sql', 'global_ldap_abook'); +$config['skin'] = 'elastic'; +$config['addressbook_sort_col'] = 'name'; +$config['draft_autosave'] = 60; +$config['check_all_folders'] = true; +$config['autoexpand_threads'] = 2; + +include_once("/etc/roundcube/debian-db-roundcube.php"); diff --git a/package-postfix_access/templates/debian-db.php.j2 b/package-postfix_access/templates/debian-db.php.j2 new file mode 100644 index 0000000..191b384 --- /dev/null +++ b/package-postfix_access/templates/debian-db.php.j2 @@ -0,0 +1,9 @@ + + Options +FollowSymLinks + # This is needed to parse /var/lib/roundcube/.htaccess. See its + # content before setting AllowOverride to None. + AllowOverride All + = 2.3> + Require all granted + + + Order allow,deny + Allow from all + + + +# Protecting basic directories: + + Options -FollowSymLinks + AllowOverride None + + + + Options -FollowSymLinks + AllowOverride None + = 2.3> + Require all denied + + + Order allow,deny + Deny from all + + + + + Options -FollowSymLinks + AllowOverride None + = 2.3> + Require all denied + + + Order allow,deny + Deny from all + + + diff --git a/package-postfix_access/templates/transport.j2 b/package-postfix_access/templates/transport.j2 new file mode 100644 index 0000000..da9f35c --- /dev/null +++ b/package-postfix_access/templates/transport.j2 @@ -0,0 +1,3 @@ +# Gmail-specific transfer policy +# {{ ansible_managed }} +gmail.com smtp-ipv4: diff --git a/package-postfix_filter/defaults/main.yml b/package-postfix_filter/defaults/main.yml new file mode 100644 index 0000000..7e116ab --- /dev/null +++ b/package-postfix_filter/defaults/main.yml @@ -0,0 +1,35 @@ +--- +# Default configurations +# I populate these from external configs; I indicate what the are as inline comments + +# Postfix + +# A list of relay domains and their target (square-bracked hostname/IP + port); examples follow +relay_domains: "{{ blse_relaydomains }}" +# - domain: "some.domain.tld" +# relay: "[mail.domain.tld]" +# - domain: "other.domain.tld" +# relay: "[secure.domain.tld]:465" + +# A list of RBLs to check for rejecting incoming mail +remote_block_lists: + - bl.spamcop.net + - zen.spamhaus.org + - cbl.abuseat.org + +# Enable TLS (literal yes/no only) and, if yes, the cert and key files +tls_enabled: yes +tls_cert: "/etc/ssl/{{ ansible_fqdn }}.crt" +tls_key: "/etc/ssl/{{ ansible_fqdn }}.key" + +# Virtual address maps +virtual_maps: + - regex: "/^postmaster@/" + map: "root@{{ blsedomains_admindomain }}" + +# SpamAssassin +notify_admin: "joshua@boniface.me" # Administrative address to notify +notify_method: "smtp:{{ blsecluster_smtphost }}:25" +custom_sender_scores: + - [qr'^(offers)@'i => 1.0] + - [qr'^.*@pizzanova.com'i => 1.0] diff --git a/package-postfix_filter/files/ham-sample/README b/package-postfix_filter/files/ham-sample/README new file mode 100644 index 0000000..76b5c47 --- /dev/null +++ b/package-postfix_filter/files/ham-sample/README @@ -0,0 +1,2 @@ +Populate me with spam-tagged legit emails. +Then `tar -cvJf ham-sample.txz ham-sample/` in the parent directory. diff --git a/package-postfix_filter/files/spam-sample/README b/package-postfix_filter/files/spam-sample/README new file mode 100644 index 0000000..76b5c47 --- /dev/null +++ b/package-postfix_filter/files/spam-sample/README @@ -0,0 +1,2 @@ +Populate me with spam-tagged legit emails. +Then `tar -cvJf ham-sample.txz ham-sample/` in the parent directory. diff --git a/package-postfix_filter/handlers/main.yml b/package-postfix_filter/handlers/main.yml new file mode 100644 index 0000000..e7784cc --- /dev/null +++ b/package-postfix_filter/handlers/main.yml @@ -0,0 +1,19 @@ +--- +- name: postmap transport + command: "postmap /etc/postfix/transport" +- name: restart amavis + service: + name: "amavis" + state: "restarted" +- name: restart saslauthd + service: + name: "saslauthd" + state: "restarted" +- name: restart postfix + service: + name: "postfix" + state: "restarted" +- name: restart spamassassin + service: + name: "spamassassin" + state: "restarted" diff --git a/package-postfix_filter/tasks/main.yml b/package-postfix_filter/tasks/main.yml new file mode 100644 index 0000000..ba1f684 --- /dev/null +++ b/package-postfix_filter/tasks/main.yml @@ -0,0 +1,220 @@ +--- +# +# Install role packages +# + +- name: install filtering packages and monitoring components + apt: + name: + - postfix + - postfix-pcre + - mailgraph + - amavis + - spamassassin + - clamav-daemon + - libnet-dns-perl + - libmail-spf-perl + - postfix-policyd-spf-python + - pfqueue + state: latest + +- name: install compression algorithms for scanning + apt: + name: + - p7zip-full + - arj + - bzip2 + - cabextract + - cpio + - file + - gzip + - lhasa + - liblz4-tool + - lrzip + - lzop + - nomarch + - pax + - rar + - rpm + - unrar-free + - unzip + - xz-utils + - zip + state: latest + +# +# ClamAV +# + +- name: ensure clamav is in amavis group + user: + name: "clamav" + append: "yes" + groups: "amavis" + +- name: ensure amavis is in clamav group + user: + name: "amavis" + append: "yes" + groups: "clamav" + +# +# policyd SPF +# + +- name: install policyd-spf config + template: + src: "{{ item }}.j2" + dest: "/etc/postfix-policyd-spf-python/{{ item }}" + notify: + - restart postfix + with_items: + - "policyd-spf.conf" + +# +# SpamAssassin +# + +- name: install SpamAssassin config + template: + src: "{{ item }}.j2" + dest: "/etc/spamassassin/{{ item }}" + notify: + - restart spamassassin + - restart amavis + with_items: + - "local.cf" + - "90_customrules.cf" + +# +# Amavis +# + +- name: install Amavis configs + template: + src: "{{ item }}.j2" + dest: "/etc/amavis/conf.d/{{ item }}" + notify: + - restart amavis + with_items: + - "15-content_filter_mode" + - "50-user" + +# +# Postfix +# + +- name: create the Postfix local config dir + file: + state: directory + dest: "/etc/postfix/local" + +- name: install the Postfix main configs + template: + src: "{{ item }}.j2" + dest: "/etc/postfix/{{ item }}" + notify: + - restart postfix + with_items: + - "main.cf" + - "master.cf" + +- name: install the Postfix local configs + template: + src: "{{ item }}.j2" + dest: "/etc/postfix/local/{{ item }}" + notify: + - restart postfix + with_items: + - helo_access + - recipient_access + - relay_domains + - transport + - virtual + +- name: link /etc/mailname to /etc/hostname + file: + dest: "/etc/mailname" + src: "/etc/hostname" + state: "link" + force: "yes" + +# +# Verify and enable services +# + +- name: verify and enable services + service: + name: "{{ item }}" + state: "started" + enabled: "yes" + with_items: + - "postfix" + - "amavis" + - "clamav-daemon" + +# +# SpamAssassin training +# + +- name: download spam sample archive + copy: + src: "spam-sample.txz" + dest: "/var/cache/spam-sample.txz" + owner: "root" + group: "root" + mode: "400" + register: spamsample + +- name: make temporary directory + command: "mktemp -d" + register: tempdirspam + when: spamsample.changed + +- name: extract spam sample archive to temporary directory + unarchive: + remote_src: "yes" + src: "/var/cache/spam-sample.txz" + dest: "{{ tempdirspam.stdout }}/" + when: spamsample.changed + +- name: sa-learn from the spam sample + command: "sa-learn --spam {{ tempdirspam.stdout }}/spam-sample/" + when: spamsample.changed + +- name: remove temporary directory + file: + dest: "{{ tempdirspam.stdout }}" + state: "absent" + when: spamsample.changed + +- name: download ham sample archive + copy: + src: "ham-sample.txz" + dest: "/var/cache/ham-sample.txz" + owner: "root" + group: "root" + mode: "400" + register: hamsample + +- name: make temporary directory + command: "mktemp -d" + register: tempdirham + when: hamsample.changed + +- name: extract ham sample archive to temporary directory + unarchive: + remote_src: "yes" + src: "/var/cache/ham-sample.txz" + dest: "{{ tempdirham.stdout }}/" + when: hamsample.changed + +- name: sa-learn from the ham sample + command: "sa-learn --ham {{ tempdirham.stdout }}/ham-sample/" + when: hamsample.changed + +- name: remove temporary directory + file: + dest: "{{ tempdirham.stdout }}" + state: "absent" + when: hamsample.changed diff --git a/package-postfix_filter/templates/15-content_filter_mode.j2 b/package-postfix_filter/templates/15-content_filter_mode.j2 new file mode 100644 index 0000000..8ea341f --- /dev/null +++ b/package-postfix_filter/templates/15-content_filter_mode.j2 @@ -0,0 +1,12 @@ +use strict; + +# Amavis filter configuration +# {{ ansible_managed }} + +@bypass_virus_checks_maps = ( + \%bypass_virus_checks, \@bypass_virus_checks_acl, \$bypass_virus_checks_re); + +@bypass_spam_checks_maps = ( + \%bypass_spam_checks, \@bypass_spam_checks_acl, \$bypass_spam_checks_re); + +1; # ensure a defined return diff --git a/package-postfix_filter/templates/50-user.j2 b/package-postfix_filter/templates/50-user.j2 new file mode 100644 index 0000000..50125ae --- /dev/null +++ b/package-postfix_filter/templates/50-user.j2 @@ -0,0 +1,40 @@ +use strict; + +@local_domains_acl = ( "." ); +$sa_tag_level_deflt = -9999; +$sa_tag2_level_deflt = 5; +$sa_kill_level_deflt = 9999; +$sa_spam_subject_tag = '*** SPAM *** '; +$final_spam_destiny = 'D_PASS'; + +$bad_header_quarantine_method = undef; + +$notify_method = '{{ notify_method }}'; + +$newvirus_admin = '{{ notify_admin }}'; +$virus_admin = '{{ notify_admin }}'; +$spam_admin = '{{ notify_admin }}'; + +$banned_admin = \@virus_admin_maps; # for compatibility with pre-2.2.1 +$bad_header_admin = \@virus_admin_maps; # for compatibility with pre-2.2.1 +@newvirus_admin_maps = (\$newvirus_admin); +@virus_admin_maps = (\%virus_admin, \$virus_admin); +@spam_admin_maps = (\%spam_admin, \$spam_admin); +@banned_admin_maps = (\$banned_admin); +@bad_header_admin_maps= (\$bad_header_admin); + +{% if custom_sender_scores is defined %} +# Custom sender_map scores +@score_sender_maps = ({ + '.' => [ + new_RE( +{% for score in custom_sender_scores %} + {{ score }}, +{% endfor %} + ), + ], +}); +{% endif %} + +#------------ Do not modify anything below this line ------------- +1; # ensure a defined return diff --git a/package-postfix_filter/templates/90_customrules.cf.j2 b/package-postfix_filter/templates/90_customrules.cf.j2 new file mode 100644 index 0000000..92bacf9 --- /dev/null +++ b/package-postfix_filter/templates/90_customrules.cf.j2 @@ -0,0 +1,7 @@ +# Adjustments to default SpamAssassin scoring +# {{ ansible_managed }} +score RCVD_IN_PSBL 3.5 # Increase default score significantly +score URIBL_BLACK 3.5 # Increase default score significantly +score LOTS_OF_MONEY 2 # Increase default score a little +score ADVANCE_FEE_4_NEW 2 # Increase default score a little +score RDNS_NONE 0.5 # Decrease default score a little diff --git a/package-postfix_filter/templates/helo_access.j2 b/package-postfix_filter/templates/helo_access.j2 new file mode 100644 index 0000000..266c7fb --- /dev/null +++ b/package-postfix_filter/templates/helo_access.j2 @@ -0,0 +1,2 @@ +/^\[[0-9]{1,3}(\.[0-9]{1,3}){3}\]$/ DUNNO announced self using an address literal +/^[0-9]{1,3}(\.[0-9]{1,3}){3}$/ REJECT announced self with an IP address instead of a domain name diff --git a/package-postfix_filter/templates/local.cf.j2 b/package-postfix_filter/templates/local.cf.j2 new file mode 100644 index 0000000..73e0a67 --- /dev/null +++ b/package-postfix_filter/templates/local.cf.j2 @@ -0,0 +1,27 @@ +# SpamAssassin local config +# {{ ansible_managed }} + +report_safe 1 +required_score 4.5 + +use_bayes 1 +bayes_auto_learn 1 +bayes_auto_learn_threshold_nonspam -0.1 +bayes_auto_learn_threshold_spam 9.0 + +score BAYES_00 -4 +score BAYES_05 -2 +score BAYES_80 2 +score BAYES_95 6 +score BAYES_99 8 + +bayes_ignore_header X-Bogosity +bayes_ignore_header X-Spam-Flag +bayes_ignore_header X-Spam-Status + +bayes_path /var/spamassassin/bayes_db/bayes +bayes_file_mode 0777 + +skip_rbl_checks 0 +ok_languages all +ok_locales all diff --git a/package-postfix_filter/templates/main.cf.j2 b/package-postfix_filter/templates/main.cf.j2 new file mode 100644 index 0000000..9b71172 --- /dev/null +++ b/package-postfix_filter/templates/main.cf.j2 @@ -0,0 +1,91 @@ +# Main Postfix configuration +# {{ ansible_managed }} + +myorigin = /etc/mailname +myhostname = {{ ansible_fqdn }} + +mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 +message_size_limit = 26214400 +mailbox_size_limit = 0 +default_process_limit = 1000 +recipient_delimiter = + +inet_interfaces = all + +smtpd_banner = {{ ansible_fqdn }} ESMTP $mail_name (Debian/GNU) +biff = no +append_dot_mydomain = no +delay_warning_time = 48h +maximal_queue_lifetime = 14d +bounce_queue_lifetime = 14d +readme_directory = no +compatibility_level = 2 + +smtpd_use_tls={{ tls_enabled }} +smtpd_tls_dh1024_param_file = /etc/ssl/dhparams.pem +smtpd_tls_cert_file={{ tls_cert }} +smtpd_tls_key_file={{ tls_key }} +smtpd_tls_ask_ccert = yes +smtpd_tls_received_header = yes +smtpd_tls_loglevel = 1 +smtpd_tls_session_cache_database = btree:$data_directory/smtpd_scache +smtpd_tls_security_level = may +smtpd_tls_protocols = !SSLv2,!SSLv3 +smtpd_tls_ciphers = medium +smtpd_tls_exclude_ciphers = RC4, CAMELLIA, SEED, 3DES + +smtp_use_tls={{ tls_enabled }} +smtp_tls_cert_file={{ tls_cert }} +smtp_tls_key_file={{ tls_key }} +smtp_tls_session_cache_database = btree:$data_directory/smtp_scache +smtp_tls_loglevel = 1 +smtp_tls_security_level = may +smtp_tls_protocols = $smtpd_tls_protocols +smtp_tls_ciphers = $smtpd_tls_ciphers +smtp_tls_exclude_ciphers = $smtpd_tls_exclude_ciphers + +mydestination = +local_recipient_maps = +alias_maps = +alias_database = +virtual_alias_maps = pcre:$config_directory/local/virtual +local_transport = error:local mail delivery is disabled +transport_maps = pcre:$config_directory/local/transport +relay_domains = $config_directory/local/relay_domains + +content_filter = smtp-amavis:[127.0.0.1]:10024 +smtpd_client_recipient_rate_limit = 250 +strict_rfc821_envelopes = yes +receive_override_options = no_address_mappings +policyd-spf_time_limit = 3600 +smtpd_relay_restrictions = + permit_mynetworks + reject_unauth_destination + check_policy_service unix:private/policyd-spf +{% for rbl in remote_block_lists %} + reject_rbl_client {{ rbl }} +{% endfor %} + warn_if_reject reject_unknown_client + +smtpd_helo_required = yes +smtpd_helo_restrictions = + check_helo_access pcre:$config_directory/local/helo_access + reject_invalid_hostname + +smtpd_sender_restrictions = + check_sender_mx_access cidr:$config_directory/local/mx_access + reject_unknown_sender_domain + reject_non_fqdn_sender + check_sender_access pcre:$config_directory/local/sender_access + +smtpd_recipient_restrictions = + reject_unknown_recipient_domain + reject_non_fqdn_recipient + reject_unauth_pipelining + reject_unauth_destination + check_policy_service unix:private/policyd-spf + check_recipient_access pcre:$config_directory/local/recipient_access + reject_unverified_recipient + +smtpd_data_restrictions = + reject_multi_recipient_bounce + reject_unauth_pipelining diff --git a/package-postfix_filter/templates/master.cf.j2 b/package-postfix_filter/templates/master.cf.j2 new file mode 100644 index 0000000..dea0256 --- /dev/null +++ b/package-postfix_filter/templates/master.cf.j2 @@ -0,0 +1,62 @@ +# Postfix master process configuration file +# {{ ansible_managed }} + +# ========================================================================== +# service type private unpriv chroot wakeup maxproc command + args +# (yes) (yes) (yes) (never) (100) +# ========================================================================== +smtp inet n - y - - smtpd +pickup unix n - y 60 1 pickup + -o content_filter= + -o receive_override_options=no_header_body_checks +cleanup unix n - y - 0 cleanup +qmgr unix n - n 300 1 qmgr +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 +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 + +policyd-spf unix - n n - 0 spawn + user=policyd-spf argv=/usr/bin/policyd-spf + +smtp-amavis unix - - y - 2 smtp + -o smtp_data_done_timeout=1200 + -o smtp_send_xforward_command=yes + -o disable_dns_lookups=yes + -o max_use=20 + +127.0.0.1:10025 inet n - y - - smtpd + -o content_filter= + -o local_recipient_maps= + -o relay_recipient_maps= + -o smtpd_restriction_classes= + -o smtpd_delay_reject=no + -o smtpd_client_restrictions=permit_mynetworks,reject + -o smtpd_helo_restrictions= + -o smtpd_sender_restrictions= + -o smtpd_recipient_restrictions=permit_mynetworks,reject + -o smtpd_data_restrictions=reject_unauth_pipelining + -o smtpd_end_of_data_restrictions= + -o mynetworks=127.0.0.0/8 + -o smtpd_error_sleep_time=0 + -o smtpd_soft_error_limit=1001 + -o smtpd_hard_error_limit=1000 + -o smtpd_client_connection_count_limit=0 + -o smtpd_client_connection_rate_limit=0 + -o receive_override_options=no_header_body_checks,no_unknown_recipient_checks diff --git a/package-postfix_filter/templates/policyd-spf.conf.j2 b/package-postfix_filter/templates/policyd-spf.conf.j2 new file mode 100644 index 0000000..cccd84a --- /dev/null +++ b/package-postfix_filter/templates/policyd-spf.conf.j2 @@ -0,0 +1,12 @@ +# policyd SPF config +# {{ ansible_managed }} + +debugLevel = 1 + +HELO_reject = False +Mail_From_reject = False + +PermError_reject = False +TempError_Defer = False + +skip_addresses = 127.0.0.0/8,::ffff:127.0.0.0/104,::1 diff --git a/package-postfix_filter/templates/recipient_access.j2 b/package-postfix_filter/templates/recipient_access.j2 new file mode 100644 index 0000000..eeee382 --- /dev/null +++ b/package-postfix_filter/templates/recipient_access.j2 @@ -0,0 +1,4 @@ +/[%!@].*[%!@]/ REJECT sender-specified routing in recipient address +/&.*@/ REJECT invalid user +/^(daemon|bin|sys|sync|games|man|lp|news|uucp|proxy|www-data|backup|list|irc|gnats|nobody)@/ REJECT reserved system user +/^(ntp|sshd|munin|postfix|clamav|sqlgrey|policyd-spf|bind|statd|freerad|mysql|smokeping|systemd-.+|)@/ REJECT reserved system user diff --git a/package-postfix_filter/templates/relay_domains.j2 b/package-postfix_filter/templates/relay_domains.j2 new file mode 100644 index 0000000..16dbac2 --- /dev/null +++ b/package-postfix_filter/templates/relay_domains.j2 @@ -0,0 +1,3 @@ +{% for domain in relay_domains %} +{{ domain.domain }} +{% endfor %} diff --git a/package-postfix_filter/templates/transport.j2 b/package-postfix_filter/templates/transport.j2 new file mode 100644 index 0000000..80a2133 --- /dev/null +++ b/package-postfix_filter/templates/transport.j2 @@ -0,0 +1,3 @@ +{% for domain in relay_domains %} +/@{{ domain.domain }}$/ relay:{{ domain.relay }} +{% endfor %} diff --git a/package-postfix_filter/templates/virtual.j2 b/package-postfix_filter/templates/virtual.j2 new file mode 100644 index 0000000..d89602a --- /dev/null +++ b/package-postfix_filter/templates/virtual.j2 @@ -0,0 +1,3 @@ +{% for map in virtual_maps %} +{{ map.regex }} {{ map.map }} +{% endfor %}