diff --git a/dovecot/defaults/main.yml b/dovecot/defaults/main.yml new file mode 100644 index 0000000000000000000000000000000000000000..2e094cc55266fee2bf1a0ab72fe2a7245e54ef98 --- /dev/null +++ b/dovecot/defaults/main.yml @@ -0,0 +1,31 @@ +--- + +dovecot_admin_mail: "postmaster@{{ domain }}" +dovecot_protocols: imap lmtp sieve +dovecot_mail_location: "maildir:~/mail:LAYOUT=fs" +dovecot_maildir_separator: / +dovecot_deny_users: [] +dovecot_users_group: users +dovecot_auth_virtual: no +dovecot_auth_system: yes +dovecot_min_uid: 500 +dovecot_max_uid: 0 + +dovecot_tls_cert: /etc/ssl/private/fullchain.pem +dovecot_tls_key: /etc/ssl/private/privkey.pem +dovecot_tls_ca_dir: /etc/ssl/certs +dovecot_tls_ciphers: "{{ tls_ciphers }}" +dovecot_tls_dh_length: 4096 +dovecot_tls_protocols: TLSv1.1 TLSv1.2 !SSLv3 + +dovecot_dsync: yes +dovecot_dsync_tls: no +dovecot_dsync_group: dovecot +dovecot_dsync_address: '0.0.0.0' +dovecot_dsync_password: "{{ lookup('passwordstore', dovecot_dsync_passwordstore ~ ' create=true length=20') }}" +dovecot_dsync_passwordstore: selfhosted/dsync +dovecot_dsync_host_attribute: ansible_host + +dovecot_content_filter: yes +dovecot_spam_folder: Spam + diff --git a/dovecot/files/filter_junk.sieve b/dovecot/files/filter_junk.sieve deleted file mode 100644 index bf4276e09a7df0013a744017c276b390f33fd04e..0000000000000000000000000000000000000000 --- a/dovecot/files/filter_junk.sieve +++ /dev/null @@ -1,10 +0,0 @@ -require ["fileinto", "mailbox"]; - -if header :contains "X-Spam-Flag" "YES" { - fileinto :create "Junk"; -} - -if header :contains "Subject" "*SPAM*" { - fileinto :create "Junk"; -} - diff --git a/dovecot/files/sa-learn-ham.sh b/dovecot/files/sa-learn-ham.sh new file mode 100644 index 0000000000000000000000000000000000000000..d18e5539c0b6638538012f3641e90594b3471ef6 --- /dev/null +++ b/dovecot/files/sa-learn-ham.sh @@ -0,0 +1,3 @@ +#!/bin/sh +# you can also use tcp/ip here, consult spamc(1) +exec /usr/bin/spamc -u ${1} -L ham -C report diff --git a/dovecot/files/sa-learn-spam.sh b/dovecot/files/sa-learn-spam.sh new file mode 100644 index 0000000000000000000000000000000000000000..69b3608336d6641b9459f25b8c5bdee09c4cc42a --- /dev/null +++ b/dovecot/files/sa-learn-spam.sh @@ -0,0 +1,3 @@ +#!/bin/sh +# you can also use tcp/ip here, consult spamc(1) +exec /usr/bin/spamc -u ${1} -L spam -C report diff --git a/dovecot/tasks/main.yml b/dovecot/tasks/main.yml index 8e7127557c9004a43bba941e85ce8379357381fa..ed49f2168adcc3abcd42df1d90c89c6c579ed7cc 100644 --- a/dovecot/tasks/main.yml +++ b/dovecot/tasks/main.yml @@ -1,7 +1,9 @@ --- - name: ensure all required dovecot packages are installed - apt: name={{ item }} state=present + apt: + name: "{{ item }}" + state: present with_items: - dovecot-core - dovecot-imapd @@ -13,18 +15,22 @@ - mail - name: ensure all configs are present - template: src={{item.src}} dest={{item.dest}} + template: + src: "{{ item }}.j2" + dest: "/etc/dovecot/{{ item }}" with_items: - - { src: 'templates/dovecot.conf.j2', dest: '/etc/dovecot/dovecot.conf' } - - { src: 'templates/conf.d/10-auth.conf.j2', dest: '/etc/dovecot/conf.d/10-auth.conf' } - - { src: 'templates/conf.d/10-mail.conf.j2', dest: '/etc/dovecot/conf.d/10-mail.conf' } - - { src: 'templates/conf.d/10-master.conf.j2', dest: '/etc/dovecot/conf.d/10-master.conf' } - - { src: 'templates/conf.d/10-ssl.conf.j2', dest: '/etc/dovecot/conf.d/10-ssl.conf' } - - { src: 'templates/conf.d/20-managesieve.conf.j2', dest: '/etc/dovecot/conf.d/20-managesieve.conf' } - - { src: 'templates/conf.d/20-imap.conf.j2', dest: '/etc/dovecot/conf.d/20-imap.conf' } - - { src: 'templates/conf.d/20-lmtp.conf.j2', dest: '/etc/dovecot/conf.d/20-lmtp.conf' } - - { src: 'templates/conf.d/90-sieve.conf.j2', dest: '/etc/dovecot/conf.d/90-sieve.conf' } - - { src: 'templates/conf.d/auth-passwdfile.conf.ext.j2', dest: '/etc/dovecot/conf.d/auth-passwdfile.conf.ext' } + - dovecot.conf + - deny-users + - conf.d/10-auth.conf + - conf.d/10-mail.conf + - conf.d/10-master.conf + - conf.d/10-ssl.conf + - conf.d/15-lda.conf + - conf.d/20-managesieve.conf + - conf.d/20-imap.conf + - conf.d/20-lmtp.conf + - conf.d/90-sieve.conf + - conf.d/auth-passwdfile.conf.ext notify: - restart dovecot tags: @@ -32,31 +38,68 @@ - mail - name: ensure there is a folder for global sieve scripts - file: dest=/var/lib/dovecot/sieve.d state=directory owner=dovecot group=vmail mode=0770 + file: + dest: /var/lib/dovecot/sieve.d + state: directory + owner: dovecot + group: "{{ dovecot_users_group }}" + mode: 0770 tags: - dovecot - mail - when: content_filter is defined - name: ensure the global spam filter and learning sieve script is present - copy: src="files/{{ item }}" dest="/var/lib/dovecot/sieve.d/{{ item }}" mode=0550 owner=dovecot group=vmail - with_items: - - filter_junk.sieve + template: + src: "sieve/{{ item }}.j2" + dest: "/var/lib/dovecot/sieve.d/{{ item }}" + mode: 0550 + owner: dovecot + group: "{{ dovecot_users_group }}" + with_items: + - filter-spam.sieve - report-spam.sieve - report-ham.sieve + when: dovecot_content_filter notify: - compile sieve scripts tags: - dovecot + - spamassassin + - mail + +- name: ensure scripts for learning spam are present + copy: + src: "{{ item }}" + dest: "/var/lib/dovecot/sieve.d/{{ item }}" + mode: 0750 + owner: dovecot + group: "{{ dovecot_users_group }}" + with_items: + - sa-learn-ham.sh + - sa-learn-spam.sh + when: dovecot_content_filter + tags: + - dovecot + - spamassassin - mail - when: content_filter is defined - name: ensure dsync config is present - template: src=templates/conf.d/99-dsync.conf.j2 dest=/etc/dovecot/conf.d/99-dsync.conf - when: dsync == True + template: + src: conf.d/99-dsync.conf.j2 + dest: /etc/dovecot/conf.d/99-dsync.conf + when: dovecot_dsync notify: - restart dovecot tags: - dovecot - mail +- name: ensure dovecot is enabled and running + service: + name: dovecot + state: started + enabled: yes + tags: + - dovecot + - mail + diff --git a/dovecot/templates/conf.d/10-auth.conf.j2 b/dovecot/templates/conf.d/10-auth.conf.j2 index 664cd8eca8f44b15fd28e0022783774af3146413..86b5cf4a17fc01662ec1d8663895e2fb544c8fe8 100644 --- a/dovecot/templates/conf.d/10-auth.conf.j2 +++ b/dovecot/templates/conf.d/10-auth.conf.j2 @@ -7,7 +7,7 @@ # matches the local IP (ie. you're connecting from the same computer), the # connection is considered secure and plaintext authentication is allowed. # See also ssl=required setting. -disable_plaintext_auth = no +disable_plaintext_auth = yes # Authentication cache size (e.g. 10M). 0 means it's disabled. Note that # bsdauth, PAM and vpopmail require cache_key to be set for caching to be used. @@ -116,13 +116,13 @@ auth_mechanisms = plain # # <doc/wiki/UserDatabase.txt> -#!include auth-deny.conf.ext -#!include auth-master.conf.ext +!include auth-deny.conf.ext +{{ '' if dovecot_auth_system else '#' }}!include auth-system.conf.ext +{{ '' if dovecot_auth_virtual else '#' }}!include auth-passwdfile.conf.ext -#!include auth-system.conf.ext +#!include auth-master.conf.ext #!include auth-sql.conf.ext #!include auth-ldap.conf.ext -!include auth-passwdfile.conf.ext #!include auth-checkpassword.conf.ext #!include auth-vpopmail.conf.ext #!include auth-static.conf.ext diff --git a/dovecot/templates/conf.d/10-mail.conf.j2 b/dovecot/templates/conf.d/10-mail.conf.j2 index d4ecb3a41813365a9fe90c3bf5013d921ca61cf7..2f5843a12501cf57b7c0b7b8a9f54d4254169494 100644 --- a/dovecot/templates/conf.d/10-mail.conf.j2 +++ b/dovecot/templates/conf.d/10-mail.conf.j2 @@ -27,7 +27,7 @@ # # <doc/wiki/MailLocation.txt> # -mail_location = {{ mail_location }} +mail_location = {{ dovecot_mail_location }} # If you need to set multiple mailbox locations or want to change default # namespace settings, you can do it by defining namespace sections. @@ -46,7 +46,7 @@ namespace inbox { # Hierarchy separator to use. You should use the same separator for all # namespaces or some clients get confused. '/' is usually a good one. # The default however depends on the underlying mail storage format. - separator = {{ seperator }} + separator = {{ dovecot_maildir_separator }} # Prefix required to access this namespace. This needs to be different for # all namespaces. For example "Public/". @@ -140,7 +140,7 @@ namespace inbox { # is currently not enforced. Use for example mailto:admin@example.com. This # value is accessible for authenticated users through the IMAP METADATA server # entry "/shared/admin". -#mail_server_admin = +mail_server_admin = {{ dovecot_admin_mail }} ## ## Mail processes @@ -172,8 +172,8 @@ namespace inbox { # to make sure that users can't log in as daemons or other system users. # Note that denying root logins is hardcoded to dovecot binary and can't # be done even if first_valid_uid is set to 0. -#first_valid_uid = 500 -#last_valid_uid = 0 +first_valid_uid = {{ dovecot_min_uid }} +last_valid_uid = {{ dovecot_max_uid }} # Valid GID range for users, defaults to non-root/wheel. Users having # non-valid GID as primary group ID aren't allowed to log in. If user @@ -212,12 +212,7 @@ namespace inbox { # Space separated list of plugins to load for all services. Plugins specific to # IMAP, LDA, etc. are added to this list in their own .conf files. -{% if dsync is defined %} -mail_plugins = $mail_plugins notify replication -{% else %} -mail_plugins = $mail_plugins notify -{% endif %} -#mail_plugins = +mail_plugins = $mail_plugins notify {{ "replication" if dovecot_dsync else "" }} ## ## Mailbox handling optimizations diff --git a/dovecot/templates/conf.d/10-ssl.conf.j2 b/dovecot/templates/conf.d/10-ssl.conf.j2 index 7aadb4b754d5ea25cf58833e147ece7a16c39aa5..d00ff9153d55324401199754bc3e12ebf6c8e0cc 100644 --- a/dovecot/templates/conf.d/10-ssl.conf.j2 +++ b/dovecot/templates/conf.d/10-ssl.conf.j2 @@ -9,8 +9,8 @@ ssl = required # dropping root privileges, so keep the key file unreadable by anyone but # root. Included doc/mkcert.sh can be used to easily generate self-signed # certificate, just make sure to update the domains in dovecot-openssl.cnf -ssl_cert = <{{ ssl_cert }} -ssl_key = <{{ ssl_key }} +ssl_cert = <{{ dovecot_tls_cert }} +ssl_key = <{{ dovecot_tls_key }} # If key file is password protected, give the password here. Alternatively # give it when starting dovecot with -p parameter. Since this file is often @@ -30,7 +30,7 @@ ssl_key = <{{ ssl_key }} # when Dovecot needs to act as an SSL client (e.g. imapc backend). The # directory is usually /etc/ssl/certs in Debian-based systems and the file is # /etc/pki/tls/cert.pem in RedHat-based systems. -#ssl_client_ca_dir = +ssl_client_ca_dir = {{ dovecot_tls_ca_dir }} #ssl_client_ca_file = # Request client to send a certificate. If you also want to require it, set @@ -43,15 +43,15 @@ ssl_key = <{{ ssl_key }} #ssl_cert_username_field = commonName # DH parameters length to use. -ssl_dh_parameters_length = 4096 +ssl_dh_parameters_length = {{ dovecot_tls_dh_length }} # SSL protocols to use -ssl_protocols = TLSv1.1 TLSv1.2 !SSLv3 +ssl_protocols = {{ dovecot_tls_protocols }} # SSL ciphers to use #ssl_cipher_list = HIGH:!LOW:!SSLv2:!EXP:!aNULL:!MD5:!RC4:!SHA1 #Supported Ciphers downto Android 2.3 -ssl_cipher_list = {{ tls_ciphers }} +ssl_cipher_list = {{ dovecot_tls_ciphers }} # Prefer the server's order of ciphers over client's. ssl_prefer_server_ciphers = yes diff --git a/dovecot/templates/conf.d/15-lda.conf.j2 b/dovecot/templates/conf.d/15-lda.conf.j2 new file mode 100644 index 0000000000000000000000000000000000000000..c67cfd6622b011091ffbf24fe2d434b0ff2a5805 --- /dev/null +++ b/dovecot/templates/conf.d/15-lda.conf.j2 @@ -0,0 +1,48 @@ +## +## LDA specific settings (also used by LMTP) +## + +# Address to use when sending rejection mails. +# Default is postmaster@<your domain>. %d expands to recipient domain. +#postmaster_address = + +# Hostname to use in various parts of sent mails (e.g. in Message-Id) and +# in LMTP replies. Default is the system's real hostname@domain. +#hostname = + +# If user is over quota, return with temporary failure instead of +# bouncing the mail. +#quota_full_tempfail = no + +# Binary to use for sending mails. +#sendmail_path = /usr/sbin/sendmail + +# If non-empty, send mails via this SMTP host[:port] instead of sendmail. +#submission_host = + +# Subject: header to use for rejection mails. You can use the same variables +# as for rejection_reason below. +#rejection_subject = Rejected: %s + +# Human readable error message for rejection mails. You can use variables: +# %n = CRLF, %r = reason, %s = original subject, %t = recipient +#rejection_reason = Your message to <%t> was automatically rejected:%n%r + +# Delimiter character between local-part and detail in email address. +#recipient_delimiter = + + +# Header where the original recipient address (SMTP's RCPT TO: address) is taken +# from if not available elsewhere. With dovecot-lda -a parameter overrides this. +# A commonly used header for this is X-Original-To. +#lda_original_recipient_header = + +# Should saving a mail to a nonexistent mailbox automatically create it? +#lda_mailbox_autocreate = no + +# Should automatically created mailboxes be also automatically subscribed? +#lda_mailbox_autosubscribe = no + +protocol lda { + # Space separated list of plugins to load (default is global mail_plugins). + mail_plugins = $mail_plugins sieve +} diff --git a/dovecot/templates/conf.d/20-imap.conf.j2 b/dovecot/templates/conf.d/20-imap.conf.j2 index 6d73b13537b66c32fe10b768572263ca54b825e4..b65b1b7c9f5c14910560b163750d961ae80fdd48 100644 --- a/dovecot/templates/conf.d/20-imap.conf.j2 +++ b/dovecot/templates/conf.d/20-imap.conf.j2 @@ -76,24 +76,22 @@ protocol imap { mail_max_userip_connections = 40 } -{% if content_filter is defined %} - +{% if dovecot_content_filter %} plugin { sieve_plugins = sieve_imapsieve sieve_extprograms # From elsewhere to Spam folder - imapsieve_mailbox1_name = Junk + imapsieve_mailbox1_name = {{ dovecot_spam_folder }} imapsieve_mailbox1_causes = COPY imapsieve_mailbox1_before = file:/var/lib/dovecot/sieve.d/report-spam.sieve # From Spam folder to elsewhere imapsieve_mailbox2_name = * - imapsieve_mailbox2_from = Junk + imapsieve_mailbox2_from = {{ dovecot_spam_folder }} imapsieve_mailbox2_causes = COPY imapsieve_mailbox2_before = file:/var/lib/dovecot/sieve.d/report-ham.sieve sieve_pipe_bin_dir = /var/lib/dovecot/sieve.d - sieve_global_extensions = +vnd.dovecot.pipe +vnd.dovecot.environment } {% endif %} diff --git a/dovecot/templates/conf.d/20-managesieve.conf.j2 b/dovecot/templates/conf.d/20-managesieve.conf.j2 index d549e70ec9a623839277c5f7bc4d2efe16dd9104..11cf0656e6bb2ee05ea35e4c95b85dd400fc7736 100644 --- a/dovecot/templates/conf.d/20-managesieve.conf.j2 +++ b/dovecot/templates/conf.d/20-managesieve.conf.j2 @@ -12,10 +12,6 @@ service managesieve-login { port = 4190 } - #inet_listener sieve_deprecated { - # port = 2000 - #} - # Number of connections to handle before starting a new process. Typically # the only useful values are 0 (unlimited) or 1. 1 is more secure, but 0 # is faster. <doc/wiki/LoginProcess.txt> diff --git a/dovecot/templates/conf.d/90-sieve.conf.j2 b/dovecot/templates/conf.d/90-sieve.conf.j2 index bee89e3712b1d11bcaa65836930cfeccc297c470..2e9aebddd7b1bd0dc656e267dd358a9b74a170be 100644 --- a/dovecot/templates/conf.d/90-sieve.conf.j2 +++ b/dovecot/templates/conf.d/90-sieve.conf.j2 @@ -76,8 +76,8 @@ plugin { #sieve_before = /var/lib/dovecot/sieve.d/ #sieve_before2 = ldap:/etc/sieve-ldap.conf;name=ldap-domain #sieve_before3 = (etc...) -{% if content_filter is defined %} - sieve_before = /var/lib/dovecot/sieve.d/filter_junk.sieve +{% if dovecot_content_filter %} + sieve_before = /var/lib/dovecot/sieve.d/filter-spam.sieve {% endif %} # Identical to sieve_before, only the specified scripts are executed after the diff --git a/dovecot/templates/conf.d/99-dsync.conf.j2 b/dovecot/templates/conf.d/99-dsync.conf.j2 index e76a63d7d47b996ddb5063c98624f2274a5f668a..71e490732d241437c84d057c358827c9e125c287 100644 --- a/dovecot/templates/conf.d/99-dsync.conf.j2 +++ b/dovecot/templates/conf.d/99-dsync.conf.j2 @@ -4,26 +4,22 @@ service replicator { mode = 0666 user = dovecot } - group = vmail + group = {{ dovecot_dsync_group }} } replication_max_conns = 10 - -# there was a problem with the oom-killer -#plugin { -# # When saving a new mail via IMAP or delivering a mail via LDA/LMTP, -# # wait for the mail to be synced to the remote site. If it doesn't finish -# # in 2 seconds, return success anyway. -# replication_sync_timeout = 2 -#} - service doveadm { inet_listener { - address = {{ tinc_vpnip }} +{% if dovecot_dsync_address != '0.0.0.0' %} + address = {{ dovecot_dsync_address }} +{% endif %} port = 37962 +{% if dovecot_dsync_tls %} + ssl = yes +{% endif %} } - group = vmail + group = {{ dovecot_dsync_group }} } service aggregator { @@ -38,14 +34,13 @@ service aggregator { } doveadm_port = 37962 - -doveadm_password = {{ lookup('passwordstore', 'wolfscloud/dsync_secret create=true length=20') }} +doveadm_password = {{ dovecot_dsync_password }} plugin { {% for partner in groups['mail'] %} {% if partner != ansible_hostname %} -mail_replica = tcp:{{hostvars[partner]["tinc_vpnip"]}}:37962 +mail_replica = tcp{{ 's' if dovecot_dsync_tls else '' }}:{{ hostvars[partner][dovecot_dsync_host_attribute] }}:37962 {% endif %} {% endfor %} diff --git a/dovecot/templates/deny-users.j2 b/dovecot/templates/deny-users.j2 new file mode 100644 index 0000000000000000000000000000000000000000..2cedf80cc1e24c167bae5db7de689c2f91de1e1d --- /dev/null +++ b/dovecot/templates/deny-users.j2 @@ -0,0 +1 @@ +{{ dovecot_deny_users|join('\n') }} diff --git a/dovecot/templates/dovecot.conf.j2 b/dovecot/templates/dovecot.conf.j2 index 5288a5722ebdb0c72a997ffcab95eed59a8ce35b..ae11aca874ac5d9fd129a08606f8e72d9e2e377c 100644 --- a/dovecot/templates/dovecot.conf.j2 +++ b/dovecot/templates/dovecot.conf.j2 @@ -96,7 +96,7 @@ dict { # first sorted by their ASCII value and parsed in that order. The 00-prefixes # in filenames are intended to make it easier to understand the ordering. !include conf.d/*.conf -protocols = {{ protocols }} +protocols = {{ dovecot_protocols }} # A config file can also tried to be included without giving an error if # it's not found: diff --git a/dovecot/templates/sieve/filter-spam.sieve.j2 b/dovecot/templates/sieve/filter-spam.sieve.j2 new file mode 100644 index 0000000000000000000000000000000000000000..34cf03e77231e8462fb1b488a98cb4ad401234de --- /dev/null +++ b/dovecot/templates/sieve/filter-spam.sieve.j2 @@ -0,0 +1,5 @@ +require ["fileinto", "mailbox"]; + +if header :contains "X-Spam-Flag" "YES" { + fileinto :create "{{ dovecot_spam_folder }}"; +} diff --git a/dovecot/files/report-ham.sieve b/dovecot/templates/sieve/report-ham.sieve.j2 similarity index 100% rename from dovecot/files/report-ham.sieve rename to dovecot/templates/sieve/report-ham.sieve.j2 diff --git a/dovecot/files/report-spam.sieve b/dovecot/templates/sieve/report-spam.sieve.j2 similarity index 100% rename from dovecot/files/report-spam.sieve rename to dovecot/templates/sieve/report-spam.sieve.j2