Add a Postfix role and apply it to emma

Changes #10
This commit is contained in:
genofire 2020-10-23 03:32:54 +02:00
parent 9edf07c8bb
commit 9110d9df82
20 changed files with 900 additions and 0 deletions

View file

@ -1,6 +1,11 @@
--- ---
dovecot_listen: '[2a01:4f8:150:926f::2], 176.9.59.104' dovecot_listen: '[2a01:4f8:150:926f::2], 176.9.59.104'
postfix_inet_interfaces: '[2a01:4f8:150:926f::2], 176.9.59.104'
postfix_my_networks:
- '2a01:4f8:150:926f::2'
- '176.9.59.104'
haproxy_v4: 176.9.59.104 haproxy_v4: 176.9.59.104
haproxy_v6: 2a01:4f8:150:926f::2 haproxy_v6: 2a01:4f8:150:926f::2

129
library/postconf_master Normal file
View file

@ -0,0 +1,129 @@
#!/usr/bin/python
ANSIBLE_METADATA = {
'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'
}
DOCUMENTATION = '''
---
module: postconf
short_description: Module for Postfix postconf
version_added: "2.4"
description:
- "This is module for setup Postfix variables in main.cf with postconf command"
options:
name:
description:
- Variable name.
required: true
value:
description:
- Value of the variable. Required if C(state=present).
required: false
default: null
state:
description:
- Whether to ensure that the variable is present or absent.
required: false
default: present
choices: [ "present", "absent" ]
extends_documentation_fragment:
- system
author:
- Alexander Galato (@alet)
'''
EXAMPLES = '''
# Assign value
- name: Make myhostname be equial "gateway.home"
postconf:
name: myhostname
value: gateway.home
# Remove variable from config file
- name: Remove milter_protocol
postconf:
name: milter_protocol
state: absent
'''
from ansible.module_utils.basic import AnsibleModule
def test_var(module, postconf_path, postconf_arg):
postconf_arg += " -H"
rc, out, err = module.run_command("%s %s %s" % (postconf_path, postconf_arg, module.params["name"]))
if rc != 0:
return False
return True
def query_var(module, postconf_path, postconf_arg):
postconf_arg += " -h"
rc, out, err = module.run_command("%s %s %s" % (postconf_path, postconf_arg, module.params["name"]))
if rc != 0:
return False
if out.rstrip() != module.params["value"]:
return False
return True
def set_value(module, postconf_path, postconf_arg):
if query_var(module, postconf_path, postconf_arg):
return (False, "The variable already set in value %s" % module.params["value"])
rc, out, err = module.run_command("%s %s %s=\"%s\"" % (postconf_path, postconf_arg, module.params["name"], module.params["value"]))
if rc != 0:
module.fail_json(msg="Could not set variable")
return (True, "Variable was set")
def remove_value(module, postconf_path, postconf_arg):
if test_var(module, postconf_path, postconf_arg):
postconf_arg += " -X"
rc, out, err = module.run_command("%s %s %s" % (postconf_path, postconf_arg, module.params["name"]))
if rc == 0:
return (True, "Variable was removed")
return (False, "Variable was not removed")
def main():
module_args = dict(
name=dict(type='str', required=True),
value=dict(type='str', required=False, default=''),
state=dict(type='str', required=False, default='present', choises=["present", "absent"]),
)
module = AnsibleModule(
argument_spec = module_args,
supports_check_mode = True,
)
postconf_path = module.get_bin_path('postconf', True)
p = module.params
changed = False
message = ''
postconf_arg = "-P"
if p["value"] is None and p["state"] == "present" :
module.fail_json(msg="You must specify 'value' to setup variable")
if p["state"] == "present":
changed, msg = set_value(module, postconf_path, postconf_arg)
elif p["state"] == "absent":
changed, msg = remove_value(module, postconf_path, postconf_arg)
module.exit_json(changed=changed, msg=', '.join(message))
if __name__ == '__main__':
main()

9
mail.yml Normal file
View file

@ -0,0 +1,9 @@
---
- hosts:
- mail
become: yes
roles:
- dovecot
- postfix

View file

@ -0,0 +1,18 @@
---
- name: Reload s6-rc
service:
name: s6-rc
state: reloaded
- name: Restart Postfix
command: s6-svc -t /run/service/postfix
- name: Reload Postfix
command: s6-svc -h /run/service/postfix
- name: Rebuild Postfix maps
command: 'postmap {{ item.type }}:{{ item.name }}'
args:
chdir: /usr/local/etc/postfix
when: item.type in postfix_rebuild_types
with_items: '{{ postfix_maps }}'

View file

@ -0,0 +1,145 @@
---
- name: Install Postfix
package:
name: postfix
state: present
notify:
- Restart Postfix
- name: Create /usr/local/etc/mail
file:
path: /usr/local/etc/mail
state: directory
owner: root
group: wheel
mode: 0755
- name: Install Postfix mailer.conf
copy:
dest: /usr/local/etc/mail/mailer.conf
src: /usr/local/share/postfix/mailer.conf.postfix
remote_src: yes
owner: root
group: wheel
mode: 0644
- name: Disable sendmail
sysrc:
name: sendmail_enable
value: NONE
- name: Make sure sendmail is stopped
service:
name: sendmail
state: stopped
- name: Disable sendmail periodic tasks
lineinfile:
path: /etc/periodic.conf
owner: root
group: wheel
mode: 0444
regexp: '^{{ item }}='
line: '{{ item }}="NO"'
with_items: '{{ sendmail_periodic }}'
- name: Add /var/log/postfix to fstab
mount:
path: /var/log/postfix
src: tmpfs
fstype: tmpfs
opts: 'rw,size={{ postfix_log_size }},mode={{ postfix_log_mode }},uid={{ postfix_log_uid }},gid={{ postfix_log_gid }},late'
state: mounted
- name: Create Postfix service directories
file:
path: '/etc/s6-rc/service/{{ item }}'
state: directory
owner: root
group: wheel
mode: 0755
with_items: '{{ postfix_service_dirs }}'
- name: Generate Postfix service scripts
template:
dest: '/etc/s6-rc/service/{{ item }}'
src: '{{ item }}.j2'
mode: 0555
owner: root
group: wheel
with_items: '{{ postfix_service_scripts }}'
notify:
- Reload s6-rc
- Restart Postfix
- name: Generate Postfix service configuration
copy:
dest: '/etc/s6-rc/service/{{ item.name }}'
content: '{{ item.content }}'
mode: 0444
owner: root
group: wheel
loop_control:
label: '{{ item.name }} = {{ item.content }}'
notify:
- Reload s6-rc
- Restart Postfix
with_items: '{{ postfix_service_config }}'
- name: Generate Postfix maps
template:
dest: '/usr/local/etc/postfix/{{ item.name }}'
src: '{{ item.name }}.j2'
mode: 0444
owner: root
group: wheel
with_items: '{{ postfix_maps }}'
notify:
- Rebuild Postfix maps
- Reload Postfix
- name: Configure Postfix
postconf:
name: '{{ item.name }}'
value: '{{ item.value | default(omit) }}'
state: '{{ item.state | default(omit) }}'
with_items: '{{ postfix_config }}'
notify:
- Reload Postfix
- name: Configure Postfix services
lineinfile:
path: /usr/local/etc/postfix/master.cf
regexp: '^{{ item.name }} +{{ item.type }}'
value: '{{ item.value }}'
with_items: '{{ postfix_services }}'
notify:
- Restart Postfix
- name: Configure per service overrides
postconf_master:
name: '{{ item.name }}'
value: '{{ item.value | default(omit) }}'
state: '{{ item.state | default(omit) }}'
with_items: '{{ postfix_params }}'
notify:
- Restart Postfix
- name: Flush handlers
meta: flush_handlers
- name: Start Postfix
command: fdmove -c 2 1 s6-rc -u -v 2 change postfix
register: change
changed_when: change.stdout | length > 0
- name: Enable Postfix
lineinfile:
path: /etc/s6-rc/service/enabled/contents
regexp: "^postfix$"
line: "postfix"
notify:
- Reload s6-rc
- name: Flush handlers (again)
meta: flush_handlers

View file

@ -0,0 +1,4 @@
# {{ ansible_managed }}
/^Received:(.*)hispeedmailer\.com/ REJECT Mass-mailer. Bye bye spammer...
/^Subject:.*=\?(big5|euc-kr|gb2312|ks_c_5601-1987)\?/ REJECT No foreign character sets, please.
/^Subject:(.*)v[i1][a@4]+g*r[a@4]+/ REJECT No pills needed, thank you.

View file

@ -0,0 +1,4 @@
# {{ ansible_managed }}
{% for line in postfix_helo_checks | default([]) %}
{{ line }}
{% endfor %}

View file

@ -0,0 +1,5 @@
{% for domain, users in dovecot_users.items() %}
{% for name, password in users.items() %}
{{ name }}@{{ domain }} OK
{% endfor %}
{% endfor %}

View file

@ -0,0 +1,4 @@
# {{ ansible_managed }}
{% for addr in postfix_my_networks %}
{{ addr }} OK
{% endfor %}

View file

@ -0,0 +1,13 @@
#!/usr/local/bin/execlineb -S2
# {{ ansible_managed }}
s6-envdir ./env
multisubstitute {
importas -i -u NAME NAME
}
fdmove -c 1 2
ifelse { test "${1}" -eq 0 } {
echo "${NAME}: Stopped."
}
echo "${NAME}: Failed with exit status (${1}, ${2})."

View file

@ -0,0 +1,25 @@
#!/usr/local/bin/execlineb -P
# {{ ansible_managed }}
s6-envdir ./env
multisubstitute {
importas -i -u NAME NAME
importas -i -u USER USER
importas -i -u GROUP GROUP
importas -i -u MODE MODE
importas -i -u DIR DIR
}
foreground { fdmove -c 1 2 echo "${NAME} log: Starting." }
ifelse -n { install -d -o "${USER}" -g "${GROUP}" -m "${MODE}" -- "${DIR}" } {
foreground { fdmove -c 1 2 echo "${NAME} log: Failed to create logging directory." }
false
}
foreground { if -n { test -p "${DIR}/fifo" } mkfifo -m 0600 -- "${DIR}/fifo" }
fdmove -c 2 1
redirfd -u 0 "${DIR}/fifo"
s6-envuidgid $USER
s6-log -d 3 T $DIR

View file

@ -0,0 +1,18 @@
#!/usr/local/bin/execlineb -P
# {{ ansible_managed }}
s6-envdir ./env
multisubstitute {
importas -i -u NAME NAME
}
ifelse {
redirfd -w 1 /dev/null
fdmove -c 2 1
postfix status
} {
foreground { fdmove -c 1 2 echo "${NAME}: Ready." }
true
}
foreground { fdmove -c 1 2 echo "${NAME}: Poll." }
false

View file

@ -0,0 +1,13 @@
#!/usr/local/bin/execlineb -S2
# {{ ansible_managed }}
s6-envdir ./env
multisubstitute {
importas -i -u NAME NAME
}
fdmove -c 1 2
ifelse { test "${1}" -eq 0 } {
echo "${NAME}: Stopped."
}
echo "${NAME}: Failed with exit status (${1}, ${2})."

View file

@ -0,0 +1,14 @@
#!/usr/local/bin/execlineb -P
# {{ ansible_managed }}
s6-envdir ./env
multisubstitute {
importas -i -u NAME NAME
}
foreground { fdmove -c 1 2 echo "${NAME}: Starting." }
s6-notifyoncheck -d -w 100 -n 70
redirfd -u 1 /var/log/postfix/fifo
fdmove -c 2 1
/usr/local/libexec/postfix/master -s

View file

@ -0,0 +1,11 @@
# {{ ansible_managed }}
# We will be rejecting much mail which is listed in multiple DNSBLs.
# We're not proud of some of the lists we are using, thus have given
# them lower scores in postscreen_dnsbl_sites listing. So this checks
# the DNSBL name postscreen(8) gets from dnsblog(8), and if it's not
# one of our Tier 1 DNSBL sites, it changes what the sender will see:
#/^b\.barracudacentral\.org$/ b.barracudacentral.org
#/^bl\.spameatingmonkey\.net$/ bl.spameatingmonkey.net
!/^zen\.spamhaus\.org$/ multiple DNS-based blocklists

View file

@ -0,0 +1,5 @@
# {{ ansible_managed }}
{% for line in postfix_rbl_override | default([]) %}
{{ line }}
{% endfor %}

View file

@ -0,0 +1,5 @@
# {{ ansible_managed }}
{% for line in postfix_sender_access | default([]) %}
{{ line }}
{% endfor %}

View file

@ -0,0 +1,5 @@
# {{ ansible_managed }}
{% for line in postfix_virtual_aliases | default([]) %}
{{ line }}
{% endfor %}

467
roles/postfix/vars/main.yml Normal file
View file

@ -0,0 +1,467 @@
---
sendmail_periodic:
- daily_clean_hoststat_enable
- daily_status_mail_rejects_enable
- daily_status_include_submit_mailq
- daily_submit_queuerun
postfix_log_size: '32m'
postfix_log_mode: '750'
postfix_log_uid: '20000'
postfix_log_gid: '20000'
postfix_rebuild_types:
- hash
- btree
postfix_maps:
- name: header_checks
type: regexp
- name: helo_checks
type: hash
- name: local_recipients
type: hash
- name: mynetworks
type: hash
- name: postscreen_dnsbl_reply_map
type: pcre
- name: rbl_override
type: hash
- name: virtual_aliases
type: hash
postfix_helo_checks:
- localhost REJECT You're not me
postfix_rbl_override: []
postfix_sender_access:
- hostepro.co.ua REJECT Die you fucking spammer!
- molingrush.co.ua REJECT Die you fucking spammer!
- jenreviews.com REJECT Die you fucking spammer!
- hes.net REJECT Die you fucking spammer!
- willsamaren.co.ua REJECT Die you fucking spammer!
- liluinc.eu REJECT Die you fucking spamemr!
- winsoker.co.ua REJECT Die you fucking spammer!
- mellingrush.eu REJECT Die you fucking spammer!
- newdgise.co.ua REJECT Die you fucking spammer!
- nicemaner.eu REJECT Die you fucking spammer!
- qr-hosting.eu REJECT Die you fucking spammer!
- villpubrel.com REJECT Die you fucking spammer!
- willi-bong.eu REJECT Die you fucking spammer!
- pgp.co.in REJECT Die you fucking spammer!
- rapnews.biz.ua REJECT Die you fucking spammer!
postfix_virtual_aliases:
- root@ccchb.de crest@ccchb.de
- abuse@ccchb.de crest@ccchb.de
- noc@ccchb.de crest@ccchb.de
- security@ccchb.de crest@ccchb.de
- postmaster@ccchb.de crest@ccchb.de
- hostmaster@ccchb.de crest@ccchb.de
- root@lists.ccchb.de crest@ccchb.de
- crest@lists.ccchb.de crest@ccchb.de
- abuse@lists.ccchb.de crest@ccchb.de
- noc@lists.ccchb.de crest@ccchb.de
- security@lists.ccchb.de crest@ccchb.de
- postmaster@lists.ccchb.de crest@ccchb.de
- hostmaster@lists.ccchb.de crest@ccchb.de
postfix_service_dirs:
- postfix
- postfix/env
- postfix/data
- postfix-log
- postfix-log/env
postfix_service_scripts:
- postfix/run
- postfix/finish
- postfix/data/check
- postfix-log/run
- postfix-log/finish
postfix_service_config:
- name: postfix/type
content: longrun
- name: postfix/dependencies
content: postfix-log
- name: postfix/notification-fd
content: 3
- name: postfix/env/NAME
content: postfix
- name: postfix/env/PATH
content: /sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/root/bin
- name: postfix-log/type
content: longrun
- name: postfix-log/notification-fd
content: 3
- name: postfix-log/env/NAME
content: postfix
- name: postfix-log/env/PATH
content: /sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/root/bin
- name: postfix-log/env/MODE
content: '750'
- name: postfix-log/env/USER
content: s6-log
- name: postfix-log/env/GROUP
content: s6-log
- name: postfix-log/env/DIR
content: /var/log/postfix
postfix_config:
- name: compatibility_level
value: '2'
state: present
- name: header_checks
value: 'regexp:$config_directory/header_checks'
state: present
- name: inet_interfaces
value: '{{ postfix_inet_interfaces }}'
state: present
- name: inet_protocols
value: 'ipv6, ipv4'
state: present
- name: local_recipient_maps
value: 'hash:$config_directory/local_recipients $alias_maps'
state: present
- name: maillog_file
value: '/var/log/postfix/fifo'
state: present
- name: mailbox_transport
value: 'lmtp:unix:$queue_directory/private/dovecot-lmtp'
state: present
- name: milter_default_action
value: 'accept'
state: present
- name: milter_mail_macros
value: 'i {mail_addr} {client_addr} {client_name} {auth_authen}'
state: present
- name: mua_client_restrictions
value: 'permit_sasl_authenticated, reject'
state: present
- name: mua_helo_restrictions
value: 'permit_sasl_authenticated, reject'
state: present
- name: mua_sender_restrictions
value: 'permit_sasl_authenticated, reject'
state: present
- name: mydestination
value: '$myhostname, localhost.$mydomain, localhost, $mydomain'
state: present
- name: mynetworks
value: 'cidr:$config_directory/mynetworks'
state: present
- name: myorigin
value: '$mydomain'
state: present
- name: postscreen_bare_newline_action
value: 'enforce'
state: present
- name: postscreen_bare_newline_enable
value: 'yes'
state: present
- name: postscreen_blacklist_action
value: 'drop'
state: present
- name: postscreen_cache_map
value: 'hash:$data_directory/postscreen_cache'
state: present
- name: postscreen_dnsbl_action
value: 'enforce'
state: present
- name: postscreen_dnsbl_reply_map
value: 'pcre:$config_directory/postscreen_dnsbl_reply_map'
state: present
- name: postscreen_dnsbl_sites
value: >-
zen.spamhaus.org*3
b.barracudacentral.org*2
bl.spameatingmonkey.net*2
bl.spamcop.net
dnsbl.sorbs.net
psbl.surriel.com
bl.mailspike.net
swl.spamhaus.org*-4
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
state: present
- name: postscreen_dnsbl_threshold
value: '3'
state: present
- name: postscreen_dnsbl_whitelist_threshold
value: '-1'
state: present
- name: postscreen_greet_action
value: 'enforce'
state: present
- name: postscreen_non_smtp_command_enable
value: 'yes'
state: present
- name: postscreen_pipelining_enable
value: 'yes'
state: present
- name: recipient_delimiter
value: '+'
state: present
- name: smtp_tls_exclude_ciphers
value: 'aNULL'
state: present
- name: smtp_tls_loglevel
value: '1'
state: present
- name: smtp_tls_note_starttls_offer
value: 'yes'
state: present
- name: smtp_tls_security_level
value: 'may'
state: present
- name: smtp_tls_session_cache_database
value: 'btree:${data_directory}/smtp_scache'
state: present
- name: smtpd_banner
value: '$myhostname ESMTP 8BIT-OK NO UCE NO UBE $mail_name'
state: present
- name: smtpd_client_restrictions
value: >-
permit_sasl_authenticated,
permit_mynetworks,
reject_unknown_client,
check_client_access
hash:$config_directory/rbl_override,
reject_rbl_client cbl.abuseat.org,
reject_rbl_client sbl.spamhaus.org,
reject_rbl_client pbl.spamhaus.org,
reject_rbl_client ix.dnsbl.manitu.net
state: present
- name: smtpd_helo_required
value: 'yes'
state: present
- name: smtpd_helo_restrictions
value: >-
permit_sasl_authenticated,
permit_mynetworks,
reject_invalid_hostname,
reject_non_fqdn_hostname,
check_helo_access hash:$config_directory/helo_checks,
reject_unknown_hostname
state: present
- name: smtpd_milters
value: 'unix:/var/run/rspamd/proxy.sock'
state: present
- name: smtpd_recipient_restrictions
value: >-
permit_sasl_authenticated,
permit_mynetworks,
reject_non_fqdn_recipient,
reject_unknown_recipient_domain,
reject_unauth_destination
state: present
- name: smtpd_sasl_auth_enable
value: 'yes'
state: present
- name: smtpd_sasl_path
value: 'private/dovecot-auth'
state: present
- name: smtpd_sender_restrictions
value: >-
permit_sasl_authenticated,
permit_mynetworks,
reject_non_fqdn_sender,
reject_unknown_sender_domain,
check_sender_access hash:$config_directory/sender_access
state: present
- name: smtpd_tls_auth_only
value: 'yes'
state: present
- name: smtpd_tls_cert_file
value: '/usr/local/etc/dovecot/fullchain.pem'
state: present
- name: smtpd_tls_eecdh_grade
value: 'ultra'
state: present
- name: smtpd_tls_exclude_ciphers
value: 'aNULL'
state: present
- name: smtpd_tls_key_file
value: '/usr/local/etc/dovecot/privkey.pem'
state: present
- name: smtpd_tls_loglevel
value: '1'
state: present
- name: smtpd_tls_mandatory_ciphers
value: 'high'
state: present
- name: smtpd_tls_mandatory_exclude_ciphers
value: 'aNULL'
state: present
- name: smtpd_tls_received_header
value: 'yes'
state: present
- name: smtpd_tls_security_level
value: 'may'
state: present
- name: smtpd_tls_session_cache_database
value: 'btree:${data_directory}/smtpd_scache'
state: present
- name: strict_rfc821_envelopes
value: 'yes'
state: present
- name: tls_high_cipherlist
value: 'EDH+CAMELLIA:EDH+aRSA:EECDH+aRSA+AESGCM:EECDH+aRSA+SHA256:EECDH:+CAMELLIA128:+AES128:+SSLv3:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!DSS:!RC4:!SEED:!IDEA:!ECDSA:kEDH:CAMELLIA128-SHA:AES128-SHA'
state: present
- name: tls_ssl_options
value: 'NO_COMPRESSION'
state: present
- name: unknown_address_reject_code
value: '554'
state: present
- name: unknown_client_reject_code
value: '554'
state: present
- name: unknown_hostname_reject_code
value: '554'
state: present
- name: virtual_alias_maps
value: 'hash:/usr/local/etc/postfix/virtual_aliases'
state: present
- name: virtual_mailbox_domains
value: 'lists.ccchb.de'
state: present
- name: virtual_transport
value: 'lmtp:unix:$queue_directory/private/dovecot-lmtp'
state: present
postfix_services:
- name: smtp
type: inet
value: "smtp inet n - n - 1 postscreen"
- name: smtpd
type: pass
value: "smtpd pass - - n - - smtpd"
- name: submission
type: inet
value: "submission inet n - n - - smtpd"
- name: dnsblog
type: unix
value: "dnsblog unix - - n - 0 dnsblog"
- name: tlsproxy
type: unix
value: "tlsproxy unix - - n - 0 tlsproxy"
postfix_params:
- name: submission/inet/syslog_name
value: 'postfix/submission'
state: present
- name: submission/inet/smtpd_tls_security_level
value: 'encrypt'
state: present
- name: submission/inet/tls_preempt_cipherlist
value: 'yes'
state: present
- name: submission/inet/smtpd_sasl_auth_enable
value: 'yes'
state: present
- name: submission/inet/smtpd_tls_auth_only
value: 'yes'
state: present
- name: submission/inet/smtpd_reject_unlisted_recipient
value: 'no'
state: present
- name: submission/inet/smtpd_client_restrictions
value: '$mua_client_restrictions'
state: present
- name: submission/inet/smtpd_helo_restrictions
value: '$mua_helo_restrictions'
state: present
- name: submission/inet/smtpd_sender_restrictions
value: '$mua_sender_restrictions'
state: present
- name: submission/inet/smtpd_recipient_restrictions
value: ''
state: present
- name: submission/inet/smtpd_relay_restrictions
value: 'permit_sasl_authenticated,reject'
state: present
- name: submission/inet/milter_macro_daemon_name
value: ORIGINATING
state: present

View file

@ -2,3 +2,4 @@
- import_playbook: s6.yml - import_playbook: s6.yml
- import_playbook: haproxy.yml - import_playbook: haproxy.yml
- import_playbook: bhyve.yml - import_playbook: bhyve.yml
- import_playbook: mail.yml