summaryrefslogtreecommitdiffstats
path: root/roles
diff options
context:
space:
mode:
authorGuilhem Moulin <guilhem@fripost.org>2015-06-04 20:26:53 +0200
committerGuilhem Moulin <guilhem@fripost.org>2015-06-07 02:54:26 +0200
commit2c925ea17fcb6f71826e5c0f30f99c5daba10e14 (patch)
tree90f0cbed686e3f5704b4440ab6239046412d91d6 /roles
parentf3d93ac759ee2ac08ecc7308d3019796e2285797 (diff)
Make the webmail connect directly to the outgoing SMTP proxy.
(Hence delete the 'webmail' Postfix instance.) This shortens the delay caused by the recipient verification probes.
Diffstat (limited to 'roles')
-rw-r--r--roles/common/files/etc/logcheck/ignore.d.server/postfix-local6
-rw-r--r--roles/common/files/etc/postfix/master.cf1
-rw-r--r--roles/webmail/handlers/main.yml4
-rw-r--r--roles/webmail/tasks/mail.yml42
-rw-r--r--roles/webmail/tasks/main.yml1
-rw-r--r--roles/webmail/tasks/roundcube.yml2
-rw-r--r--roles/webmail/templates/etc/postfix/main.cf.j2107
-rw-r--r--roles/webmail/templates/etc/stunnel/postfix.conf.j255
8 files changed, 95 insertions, 123 deletions
diff --git a/roles/common/files/etc/logcheck/ignore.d.server/postfix-local b/roles/common/files/etc/logcheck/ignore.d.server/postfix-local
index fd6cbcb..45327b1 100644
--- a/roles/common/files/etc/logcheck/ignore.d.server/postfix-local
+++ b/roles/common/files/etc/logcheck/ignore.d.server/postfix-local
@@ -31,9 +31,9 @@
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/smtpd\[[[:digit:]]+\]: warning: Connection concurrency limit exceeded: [0-9]+ from [._[:alnum:]-]+\[[[:digit:].]{7,15}\] for service smtpd$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-(msa|mx)/smtpd\[[[:digit:]]+\]: timeout after [-[:upper:]]+( \([[:digit:]]+ bytes\))? from [^[:space:]]+$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-((msa|mx)/smtpd|out/smtp)\[[[:digit:]]+\]: warning: (tls_text_name: [-._[:alnum:]]+\[[[:xdigit:].:]{3,39}\]: )?peer certificate has no (subject CN|issuer Organization)$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-(msa|webmail)/smtpd\[[[:digit:]]+\]: (NOQUEUE|[[:xdigit:]]+): reject: [[:upper:]]+ from [^[:space:]]+: 450( 4\.1\.2)? <[^>]*>: Recipient address rejected: Domain not found;( from=<[^>]*> to=<[^[:space:]]+>)? proto=E?SMTP( helo=<[^[:space:]]+>)?$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-(msa|webmail)/smtpd\[[[:digit:]]+\]: (NOQUEUE|[[:xdigit:]]+): reject: [[:upper:]]+ from [^[:space:]]+: 450( 4\.1\.8)? <[^>]*>: Sender address rejected: Domain not found;( from=<[^>]*> to=<[^[:space:]]+>)? proto=E?SMTP( helo=<[^[:space:]]+>)?$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-(msa|webmail)/smtpd\[[[:digit:]]+\]: (NOQUEUE|[[:xdigit:]]+): reject: [[:upper:]]+ from [^[:space:]]+: 504( 5\.5\.2)? <[^>]*>: (Recipient|Sender) address rejected: need fully-qualified address;( from=<[^>]*> to=<[^[:space:]]+>)? proto=E?SMTP( helo=<[^[:space:]]+>)?$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-msa/smtpd\[[[:digit:]]+\]: (NOQUEUE|[[:xdigit:]]+): reject: [[:upper:]]+ from [^[:space:]]+: 450( 4\.1\.2)? <[^>]*>: Recipient address rejected: Domain not found;( from=<[^>]*> to=<[^[:space:]]+>)? proto=E?SMTP( helo=<[^[:space:]]+>)?$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-msa/smtpd\[[[:digit:]]+\]: (NOQUEUE|[[:xdigit:]]+): reject: [[:upper:]]+ from [^[:space:]]+: 450( 4\.1\.8)? <[^>]*>: Sender address rejected: Domain not found;( from=<[^>]*> to=<[^[:space:]]+>)? proto=E?SMTP( helo=<[^[:space:]]+>)?$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-msa/smtpd\[[[:digit:]]+\]: (NOQUEUE|[[:xdigit:]]+): reject: [[:upper:]]+ from [^[:space:]]+: 504( 5\.5\.2)? <[^>]*>: (Recipient|Sender) address rejected: need fully-qualified address;( from=<[^>]*> to=<[^[:space:]]+>)? proto=E?SMTP( helo=<[^[:space:]]+>)?$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-msa/smtpd\[[[:digit:]]+\]: NOQUEUE: reject: RCPT from [._[:alnum:]-]+\[[[:xdigit:].:]{3,39}\]: 554 5\.7\.1 <[._[:alnum:]-]+\[[[:xdigit:].:]{3,39}\]>: Client host rejected: Access denied;( from=<[^>]*> to=<[^[:space:]]+>)? proto=E?SMTP( helo=<[^[:space:]]+>)?$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mda/lmtp\[[[:digit:]]+\]: [[:xdigit:]]{10}: to=<[^[:space:]]+>,( orig_to=<[^[:space:]]+>,)? relay=[._[:alnum:]-]+\[private/dovecot-lmtpd\],( conn_use=[[:digit:]]+,)? delay=[.[:digit:]]+(, delays=([.[:digit:]]+/){3}[.[:digit:]]+)?(, dsn=2(\.[[:digit:]]+){2})?, status=sent \(2[[:digit:]][[:digit:]] .+\)$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-\w+/(error|n?qmgr|smtp)\[[[:digit:]]+\]: [[:alnum:]]+: to=<[^[:space:]]+>,( orig_to=<[^[:space:]]+>,)? relay=(none|[^[:space:]]+\[[[:digit:].]{7,15}\]:[[:digit:]]+),( conn_use=[[:digit:]]+,)? delay=[[:digit:].]+,( delays=[[:digit:]./]+,)?( dsn=[45]\.[[:digit:]]\.[[:digit:]],)? status=(deferred|undeliverable) \((delivery temporarily suspended: )?((lost connection with [^[:space:]]+|conversation with [^[:space:]]+ timed out) while (sending [[:alnum:]]+( [[:alnum:]]+)?|performing the (HELO|EHLO) handshake|receiving the initial server greeting|sending [[:alnum:]]+( [/[:alnum:]]+)?|sending end of data -- message may be sent more than once)|connect to [^[:space:]]+: (Connection timed out|read timeout|Connection refused)|host [^[:space:]]+ refused to talk to me: [45][[:digit:]][[:digit:]].*|Host or domain name not found. Name service errorfor name=[^[:space:]]+ type=MX: Host not found, try again|User unknown in virtual alias table|host [^[:space:]]+\[[[:digit:].]{7,15}\] said: [45][[:digit:]][[:digit:]] [45](\.[[:digit:]]+){2} <[^>]+>: (Temporarily rejected\. Try again later\.|Recipient address rejected: (undeliverable|unverified) address:) .*)\)$
diff --git a/roles/common/files/etc/postfix/master.cf b/roles/common/files/etc/postfix/master.cf
index 36c016b..9b81c70 100644
--- a/roles/common/files/etc/postfix/master.cf
+++ b/roles/common/files/etc/postfix/master.cf
@@ -45,7 +45,6 @@ scache unix - - - - 1 scache
2525 inet n - - - - smtpd
2526 inet n - - - - smtpd
2527 inet n - - - - smtpd
-127.0.0.1:2580 inet n - - - - smtpd
reserved-alias unix - n n - - pipe
flags=Rhu user=nobody argv=/usr/local/bin/reserved-alias.pl ${sender} ${original_recipient} @fripost.org
sympa unix - n n - - pipe
diff --git a/roles/webmail/handlers/main.yml b/roles/webmail/handlers/main.yml
index 76084e4..f7e403e 100644
--- a/roles/webmail/handlers/main.yml
+++ b/roles/webmail/handlers/main.yml
@@ -1,6 +1,6 @@
---
-- name: Reload Postfix
- service: name=postfix state=reloaded
+- name: Restart stunnel
+ service: name=stunnel4 pattern=/usr/bin/stunnel4 state=restarted
- name: Restart Nginx
service: name=nginx state=restarted
diff --git a/roles/webmail/tasks/mail.yml b/roles/webmail/tasks/mail.yml
index e2dea38..7603a56 100644
--- a/roles/webmail/tasks/mail.yml
+++ b/roles/webmail/tasks/mail.yml
@@ -1,15 +1,39 @@
-- name: Install Postfix
- apt: pkg=postfix
+- name: Install stunnel
+ apt: pkg=stunnel4
-- name: Configure Postfix
- template: src=etc/postfix/main.cf.j2
- dest=/etc/postfix-{{ postfix_instance[inst].name }}/main.cf
+- name: Auto-enable stunnel
+ lineinfile: dest=/etc/default/stunnel4
+ regexp='^(\s*#)?\s*ENABLED='
+ line='ENABLED=1'
+ owner=root group=root
+ mode=0644
+
+- name: Create /etc/stunnel/certs
+ file: path=/etc/stunnel/certs
+ state=directory
+ owner=root group=root
+ mode=0755
+
+- name: Copy the SMTP outgoing proxy's X.509 certificate
+ assemble: src=certs/postfix regexp="{{ groups.out | difference([inventory_hostname]) | join('|') }}\.pem$" remote_src=no
+ dest=/etc/stunnel/certs/postfix.pem
owner=root group=root
mode=0644
+ register: r1
notify:
- - Reload Postfix
+ - Restart stunnel
-- meta: flush_handlers
+- name: Configure stunnel
+ template: src=etc/stunnel/postfix.conf.j2
+ dest=/etc/stunnel/postfix.conf
+ owner=root group=root
+ mode=0644
+ register: r2
+ notify:
+ - Restart stunnel
-- name: Start Postfix
- service: name=postfix state=started
+- name: Start stunnel
+ service: name=stunnel4 pattern=/usr/bin/stunnel4 state=started
+ when: not (r1.changed or r2.changed)
+
+- meta: flush_handlers
diff --git a/roles/webmail/tasks/main.yml b/roles/webmail/tasks/main.yml
index a6eeee2..030a547 100644
--- a/roles/webmail/tasks/main.yml
+++ b/roles/webmail/tasks/main.yml
@@ -1,2 +1,3 @@
- include: mail.yml tags=postfix,mail
+ when: "'out' not in group_names"
- include: roundcube.yml tags=roundcube,webmail
diff --git a/roles/webmail/tasks/roundcube.yml b/roles/webmail/tasks/roundcube.yml
index ebe93c8..5392242 100644
--- a/roles/webmail/tasks/roundcube.yml
+++ b/roles/webmail/tasks/roundcube.yml
@@ -36,7 +36,7 @@
- { var: messages_cache, value: "null" }
# SMTP
- { var: smtp_server, value: "'localhost'" }
- - { var: smtp_port, value: "2580" }
+ - { var: smtp_port, value: "2525" }
# System
- { var: force_https, value: "TRUE" }
- { var: login_autocomplete, value: "2" }
diff --git a/roles/webmail/templates/etc/postfix/main.cf.j2 b/roles/webmail/templates/etc/postfix/main.cf.j2
deleted file mode 100644
index f4079d6..0000000
--- a/roles/webmail/templates/etc/postfix/main.cf.j2
+++ /dev/null
@@ -1,107 +0,0 @@
-########################################################################
-# Webmail 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
-
-delay_warning_time = 4h
-maximal_queue_lifetime = 5d
-
-myorigin = /etc/mailname
-myhostname = webmail{{ webmailno | default('') }}.$mydomain
-mydomain = fripost.org
-append_dot_mydomain = no
-
-# Turn off all TCP/IP listener ports except that necessary for the webmail.
-master_service_disable = !127.0.0.1:2580.inet inet
-
-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 nullclient
-mynetworks_style = host
-inet_interfaces = loopback-only
-
-# 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 %}
-relay_domains =
-
-
-# Don't rewrite remote headers
-local_header_rewrite_clients =
-# Avoid splitting the envelope and scanning messages multiple times
-smtp_destination_recipient_limit = 1000
-# Tolerate occasional high latency
-smtp_data_done_timeout = 1200s
-
-{% 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 = none
-
-
-strict_rfc821_envelopes = yes
-smtpd_delay_reject = yes
-disable_vrfy_command = yes
-
-# UCE control
-unknown_client_reject_code = 554
-unverified_recipient_reject_code = 550
-
-smtpd_client_restrictions =
- permit_mynetworks
- reject
-
-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 =
- permit_mynetworks
- reject
-
-smtpd_recipient_restrictions =
- reject_non_fqdn_recipient
- reject_unknown_recipient_domain
- reject_unverified_recipient
-
-smtpd_data_restrictions =
- reject_unauth_pipelining
-
-# vim: set filetype=pfmain :
diff --git a/roles/webmail/templates/etc/stunnel/postfix.conf.j2 b/roles/webmail/templates/etc/stunnel/postfix.conf.j2
new file mode 100644
index 0000000..78922c8
--- /dev/null
+++ b/roles/webmail/templates/etc/stunnel/postfix.conf.j2
@@ -0,0 +1,55 @@
+; **************************************************************************
+; * Global options *
+; **************************************************************************
+
+; setuid()/setgid() to the specified user/group in daemon mode
+setuid = stunnel4
+setgid = stunnel4
+
+; PID is created inside the chroot jail
+pid = /var/run/stunnel4/postfix.pid
+
+; Only log messages at severity warning (4) and higher
+debug = 4
+
+; **************************************************************************
+; * Service defaults may also be specified in individual service sections *
+; **************************************************************************
+
+; Certificate/key is needed in server mode and optional in client mode
+cert = /etc/postfix/ssl/{{ ansible_fqdn }}.pem
+key = /etc/postfix/ssl/{{ ansible_fqdn }}.key
+client = yes
+socket = a:SO_BINDTODEVICE=lo
+
+; Some performance tunings
+socket = l:TCP_NODELAY=1
+socket = r:TCP_NODELAY=1
+
+; Prevent MITM attacks
+verify = 4
+
+; Disable support for insecure protocols
+options = NO_SSLv2
+options = NO_SSLv3
+options = NO_TLSv1
+options = NO_TLSv1.1
+
+; These options provide additional security at some performance degradation
+options = SINGLE_ECDH_USE
+options = SINGLE_DH_USE
+
+; Select permitted SSL ciphers
+ciphers = EECDH+AES:EDH+AES:!MEDIUM:!LOW:!EXP:!aNULL:!eNULL:!SSLv2:!SSLv3:!TLSv1:!TLSv1.1
+
+; **************************************************************************
+; * Service definitions (remove all services for inetd mode) *
+; **************************************************************************
+
+[smtp]
+accept = localhost:2525
+connect = outgoing.fripost.org:{{ postfix_instance.out.port }}
+CAfile = /etc/stunnel/certs/postfix.pem
+protocol = smtp
+
+; vim:ft=dosini