summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ansible.cfg2
-rw-r--r--certs/dkim/0ef2a7235861d65c872faf4e72b29a29:jakmedlem.se.pub9
-rw-r--r--certs/dkim/138abf7e73c88d8dc67ca2d26881bc81:guilhem.se.pub9
-rw-r--r--certs/dkim/564736f16aac6a05b50ea67fd6259e16:hemskaklubben.se.pub9
-rw-r--r--certs/dkim/5d30c523ff3622ed454230a16a11ddf6.guilhem.user:debian.org.pub9
-rw-r--r--certs/dkim/5fd8ba74ecb12069964e21a0ba90a516:tevs.net.pub9
-rw-r--r--certs/dkim/79992d8659ce1c2d3f5a9ad20d167c15:r0x.se.pub9
-rw-r--r--certs/dkim/9552b222c0c258daf13bd410f6b5a159:ljhms.se.pub9
-rw-r--r--certs/dkim/a4b2e822cfcf594acd24f44587590eb1:gbg.cmsmarx.org.pub9
-rw-r--r--certs/dkim/aa813339234ce48d3b3bbfa334fbf48e:dubre.me.pub9
-rw-r--r--certs/dkim/caf0355abffeda8264045c3730362147:himmelkanten.se.pub9
-rw-r--r--certs/dkim/ccb92aa8f79aa6d76b2a9d6ecf6b30e6:vimmelkanten.se.pub9
-rw-r--r--certs/dkim/ce3283cc9129cb6692174bd2ec480b88:kodafritt.se.pub9
-rw-r--r--certs/dkim/d32231afe345182ae1a9b376fa912dca:guilhem.org.pub9
-rw-r--r--certs/dkim/d3df4ddda85e3c927621b1b02a9cbb85:lists.fripost.org.pub9
-rw-r--r--certs/dkim/f032227401564da2cee5d5d0965969c4:hemdal.se.pub9
-rwxr-xr-xcerts/gencerts.sh14
-rw-r--r--certs/ipsec/benjamin.pem14
-rw-r--r--certs/ipsec/levante.pem14
-rw-r--r--certs/ldap/ldap.fripost.org.pem39
-rw-r--r--certs/ldap/mx.pem31
-rw-r--r--certs/ldap/syncrepl/mx@civett.pem12
-rw-r--r--certs/ldap/syncrepl/mx@elefant.pem12
-rw-r--r--certs/ssh_known_hosts3
-rw-r--r--group_vars/all.yml49
-rw-r--r--lib/action_plugins/fetch_cmd.py2
-rw-r--r--lib/modules/mysql_user2495
-rw-r--r--lib/modules/openldap83
-rw-r--r--lib/modules/postmulti4
-rw-r--r--production18
-rw-r--r--roles/IMAP/files/etc/dovecot/conf.d/10-auth.conf17
-rw-r--r--roles/IMAP/files/etc/dovecot/conf.d/10-logging.conf85
-rw-r--r--roles/IMAP/files/etc/dovecot/conf.d/10-mail.conf392
-rw-r--r--roles/IMAP/files/etc/dovecot/conf.d/10-ssl.conf62
-rw-r--r--roles/IMAP/files/etc/dovecot/conf.d/15-lda.conf48
-rw-r--r--roles/IMAP/files/etc/dovecot/conf.d/15-mailboxes.conf76
-rw-r--r--roles/IMAP/files/etc/dovecot/conf.d/20-imap.conf85
-rw-r--r--roles/IMAP/files/etc/dovecot/conf.d/20-lmtp.conf27
-rw-r--r--roles/IMAP/files/etc/dovecot/conf.d/90-plugin.conf33
-rw-r--r--roles/IMAP/files/etc/dovecot/conf.d/90-sieve.conf214
-rw-r--r--roles/IMAP/files/etc/dovecot/dovecot-dict-auth.conf.ext2
-rw-r--r--roles/IMAP/files/etc/dovecot/dovecot-ldap.conf.ext11
-rw-r--r--roles/IMAP/files/etc/dovecot/ssl/config2
-rw-r--r--roles/IMAP/files/etc/systemd/system/dovecot-auth-proxy.service10
-rwxr-xr-xroles/IMAP/files/usr/local/bin/dovecot-auth-proxy.pl104
-rwxr-xr-xroles/IMAP/files/usr/local/bin/list-users.pl45
-rw-r--r--roles/IMAP/tasks/imap.yml37
-rw-r--r--roles/IMAP/tasks/mda.yml2
-rw-r--r--roles/IMAP/tasks/spam.yml4
-rw-r--r--roles/IMAP/templates/etc/dovecot/conf.d/10-master.conf.j230
-rw-r--r--roles/IMAP/templates/etc/dovecot/conf.d/15-lda.conf0
-rw-r--r--roles/IMAP/templates/etc/dovecot/conf.d/99-local.conf.j2204
-rw-r--r--roles/IMAP/templates/etc/postfix/main.cf.j22
-rw-r--r--roles/LDAP-provider/files/etc/ldap/dynlist.ldif26
-rw-r--r--roles/LDAP-provider/tasks/main.yml15
-rw-r--r--roles/MSA/files/etc/postfix/anonymize_sender.pcre3
-rw-r--r--roles/MSA/files/etc/systemd/system/postfix-sender-login.service6
-rwxr-xr-xroles/MSA/files/usr/local/bin/postfix-sender-login.pl13
-rw-r--r--roles/MSA/tasks/main.yml30
-rw-r--r--roles/MSA/templates/etc/postfix/main.cf.j213
l---------roles/MSA/templates/etc/postfix/smtp_tls_policy.j21
-rw-r--r--roles/MX/files/etc/opendmarc.conf116
-rw-r--r--roles/MX/files/etc/systemd/system/opendmarc.service.d/override.conf17
-rw-r--r--roles/MX/files/etc/systemd/system/opendmarc.socket10
-rw-r--r--roles/MX/handlers/main.yml9
-rw-r--r--roles/MX/tasks/main.yml45
-rw-r--r--roles/MX/templates/etc/postfix/main.cf.j27
-rw-r--r--roles/MX/templates/etc/postfix/virtual/transport.j24
-rw-r--r--roles/amavis/tasks/main.yml6
-rw-r--r--roles/amavis/templates/etc/amavis/conf.d/50-user.j23
-rw-r--r--roles/bacula-dir/files/etc/systemd/system/bacula-director.service.d/override.conf (renamed from roles/bacula-dir/files/etc/systemd/system/bacula-director.service)14
-rw-r--r--roles/bacula-dir/tasks/main.yml18
-rw-r--r--roles/bacula-dir/templates/etc/bacula/bacula-dir.conf.j2240
-rw-r--r--roles/bacula-sd/files/etc/systemd/system/bacula-sd.service.d/override.conf (renamed from roles/bacula-sd/files/etc/systemd/system/bacula-sd.service)14
-rw-r--r--roles/bacula-sd/tasks/main.yml14
-rw-r--r--roles/bacula-sd/templates/etc/bacula/bacula-sd.conf.j24
-rwxr-xr-xroles/common-LDAP/files/usr/local/sbin/slapcat-all.sh33
-rw-r--r--roles/common-LDAP/tasks/main.yml42
-rw-r--r--roles/common-LDAP/templates/etc/default/slapd.j22
-rw-r--r--roles/common-LDAP/templates/etc/ldap/database.ldif.j2131
-rw-r--r--roles/common-SQL/files/etc/mysql/mariadb.conf.d/99-user.cnf4
-rw-r--r--roles/common-SQL/files/etc/mysql/my.cnf131
-rw-r--r--roles/common-SQL/tasks/main.yml14
-rw-r--r--roles/common-web/files/etc/nginx/sites-available/default6
-rw-r--r--roles/common-web/files/etc/nginx/snippets/acme-challenge.conf4
-rw-r--r--roles/common-web/files/etc/nginx/snippets/fastcgi-php.conf17
-rw-r--r--roles/common-web/files/etc/nginx/snippets/fastcgi.conf9
-rw-r--r--roles/common-web/files/etc/nginx/snippets/ssl.conf24
-rw-r--r--roles/common-web/tasks/main.yml16
-rw-r--r--roles/common/files/etc/apt/apt.conf.d/50unattended-upgrades113
-rw-r--r--roles/common/files/etc/apt/listchanges.conf5
-rw-r--r--roles/common/files/etc/default/rkhunter2
-rw-r--r--roles/common/files/etc/fail2ban/action.d/nftables-allports.local6
-rw-r--r--roles/common/files/etc/fail2ban/fail2ban.local13
-rw-r--r--roles/common/files/etc/fail2ban/filter.d/dovecot.conf34
-rw-r--r--roles/common/files/etc/logcheck/ignore.d.server/common-local135
-rw-r--r--roles/common/files/etc/logcheck/ignore.d.server/dovecot-local30
-rw-r--r--roles/common/files/etc/logcheck/ignore.d.server/postfix-local74
-rw-r--r--roles/common/files/etc/logcheck/ignore.d.server/strongswan-local37
-rw-r--r--roles/common/files/etc/logcheck/logcheck.conf15
-rw-r--r--roles/common/files/etc/logcheck/violations.ignore.d/logcheck-sudo10
-rw-r--r--roles/common/files/etc/logrotate.d/fripost-mail4
-rw-r--r--roles/common/files/etc/rkhunter.conf253
-rw-r--r--roles/common/files/etc/rsyslog.conf12
-rw-r--r--roles/common/files/etc/strongswan.d/charon.conf109
-rw-r--r--roles/common/files/etc/strongswan.d/charon/socket-default.conf3
-rw-r--r--roles/common/files/etc/systemd/system/bacula-fd.service25
-rw-r--r--roles/common/files/etc/systemd/system/bacula-fd.service.d/override.conf13
-rw-r--r--roles/common/files/etc/systemd/system/fail2ban.service.d/override.conf5
-rw-r--r--roles/common/files/etc/systemd/system/munin-node.service.d/override.conf14
-rw-r--r--roles/common/files/etc/systemd/system/stunnel4@.service5
-rwxr-xr-xroles/common/files/usr/local/bin/genkeypair.sh12
-rwxr-xr-xroles/common/files/usr/local/sbin/update-firewall16
-rw-r--r--roles/common/handlers/main.yml14
-rw-r--r--roles/common/tasks/bacula.yml14
-rw-r--r--roles/common/tasks/fail2ban.yml20
-rw-r--r--roles/common/tasks/firewall.yml2
-rw-r--r--roles/common/tasks/ipsec.yml5
-rw-r--r--roles/common/tasks/logging.yml7
-rw-r--r--roles/common/tasks/main.yml13
-rw-r--r--roles/common/tasks/munin-node.yml56
-rw-r--r--roles/common/tasks/ntp.yml32
-rw-r--r--roles/common/tasks/resolved.yml36
-rw-r--r--roles/common/tasks/smart.yml7
-rw-r--r--roles/common/tasks/stunnel.yml12
-rw-r--r--roles/common/tasks/sysctl.yml10
-rw-r--r--roles/common/tasks/unbound.yml11
-rw-r--r--roles/common/templates/etc/apt/preferences.j210
-rw-r--r--roles/common/templates/etc/apt/sources.list.j28
-rw-r--r--roles/common/templates/etc/bacula/bacula-fd.conf.j212
-rw-r--r--roles/common/templates/etc/clamav/freshclam.conf.j21
-rw-r--r--roles/common/templates/etc/fail2ban/jail.local.j28
-rw-r--r--roles/common/templates/etc/ipsec.conf.j25
-rw-r--r--roles/common/templates/etc/munin/munin-node.conf.j24
-rw-r--r--roles/common/templates/etc/munin/plugin-conf.d/munin-node.j22
-rwxr-xr-xroles/common/templates/etc/nftables.conf.j2219
-rw-r--r--roles/common/templates/etc/ntp.conf.j214
-rw-r--r--roles/common/templates/etc/postfix/main.cf.j22
-rw-r--r--roles/common/templates/etc/postfix/master.cf.j26
-rw-r--r--roles/common/templates/etc/systemd/resolved.conf.d/local.conf.j211
-rw-r--r--roles/common/templates/etc/systemd/timesyncd.conf.d/fripost.conf.j29
-rw-r--r--roles/common/templates/etc/unbound/unbound.conf.j22
-rw-r--r--roles/git/files/etc/nginx/sites-available/git54
-rw-r--r--roles/git/files/etc/systemd/system/cgit.service23
-rw-r--r--roles/git/files/etc/systemd/system/cgit.socket11
-rw-r--r--roles/git/files/etc/systemd/system/git-http-backend.service21
-rw-r--r--roles/git/files/etc/systemd/system/git-http-backend.socket11
-rw-r--r--roles/git/files/etc/uwsgi/apps-available/cgit.ini6
-rw-r--r--roles/git/files/etc/uwsgi/apps-available/git-http-backend.ini8
-rw-r--r--roles/git/handlers/main.yml13
-rw-r--r--roles/git/tasks/cgit.yml96
-rw-r--r--roles/git/tasks/gitolite.yml2
-rw-r--r--roles/lacme/files/etc/lacme/lacme.conf119
-rw-r--r--roles/lacme/tasks/main.yml9
-rw-r--r--roles/lists/files/etc/nginx/sites-available/sympa35
-rw-r--r--roles/lists/files/etc/sympa/sympa/sympa.conf32
-rw-r--r--roles/lists/files/etc/systemd/system/wwsympa.service9
-rw-r--r--roles/lists/tasks/mail.yml2
-rw-r--r--roles/lists/tasks/sympa.yml4
-rw-r--r--roles/lists/templates/etc/postfix/main.cf.j22
-rw-r--r--roles/lists/templates/etc/sympa/robot.conf.j23
-rw-r--r--roles/munin-master/files/etc/nginx/sites-available/munin4
-rw-r--r--roles/munin-master/tasks/main.yml11
-rw-r--r--roles/munin-master/templates/etc/munin/munin.conf.j26
-rw-r--r--roles/nextcloud/files/etc/cron.d/nextcloud2
-rw-r--r--roles/nextcloud/files/etc/ldap/ldap.conf4
-rw-r--r--roles/nextcloud/files/etc/logrotate.d/nextcloud9
-rw-r--r--roles/nextcloud/files/etc/nginx/sites-available/nextcloud76
-rw-r--r--roles/nextcloud/files/etc/php/fpm/pool.d/nextcloud.conf24
-rw-r--r--roles/nextcloud/handlers/main.yml7
-rw-r--r--roles/nextcloud/tasks/main.yml140
-rw-r--r--roles/out/tasks/main.yml19
-rw-r--r--roles/out/templates/etc/postfix/canonical.j22
-rw-r--r--roles/out/templates/etc/postfix/main.cf.j25
-rw-r--r--roles/out/templates/etc/postfix/smtp_tls_policy.j212
-rw-r--r--roles/webmail/files/etc/cron.d/roundcube-core7
-rw-r--r--roles/webmail/files/etc/nginx/sites-available/roundcube43
-rw-r--r--roles/webmail/files/etc/php/fpm/pool.d/roundcube.conf22
-rw-r--r--roles/webmail/files/etc/roundcube/plugins/authres_status/config.inc.php6
-rw-r--r--roles/webmail/files/etc/roundcube/plugins/html5_notifier/config.inc.php6
-rw-r--r--roles/webmail/files/etc/roundcube/plugins/jqueryui/config.inc.php11
-rw-r--r--roles/webmail/files/etc/roundcube/plugins/password/config.inc.php2
-rw-r--r--roles/webmail/files/etc/roundcube/plugins/thunderbird_labels/config.inc.php5
-rw-r--r--roles/webmail/files/etc/systemd/system/stunnel4@ldap.socket11
-rw-r--r--roles/webmail/files/usr/share/roundcube/program/resources/fripost_logo_black.png (renamed from roles/webmail/files/usr/share/roundcube/skins/classic/images/fripost_logo.png)bin6567 -> 6567 bytes
-rw-r--r--roles/webmail/files/usr/share/roundcube/program/resources/fripost_logo_white.png (renamed from roles/webmail/files/usr/share/roundcube/skins/larry/images/fripost_logo.png)bin5454 -> 5454 bytes
-rw-r--r--roles/webmail/handlers/main.yml10
-rw-r--r--roles/webmail/tasks/ldap.yml34
-rw-r--r--roles/webmail/tasks/main.yml2
-rw-r--r--roles/webmail/tasks/roundcube.yml143
-rw-r--r--roles/webmail/templates/etc/roundcube/plugins/managesieve/config.inc.php.j24
-rw-r--r--roles/webmail/templates/etc/stunnel/ldap.conf.j2 (renamed from roles/webmail/files/etc/stunnel/ldap.conf)32
-rw-r--r--roles/wiki/files/etc/nginx/sites-available/website19
-rw-r--r--roles/wiki/files/etc/nginx/sites-available/wiki21
-rw-r--r--roles/wiki/files/etc/systemd/system/ikiwiki.service23
-rw-r--r--roles/wiki/files/etc/systemd/system/ikiwiki.socket11
-rw-r--r--roles/wiki/files/var/lib/ikiwiki/IkiWiki/Plugin/pandoc.pm55
-rw-r--r--roles/wiki/files/var/lib/ikiwiki/fripost-wiki.setup3
-rw-r--r--roles/wiki/handlers/main.yml9
-rw-r--r--roles/wiki/tasks/main.yml39
200 files changed, 3233 insertions, 3043 deletions
diff --git a/ansible.cfg b/ansible.cfg
index fac3b72..09c8745 100644
--- a/ansible.cfg
+++ b/ansible.cfg
@@ -39,6 +39,6 @@ become_ask_pass=True
[ssh_connection]
-control_path = ~/.ssh/S.ansible-%%C
+control_path = ${XDG_RUNTIME_DIR}/ssh-ansible-%%C
ssh_args = -oHashKnownHosts=no -oUserKnownHostsFile=./certs/ssh_known_hosts -oStrictHostKeyChecking=yes -oControlMaster=auto -oControlPersist=60s
pipelining = True
diff --git a/certs/dkim/0ef2a7235861d65c872faf4e72b29a29:jakmedlem.se.pub b/certs/dkim/0ef2a7235861d65c872faf4e72b29a29:jakmedlem.se.pub
new file mode 100644
index 0000000..07b06bc
--- /dev/null
+++ b/certs/dkim/0ef2a7235861d65c872faf4e72b29a29:jakmedlem.se.pub
@@ -0,0 +1,9 @@
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA631Sqr0EH+zzmS8g1I6f
+JziGSCos24MbNjt//uqJVdkSEO6syumWePmYLzVz/G4PhFl4D1Y3ZtbXS8bR+BZ6
+MJNy+U+nGfyqo/MOxEPXIT/tRVa/8Ikniq1mvasIhX+TZllCf86wLCo061bgn9cH
+IiZS6zeSgxGbLWEQdSE7Kb/Pd0vzH2piaVEA4MzZQyonguqMlm3AU4kQ0k8pMp6k
+caMSUr7WxEPE6k5p5ah+mJ54fAvezkXyBs7oDuc3SrExkv2mfjBifN+GlGzMsYbb
+iQl4ixfxPAw1pLwP4/sPDhdIZf0vQcrSgxuEMGmFr23BD7moCLXn0lXxalICkz7m
+xwIDAQAB
+-----END PUBLIC KEY-----
diff --git a/certs/dkim/138abf7e73c88d8dc67ca2d26881bc81:guilhem.se.pub b/certs/dkim/138abf7e73c88d8dc67ca2d26881bc81:guilhem.se.pub
new file mode 100644
index 0000000..7996cdb
--- /dev/null
+++ b/certs/dkim/138abf7e73c88d8dc67ca2d26881bc81:guilhem.se.pub
@@ -0,0 +1,9 @@
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA27ioPU45Jca7x1J37gnI
+MOYTxxWE2H/EhL0SiMUROTphBPGYPyqJMmVCb3ff30Uf1tNv4g2UudWkMmoyHfgB
+hS7B07U+kK+q1gIDzcdQyGv1NN4efYtzo7iT6aNEArSP7vxa+OW1pltF1MQz5tnS
+UNFagc34cmQcN3QQXJW8XPMrQfDCm5QYgjXKamQ59GQuH+H6awNi0jGoEmlkwZad
+ZZ0O2Ly7eP/VPrmjDjP0QfC3pUjiFVa7ZPeL89aUuhQv40//7UxuGWuRKH/S7Rna
+tn3P059zXbK73Gg4ZdxLp9FPoORAyKxTq4F0ekSDc64zwNzTuNMusysBzAf3g2WS
+LwIDAQAB
+-----END PUBLIC KEY-----
diff --git a/certs/dkim/564736f16aac6a05b50ea67fd6259e16:hemskaklubben.se.pub b/certs/dkim/564736f16aac6a05b50ea67fd6259e16:hemskaklubben.se.pub
new file mode 100644
index 0000000..8f0a4bd
--- /dev/null
+++ b/certs/dkim/564736f16aac6a05b50ea67fd6259e16:hemskaklubben.se.pub
@@ -0,0 +1,9 @@
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzdBZEho4wiYXL2RcxE3f
+ELcE7p2gjJD+gCIEIY6a7R6TM+GDxY/uLRXJuMpaw3Ar23R9Dj9I4Pu8k/MpskXU
+XQPwpOlnY18Dg/AYJR23RMBOZl8x6AGrO7GxP1R21l/9Y+ZHcuORPnIvRyLgX9aj
+k8iUwWaHfRo+rIyDTsPGQ6O8Zi1mCjlV+iuY1EO2AE88MNh6DiBlZlAH0dhLD9nw
+2AIz6oDQb9PNuUMfW6CBILWK45ETaBkAXqSJjcxzNbRov7AkHNDXx4Vw/s9AE2n+
+On7QHuojPtz4rJh83nInCFVuHXF9ZYR/MYBFLTBa9QzN6W/p7igulc4pn0Bn8STD
+RQIDAQAB
+-----END PUBLIC KEY-----
diff --git a/certs/dkim/5d30c523ff3622ed454230a16a11ddf6.guilhem.user:debian.org.pub b/certs/dkim/5d30c523ff3622ed454230a16a11ddf6.guilhem.user:debian.org.pub
new file mode 100644
index 0000000..bc14abf
--- /dev/null
+++ b/certs/dkim/5d30c523ff3622ed454230a16a11ddf6.guilhem.user:debian.org.pub
@@ -0,0 +1,9 @@
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvGwfj6qfh15Nr/fLITGU
+ES9Vxtjqz6XR8uYifT9P6n80yVLLF0mCVvekSsH8Y8ZShmDmlqrNAM8i5MyKSGTq
+nMTABFlXa0bCHSjY3MNTG0PEn2yUGuc2IsmZWps8oaut5AGirEHoKjx/p2TpcFlD
+8DsyojlFbsIYmAQe65nfliDM8Qiu7NgJlghfRTTBTeXJ2yijrPymBFhJ1z1GWxUm
+nJHzj4I5ySvOmNgCVfv6nP6OjaGOdso8hiS6rse84evRlczFp+IQ/3ErP4HyNZlS
+gHFwRzcENwFdiZ9H3KjM5MUwUJ9ifyy1n2bH/5LOVEsqzmbVJqwrTi1gIP3JQL9z
+EwIDAQAB
+-----END PUBLIC KEY-----
diff --git a/certs/dkim/5fd8ba74ecb12069964e21a0ba90a516:tevs.net.pub b/certs/dkim/5fd8ba74ecb12069964e21a0ba90a516:tevs.net.pub
new file mode 100644
index 0000000..c4c5317
--- /dev/null
+++ b/certs/dkim/5fd8ba74ecb12069964e21a0ba90a516:tevs.net.pub
@@ -0,0 +1,9 @@
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv6xXJyURaqp+OD7VETPP
+CykL9Mwl90uFQOGl6HElV9uZwAhKekmVQka8JrMTZ5KpgVG+ro/NgnRGP8poQB9A
+poXRovX6kqwibzkh9Y/mcEW9UJg3WFc/VfOHUoKyqKtFrWwAPbTzLqC9idqEr1P/
+dLoU5i0Qhp/fWJJg0cnEg3V+6LZtmRjZwGBWKqrSaJENGAAUe0eqm5kJGfNHPagB
+Dg85o6fuTnz3ydXJk0+JaZc96jiXQzDlya0H+QbfMjBOOg7VjNzbLaDDQnFBLaY0
+tsGGcNqyS1cC8rR5Pv/1SY9fvjXBnu3//tuWuJYeHS5Q7wx84yZ03VcvVsA8yjro
+GwIDAQAB
+-----END PUBLIC KEY-----
diff --git a/certs/dkim/79992d8659ce1c2d3f5a9ad20d167c15:r0x.se.pub b/certs/dkim/79992d8659ce1c2d3f5a9ad20d167c15:r0x.se.pub
new file mode 100644
index 0000000..0b5de26
--- /dev/null
+++ b/certs/dkim/79992d8659ce1c2d3f5a9ad20d167c15:r0x.se.pub
@@ -0,0 +1,9 @@
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0fHwmvlTzoFX3AYvh6JZ
+t2P2vS1dDRaMB6sVXEoHjdesrvmkYCYkMvboAA1Sv34ZOqoc0E6WhSsiwEP4tRdl
+WkIQhOFr85KR3sdj3KtepngBexl4arx8FcE55mbDErzaHdmMZVbITJDNfl002DiD
+j2U35R81pTOT1M7j8eJPAF2yu2FzJG/hw98ZQWwbkgyZrIcdtTmi95uWnsjGbfcM
+Iq9YBPQItt0g/tGF379+r1D4md50UQz5SbqzsZ36O73UhY1CYo+ZFZH5dHtEl8am
+mnGy0QSdMHvwd+emPXo5bZHYSKqUqt/dDJ7NkYUnXiDpFbnCyt3s/UJ4T5VAyMQg
+CQIDAQAB
+-----END PUBLIC KEY-----
diff --git a/certs/dkim/9552b222c0c258daf13bd410f6b5a159:ljhms.se.pub b/certs/dkim/9552b222c0c258daf13bd410f6b5a159:ljhms.se.pub
new file mode 100644
index 0000000..cbf348c
--- /dev/null
+++ b/certs/dkim/9552b222c0c258daf13bd410f6b5a159:ljhms.se.pub
@@ -0,0 +1,9 @@
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzzcLgdRi0hh0X1aXWA5R
+oa92nKQCAf26aClwuXCyl9mfJXhIWPrw/tobpl1RCrRXUT7d/3qQ/cboacjuPbIB
+E8U6a3D0S9usWg9qY31fNMQoqKQPk/lXbfAfeiJCccVUdaXqEtMErqj8+XTnd4jJ
+EfA/P/p956w3bdZAH+4jEtrXgf7NErn7YJcusK2HQp1clOzV+kBo9bABqjhXHL2L
+rhtWRUgO3ODaiPmUl1VAFjepjJYb6gXSQOuquJdlKYfOwyxcVgKA1caADeWS51em
+hc/MOob5DKL99S3IjecicaBffTArijW5PcJLfGGKHIkAxmTWo/YsTA3hxSmnpGna
+1wIDAQAB
+-----END PUBLIC KEY-----
diff --git a/certs/dkim/a4b2e822cfcf594acd24f44587590eb1:gbg.cmsmarx.org.pub b/certs/dkim/a4b2e822cfcf594acd24f44587590eb1:gbg.cmsmarx.org.pub
new file mode 100644
index 0000000..e4b2949
--- /dev/null
+++ b/certs/dkim/a4b2e822cfcf594acd24f44587590eb1:gbg.cmsmarx.org.pub
@@ -0,0 +1,9 @@
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvmO04P51AngD41CpgrTm
+5Mjs4M4iT10In9JF9X2l83opAoiGDoTPElcXxmmGvOvwbUV1Q2sNb2/WKLhNvlRp
+EgZiBqBd9Gf1Rf9OxpoQlfZjdhbQ5UPhxma4f/saN3RNNvAgDH+TE6DltAvZF+kW
+sjRlBabVdB+vPHBwfSBIEHvzS2rJLwx8jzzsWJQpBRkjBcueX2v4AmPIw2Lc0RJh
+/76a63xyeyGXcvKzHrBlhZPl+P6Yz5KXOE9eGJmdS9ahArZTUs5ACSwWlSrJyDUo
+hT7UeuDp0/J3HMKY51CsMwTLUxfrUoNMIAyJTJg20XeqkYzymMG5hgFilhdJdS4C
+PwIDAQAB
+-----END PUBLIC KEY-----
diff --git a/certs/dkim/aa813339234ce48d3b3bbfa334fbf48e:dubre.me.pub b/certs/dkim/aa813339234ce48d3b3bbfa334fbf48e:dubre.me.pub
new file mode 100644
index 0000000..92f7479
--- /dev/null
+++ b/certs/dkim/aa813339234ce48d3b3bbfa334fbf48e:dubre.me.pub
@@ -0,0 +1,9 @@
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArZQr93FM5Ob62mmMlE2r
+pPnRJCSnaKobSedlAjdvN3frKp7jI38ygRf+9tlj40k8XPES9CYcqmN3EGCZsOTF
+JxcZvFbSQIj+1YDKiefUm6ezGbOWdSOYHY0Ztycl9pJeUFWFFXrqhk6jBs8kt3gb
+siwLD2mgXUauV+PRumoxkzLz7oH+wnNlAEcyhzhor4sHN+2oYfr/KBHfS6X1UcVp
+Tn6mGv71OAzI0Ae3VgJ+uIfNA5rcm0iBpVMIZL2z4KYNbDUl3ah7H46/W0SI+53E
+1aUsq4mHccDZV5CtMjncM16O1iqVRbA0BBvt1lxgd42YInGd88eM9Bp6GuyBuSFr
+GwIDAQAB
+-----END PUBLIC KEY-----
diff --git a/certs/dkim/caf0355abffeda8264045c3730362147:himmelkanten.se.pub b/certs/dkim/caf0355abffeda8264045c3730362147:himmelkanten.se.pub
new file mode 100644
index 0000000..f0f4827
--- /dev/null
+++ b/certs/dkim/caf0355abffeda8264045c3730362147:himmelkanten.se.pub
@@ -0,0 +1,9 @@
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoJ2pK0ZGuPMzXm9yUXjS
+A8CYffODp8qGl+C4Hg3F3EbBvv5VP92ALwVh3bsA63Zn4TXQ2yKztK/czoRvmTBw
+qfpZABMdkLbokffIALHrouz3e0oNxrfNcH/H/vB0AjjtHvENfOLlhBBB178HuHpa
+YVKAItiD5T0rQ3soTXRYt5Lc/TjXLMfiN8MXxVKNc5FtHi8KFZLDMXC4wfBbkkyD
+iJGryG2p3XFTCn03nEOdpLb291K/tnE6BOdDsIkgN0OHwWv/SefSgiyyJtTYvdlN
+7Cknr0uu6vjjEGhvkF3q7HzIqqlA8OwiTWuqegnOvsOR3ueIly5DIZ/cgAuhpOgY
+0QIDAQAB
+-----END PUBLIC KEY-----
diff --git a/certs/dkim/ccb92aa8f79aa6d76b2a9d6ecf6b30e6:vimmelkanten.se.pub b/certs/dkim/ccb92aa8f79aa6d76b2a9d6ecf6b30e6:vimmelkanten.se.pub
new file mode 100644
index 0000000..51ce588
--- /dev/null
+++ b/certs/dkim/ccb92aa8f79aa6d76b2a9d6ecf6b30e6:vimmelkanten.se.pub
@@ -0,0 +1,9 @@
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1Raz+2M5r1t/bKiFYRZx
+e3HsciNmoMIHy1+UaXq7gnGHmSFxOwDquItmrsmXZBLPbul34NnOcXjmz2sOYDNR
+bAbKWGp/Gp1Tw0d8wWGScOI8QJLayVqmnnJW2INzYQ3XmXXlVJu0U8659W/jIBrE
+GHtVGus9X46tNI1fMQjRxTuJ9fKp4cjVuUCpZM4U8+YAyqPI+uGkRtacYRpoHcrR
+/OeN6/rx63XLgvjW8woihdoUo2S2FAqMvHRKSVwrkoMl9C3yNUUZTq/ddzUPd/jm
+skzgGqkgePSwMM04TE4fW395GFaZwhh0opecwZS2KV9MAPjVtnm/PnTLluAQLBeG
+4QIDAQAB
+-----END PUBLIC KEY-----
diff --git a/certs/dkim/ce3283cc9129cb6692174bd2ec480b88:kodafritt.se.pub b/certs/dkim/ce3283cc9129cb6692174bd2ec480b88:kodafritt.se.pub
new file mode 100644
index 0000000..f673d2e
--- /dev/null
+++ b/certs/dkim/ce3283cc9129cb6692174bd2ec480b88:kodafritt.se.pub
@@ -0,0 +1,9 @@
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuTFd3JIWOX5P2dHwyyfX
+o9OS5KKZ7SYzOntHE6mKJV2jwkt81XX2BznximopptMCyRQWucSAxIrlbYb6zgIA
+QdHSK1OD9c2zMtq4iRGiLAv7Be/QaTtB2zq0+Q2YYTHM+GqFMlPa3PJ+4F4DeJZG
+Z8o1ylYjd8VI57P8HP217sHZQinYeht0iEX7kQgkwW1SdEH/FuMC/dptD9+Z29Cd
+3ml873GnY+Rx6p41EvFq7EhUsJamnY3gGADWmcmDudxVWgwjZdxr9zs11Z2tWI7D
+aU4Ze62vTY55t1opeYM0YfSiPHs3X91T2Wn0dtkLm9Xa+E4NKjTFQt0353c42ODR
+PwIDAQAB
+-----END PUBLIC KEY-----
diff --git a/certs/dkim/d32231afe345182ae1a9b376fa912dca:guilhem.org.pub b/certs/dkim/d32231afe345182ae1a9b376fa912dca:guilhem.org.pub
new file mode 100644
index 0000000..360fe90
--- /dev/null
+++ b/certs/dkim/d32231afe345182ae1a9b376fa912dca:guilhem.org.pub
@@ -0,0 +1,9 @@
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArcDGkR2PB0DAySR3Rel5
+qGjrMYInAwPAbyZ6SFYjjKZxEGFqkgyweUJATxa17rFZ2AWU6M0TKKEgCCDWYasa
+NfQUJd5yRcZksEhLU3S3dKNj5OmtbgFdtV3rtw8Eavxv6rSsYkzyzcQTSQDKkkGf
+CMSwWAkWYVTxRhdqRdbv+rQv47ykzymBKSU2PTkg3u/oWE0ebtSM9O4Q6AzSNiWM
+X4ClWndCpK+04WrR8GaWfsQiWpQHzwidTq8ybZXzHjU8wBl44/N5R4RytB9AFhiM
+31gnQ7yQ0JAt9vVrnzF8WNNAiSbtMukygsP9lem9ZTKCjPgKrr8IajKbdlwV49My
+GwIDAQAB
+-----END PUBLIC KEY-----
diff --git a/certs/dkim/d3df4ddda85e3c927621b1b02a9cbb85:lists.fripost.org.pub b/certs/dkim/d3df4ddda85e3c927621b1b02a9cbb85:lists.fripost.org.pub
new file mode 100644
index 0000000..e879336
--- /dev/null
+++ b/certs/dkim/d3df4ddda85e3c927621b1b02a9cbb85:lists.fripost.org.pub
@@ -0,0 +1,9 @@
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuo5CbOjxGWmBKtAHWujA
+Jt13eluCYkki0gY8mF8/EJdMIrkJIRBitHHTI0Dbue1jSlD/xaAxIjeDa0okhfrR
+9XHc6cO5kImYgcdE6/0kdqy+UIo9c66i2RBtOu6luyHAMMXqUEaS8DxhxZv8v2Bx
+Ufotx9c1xIFz0h0z2Jlbvq8JFhEDFJY2Gj452lM9aRiADqHt9NeNqhBQyK+3dydx
+6VoTSj72tiEE28l/iT7EVYdAuHKNNDNBQgZBdWHqb+zZg3F5VpH/A5qfOykdXApc
+8gY4bUEK60eDT5h52o3Hguaq1hsP3AqBuOlZ4RVmtchn7tmu/9QT3S0QENfW7waM
+kQIDAQAB
+-----END PUBLIC KEY-----
diff --git a/certs/dkim/f032227401564da2cee5d5d0965969c4:hemdal.se.pub b/certs/dkim/f032227401564da2cee5d5d0965969c4:hemdal.se.pub
new file mode 100644
index 0000000..2aed357
--- /dev/null
+++ b/certs/dkim/f032227401564da2cee5d5d0965969c4:hemdal.se.pub
@@ -0,0 +1,9 @@
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxPW6X6CAplQ0He8CyqUs
+Ob5RnoukZtVllZsHJxvFCPjsXq4ZcPZRyNkyBo71XkDG0IBD5lCXYJk0dO/3iLMP
+fOXl9g250sZkaa1lZTdUu19Jv0Sitegql2MF6WMmt/ntPnIIaG4yq/w40ylnF8HJ
+flfN5MvPBnW2ltzzfBwUdOEEXlCsZ+tFp0s6qPrfz9dnqN0TIwFfRui3ohHGox1o
+5tKGoX3HLQ+pFyOg16dyegCXLezBwcy7RfymUnG5H0BeOrQlNZyQoSX0G/Fh4WGe
+NYyFVoWg8oYrry59zow7gEITGoYABDI/DGfMQIJMA6XHXauvhnGzFuY5Ae4ElsKU
+0QIDAQAB
+-----END PUBLIC KEY-----
diff --git a/certs/gencerts.sh b/certs/gencerts.sh
index b796339..3314757 100755
--- a/certs/gencerts.sh
+++ b/certs/gencerts.sh
@@ -26,8 +26,8 @@ x509fpr() {
host="${msg%%,*}"; host="${host%% *}"; host="${host#\`}"
pub="$DIR/${host%%:*}.pub"
spki=$(openssl pkey -pubin -outform DER <"$pub" | openssl dgst -sha256 | sed -nr 's/^[^=]+=\s*//p')
- [ "$typ" = mdwn ] && printf '\n[%s](https://crt.sh/?spkisha256=%s&iCAID=16418&exclude=expired)\n\n' "$msg" "$spki" \
- || printf '\n%s\n\n: X.509: https://crt.sh/?spkisha256=%s&iCAID=16418&exclude=expired\n SPKI:\n' \
+ [ "$typ" = mdwn ] && printf '\n[%s](https://crt.sh/?spkisha256=%s&exclude=expired)\n\n' "$msg" "$spki" \
+ || printf '\n%s\n\n: X.509: https://crt.sh/?spkisha256=%s&exclude=expired\n SPKI:\n' \
"$(printf '%s' "$msg" | tr -d '`' )" "$spki"
[ "$typ" = mdwn ] && indent=":${indent#?}"
for h in sha1 sha256; do
@@ -124,10 +124,10 @@ admin@fripost.org
These certificates are all issued by the Let's Encrypt Certificate
-Authority, and are submitted to Certificate Transparency logs. You can
-view all issued Let's Encrypt certificates at crt.sh:
+Authority, and are submitted to Certificate Transparency logs. You can
+view all issued certificates at crt.sh:
- https://crt.sh/?Identity=%25fripost.org&iCAID=16418
+ https://crt.sh/?Identity=fripost.org
The SPKI of our X.509 certificates are also available in PEM format at:
@@ -155,8 +155,8 @@ the [signed version of this page](/certs.asc).)
These certificates are all issued by the [Let's Encrypt Certificate
Authority](https://letsencrypt.org), and are submitted to [Certificate
Transparency logs](https://www.certificate-transparency.org).
-You can view all issued Let's Encrypt certificates at
-[crt.sh](https://crt.sh/?Identity=%25fripost.org&iCAID=16418).
+You can view all issued certificates at
+[crt.sh](https://crt.sh/?Identity=fripost.org).
The SPKI of our X.509 certificates are also available in PEM format
under our [Git repository]($VCS_BROWSER/tree/certs/public),
from which this fingerprint list was [generated]($VCS_BROWSER/tree/certs/gencerts.sh), at
diff --git a/certs/ipsec/benjamin.pem b/certs/ipsec/benjamin.pem
deleted file mode 100644
index bfb094e..0000000
--- a/certs/ipsec/benjamin.pem
+++ /dev/null
@@ -1,14 +0,0 @@
------BEGIN PUBLIC KEY-----
-MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAwOODNQ5sdVXFrzAeo9bC
-hbauUP69uXoc6OP/l1xB9kjzmErEnoAlVjKO05nUE6Uus03/RkEPdyaMCfKarAhb
-FHaowtylUjUcIsVJkGsem4vRtuLv929vLx4TdL8BN5NCMsXOecoI5z//lfJ4YVfp
-mLQ+OUM8kWNcHOPRpnLLZq/Pwvn93WbzWmxlcmVZUwq66f0N9zBSk8678TikZGx2
-dJ/HZwigswo0PSxTIbvE2eoDdFohi9RrBxpXTnsxCAXpFIV7SLobw+tQvuv+r2oK
-5oGOnHIGmJZWVC3bRIb+PPELeB1g3TfNz7bP5PRKpXnP0cdK/0J2A+vQqArr8ACs
-gzxsKUb7t9OASLH14fQ25FJ3nsc+CS9snXIxJourd5d2cyhMe3xBo0tzPLC8sc3m
-wIyuz60o0pOjvIfzlYyldtYk3CTCVKMs1UpLnea8DDIvzhWn+TLX2yAKS/KNG0Tw
-72aLc86ZUVKV0+fkwjRWtIAWSJQZL/tOl4iDyU+T9dG9dDR1KlsfW0JBGTkyZOLZ
-rSBVQvDj/aUQjgc8e54MghJsS5QdAvD2rTO5liqB8YzHY77Nj2d4f5kqBHj41Kwt
-GOQT4nXYI+rdOpkmkMj5kOGoeRICSv+eszXADnHHtoPS73rjej0gseibSvvm9n3i
-Kkd5mm2N2oZ9Q5pF52CUFfMCAwEAAQ==
------END PUBLIC KEY-----
diff --git a/certs/ipsec/levante.pem b/certs/ipsec/levante.pem
new file mode 100644
index 0000000..ace22c1
--- /dev/null
+++ b/certs/ipsec/levante.pem
@@ -0,0 +1,14 @@
+-----BEGIN PUBLIC KEY-----
+MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA1YZv2Xs5c/fN92CXtOZp
+c4oAlV099Og3mLlsypu1xTyf0eeUhMuqH1dsGWCyLF2Wcha4GJCgWXZ5Fy1nwYBV
+JyF5Ji1Jj3Xssr9locno5dFm0WsdPF7C6SNxKYxk8QkTC6LT6ypv8O1uVqlO+G8t
+C7pRt+qALNJ5pqK7h+KsZqrMk89ztjXfTaK5aeupDYr77479WHVvOXMdQhiizgUF
+9yMA9muRfaNeegR86DPo+1HTX1cvzAl/WE0H90wAiLbo4VrYHS/U79maTQf3LCHZ
+CU0G4gC2+xDNbei+A4Dn7s/nGJckxkkBAaBRJ0lDY1gAdJvCrPeKT34aBUnhg05+
+kl4VHbupVJ7x5DOogxN6iV1veER06vikfpenlxffodT6oLhmhjaMFhhNlc918zkh
+7c4devC7oIzCPnpBgQmK/2tWc4jWbZ7nU64csi9VhkQPLukLruAxtP+0k6opAiVm
+a74T0OyExjfs7p80yNd62aeX7OgKXms0+0xbmxhmboAI2LYGAIaTLRZvf2ZYDSJn
+qNuvkXQmcosz32uS/ZED7i9FWNXdAQrhsxZ/epSf8lelyHcLEPohO6p1ab1dpfWe
++X36GreoiUEnBEiSE1h5n7OWGR4ClJCfssu6q5gQ+2MRFCxVrh5CFJ4ZgT9tkc44
+7Q5TodP5Fcvz/hLhvaX8dtUCAwEAAQ==
+-----END PUBLIC KEY-----
diff --git a/certs/ldap/ldap.fripost.org.pem b/certs/ldap/ldap.fripost.org.pem
index f9d9e94..02b1237 100644
--- a/certs/ldap/ldap.fripost.org.pem
+++ b/certs/ldap/ldap.fripost.org.pem
@@ -1,31 +1,12 @@
-----BEGIN CERTIFICATE-----
-MIIFXzCCA0egAwIBAgIJALUdgbcP0QegMA0GCSqGSIb3DQEBCwUAME8xEDAOBgNV
-BAoTB0ZyaXBvc3QxETAPBgNVBAsTCFNTTGNlcnRzMQ0wCwYDVQQLEwRMREFQMRkw
-FwYDVQQDExBsZGFwLmZyaXBvc3Qub3JnMB4XDTE0MDkxMjE2NDM1NloXDTI0MDkw
-OTE2NDM1NlowTzEQMA4GA1UEChMHRnJpcG9zdDERMA8GA1UECxMIU1NMY2VydHMx
-DTALBgNVBAsTBExEQVAxGTAXBgNVBAMTEGxkYXAuZnJpcG9zdC5vcmcwggIiMA0G
-CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCqwdXg+Jst/vZ6NUPfT4DwXCwt7Xl4
-L2txiwGbpHqgC5B2ZcSePpoGCyT1CC7GsFCw+4qSDtB+7kDqDcomZsru1+n3onET
-YC7cSFzs6ks9PtpRMmnWC7184X0bUm6wkvpdJE8tlaqWzkt8S1RlGS/4g5bLKbmz
-ClYz/IrG68yPLWU9MHwlrV79Uf29mwLZGwK1PBV29QOiKDTp1KribRepjiO/bKVd
-+NIrHY8k7rdbZoe4z1Hp/SBdr7WyospSLwbJgNAFXPw/Nju9B/xEkQhDL+DkUR1X
-6JmIik1iAIxv3t1YgctL3Dyc8+RP0vjekrBWUYgRK9dBqia7Etmn7pGB19dqZe6g
-y30OsI9TcpW8Elqwg768QUCYZjwI2LN1SyR/et7hL3FQasjMjJOwqlT/PIQAJsLF
-CdqK+zZKBi/fNpdzJIb7TW7g4p8NJaICU0n9PMsoSdp4yi4n3OEYq6c8fKUuDF1i
-w8pCZE7SHW4qB1Vz5BgZjGmRk+MRzF48VigiZvL+WYoKEvNK7bhXQJ1DACc60j5h
-hrX5mleUANrhgwG72+m7gyZNCo2p15SausLup9ImyImZoQT88xRgz8txsDxe08Oa
-fO7z9dTuenY/tNVYHMkiJ/0RskOs7fDnSRpHzcwzWf1u4iEDS6lEbUWDdkyZ3XEP
-wLoBBaRhexm4mQIDAQABoz4wPDAcBgNVHREEFTATgRFhZG1pbkBmcmlwb3N0Lm9y
-ZzAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwICpDANBgkqhkiG9w0BAQsFAAOC
-AgEAglkIiXCYMajASIjJuVp8e3Eu+k3FKXvW7SPfga6SxcKUTmVPyzNAIVUWXxDq
-3nHArOEgrHW8ZAa9aFvLHKcUFOo9hmFZe+dxCXBK++XSyf2Au8PQ7B+8uznaC8/w
-JhSq+VarhItd3KMcW9ueG8YMCAxL7yahC0NQkMmwdecvdNB1gNRNnefvjhGIGFOJ
-Af5EPSckv+M6f4tFiX8EiabE4t4YW1yHHQ+6SStZL8vBJgT4OCeXaARirGAUiL7K
-xVR55ilO3dOdTEg7/+9ASNqygxtz53flnGltKfzt+QwzFK37WSBvGyp+tvmh6EE7
-XaqhBTYepWoiWJ2oRZsQet3QL4goCQGug0HFhYjW2sIl6TjlczuHXc3ynC6kkTD5
-8fhHNDt2bqXPfWmLqHXFP8RFapj+j/PzSXFH0JgllYGXtJufLXzGfN5Bg+6zpJSo
-COuZcoWw0e4BgNlc3gT8lKDqjK7zBoAVoxxvsOOaDB27T0sWwg3SERZXKD3xn7Jw
-vOIAWYkaQLonYuexW3KUX7OoG9d8HQAOyEkgoU0R6CfwGmK5VbGUQCFAwjF0VHqz
-9rKQrRB5+Oh4wK0dQhtU1m5IuxRrRyV7CX/n79vlBePdUIbDRWgJOvaSD125P+9l
-RHOSUOZ3tq6IltCLetUMM+qgDkVUFvRvXy2tev5ZBFUpJQs=
+MIIBvTCCAW+gAwIBAgIUHA3QvHLOo4JVBaYkVrDL9xv+sdMwBQYDK2VwME8xEDAO
+BgNVBAoMB0ZyaXBvc3QxETAPBgNVBAsMCFNTTGNlcnRzMQ0wCwYDVQQLDARMREFQ
+MRkwFwYDVQQDDBBsZGFwLmZyaXBvc3Qub3JnMB4XDTI0MDkwODE4MzMyM1oXDTM0
+MDkwNjE4MzMyM1owTzEQMA4GA1UECgwHRnJpcG9zdDERMA8GA1UECwwIU1NMY2Vy
+dHMxDTALBgNVBAsMBExEQVAxGTAXBgNVBAMMEGxkYXAuZnJpcG9zdC5vcmcwKjAF
+BgMrZXADIQAvg/MmR2tVDRb0MYcfQ8T9CMm6xNSWLt+2JDpXs7W0x6NdMFswHAYD
+VR0RBBUwE4ERYWRtaW5AZnJpcG9zdC5vcmcwDAYDVR0TAQH/BAIwADAOBgNVHQ8B
+Af8EBAMCBaAwHQYDVR0OBBYEFEJgdyZi8bgHZljJaUT/p8e8ZIWeMAUGAytlcANB
+APqO/lJ6WkT2rr8MG7kG+3IvBa7+KWKCmzV8ew9SoSF+enaCkNjOBtvW85W0lHBT
+i4DzFM0IxdgxgWIEP/NsrgQ=
-----END CERTIFICATE-----
diff --git a/certs/ldap/mx.pem b/certs/ldap/mx.pem
deleted file mode 100644
index 2e6275e..0000000
--- a/certs/ldap/mx.pem
+++ /dev/null
@@ -1,31 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIFaTCCA1GgAwIBAgIJAMFfcQJWxnoSMA0GCSqGSIb3DQEBCwUAMFQxEDAOBgNV
-BAoTB0ZyaXBvc3QxETAPBgNVBAsTCFNTTGNlcnRzMQ0wCwYDVQQLEwRMREFQMREw
-DwYDVQQLEwhTeW5jUmVwbDELMAkGA1UEAxMCbXgwHhcNMTQwOTEyMTY0MzM3WhcN
-MjQwOTA5MTY0MzM3WjBUMRAwDgYDVQQKEwdGcmlwb3N0MREwDwYDVQQLEwhTU0xj
-ZXJ0czENMAsGA1UECxMETERBUDERMA8GA1UECxMIU3luY1JlcGwxCzAJBgNVBAMT
-Am14MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEArdTG5Uh17j85iOs2
-8+92wHtIR/95ic3+E0Ao8KsWNXYduKLGGrLLAh7T9JPMK80M3gF32nZcbTD5pBuW
-NpuClezmCHtPN5ZtTMN6sRl3I/OGhu4vrOkfjOvRNTSByQo3ZC48rcgZbUPTzrCq
-+2eDc3R+TbllGhXB9JyZtM71nIix6c6vuERuj6uPQ64oonNWL5eVPH/Ww8wlTDzp
-Q69ATXQ92KoIILWllN7zqoU6ldVUyNswo0/wZsqDjxajh7s0qQwQLt7jMLV5JGNd
-kWvzyeMJMrmZj5C7Ch54usZh1gdOyf+ZnpnrhCERNOKpkxL59WOrglQPNiKMBZin
-MYVcpeCG3UdFaN59kuExUut8U3AVVflYuDfQIP9iHGdHKsBazqUTfqgLIZyWIMoe
-MdERazvRANPNHBMjIYYLlcWyjDch3k5iY1pyl8jskWi72F82XsiKMkr5H+tjFPve
-H3VaUCY2XNYNI8Ztvn6lifjvA+uVAI084pHZUDQkZFbT4LnLKY79d5IOwE1uXHtf
-6tUu8PHG9HeLZNiGex+kIPhg5gmQmipZwofbXX4xG0Km+3Dz2dWViOQri4n1s5xQ
-G1bWJtVmyDKEfDGF2ZiUZ+dAiih3qit1rTFZoiMqtNgEiahh/8R78Qx2xsCcu/76
-GLg/qh8r+lR1wMkWcoUbToIpARcCAwEAAaM+MDwwHAYDVR0RBBUwE4ERYWRtaW5A
-ZnJpcG9zdC5vcmcwDAYDVR0TAQH/BAIwADAOBgNVHQ8BAf8EBAMCAqQwDQYJKoZI
-hvcNAQELBQADggIBAGmCGK8Q32nc1Ltc3S2XCkbMzn4qfFKu1agEk2fBgU1qrVnx
-ioNWcct4trI8hwYwJ7QMQLx8ZdmuBbEyD60k9/qj+SCctrXnSA8p0SSCRUKgwyN0
-L14hvu+7P6G5VfPDNd+T1yqVMbMM2qgNYMHQDmf8e9IFa1DUSYks0v/3YdGwLSxj
-5IoIvc1JxBlGmgRGgG4z5a4v0ikuDc+XAEV0wWT2xF/7CuJnwglpedOgE+l7PLgU
-RQ4uPFQUnFUbcBBE+GLDxXxkOosD7GmAkvppaS8vwA+beqYX8LZMlCqqzXqk+3bp
-FCgQ6IARyYWchp/x4PFy1uGkU8PKsVO4xzQ15WuyaJCy3jqum9TfQUW/ZjRFT+3m
-sEgzarTxqP7CIlCHygVaDj2ALiaMjGbpHGA5JbwMFFaIuzVDj/DEJWKnxu5paJw1
-ERLBmZXhCqtveGmbI08RCMIZjlZ1xLAhFKGRQ4abDTfTlD4QU1EWh+NLHlSRTIg4
-Idbs9QDQH9Eb6p2+scEUL6ci2XGWRjet2wKdCPC3VMNwW/+pXG5YvrvHJBdx8V+F
-w0jWYOg4RQQuB/tAbucj1fvCnj2yMJPCsnlbeN4RPG/xF/89qlSey3kxUfma5eid
-m9kmjWPgXPgUQf+hmefL5HcN7M8zShTdSf81Xa0z3VqJENoQ4v4AqidEjVGY
------END CERTIFICATE-----
diff --git a/certs/ldap/syncrepl/mx@civett.pem b/certs/ldap/syncrepl/mx@civett.pem
new file mode 100644
index 0000000..430c3e6
--- /dev/null
+++ b/certs/ldap/syncrepl/mx@civett.pem
@@ -0,0 +1,12 @@
+-----BEGIN CERTIFICATE-----
+MIIBxzCCAXmgAwIBAgIUKkHGFnwdZ85QwHkb4cCfE8chdFEwBQYDK2VwMFQxEDAO
+BgNVBAoMB0ZyaXBvc3QxETAPBgNVBAsMCFNTTGNlcnRzMQ0wCwYDVQQLDARMREFQ
+MREwDwYDVQQLDAhTeW5jUmVwbDELMAkGA1UEAwwCbXgwHhcNMjQwOTA4MTgzNjU2
+WhcNMzQwOTA2MTgzNjU2WjBUMRAwDgYDVQQKDAdGcmlwb3N0MREwDwYDVQQLDAhT
+U0xjZXJ0czENMAsGA1UECwwETERBUDERMA8GA1UECwwIU3luY1JlcGwxCzAJBgNV
+BAMMAm14MCowBQYDK2VwAyEATR5gkOjpEYhG4e2fRjcowwSWkwLFjWHy1mGEjaru
+/jmjXTBbMBwGA1UdEQQVMBOBEWFkbWluQGZyaXBvc3Qub3JnMAwGA1UdEwEB/wQC
+MAAwDgYDVR0PAQH/BAQDAgWgMB0GA1UdDgQWBBSe9LYpYEdZNz7vx0Pe/LXFCJST
+PDAFBgMrZXADQQC0Isvso/VBCBrQx2uOVRUC8hZiKhKHX3SozqYGgrxlQBjxy8dZ
+cx3gsl4TGw/VWt80BSXQ+TqJHocjoyoy5/oE
+-----END CERTIFICATE-----
diff --git a/certs/ldap/syncrepl/mx@elefant.pem b/certs/ldap/syncrepl/mx@elefant.pem
new file mode 100644
index 0000000..bbd5f56
--- /dev/null
+++ b/certs/ldap/syncrepl/mx@elefant.pem
@@ -0,0 +1,12 @@
+-----BEGIN CERTIFICATE-----
+MIIBxzCCAXmgAwIBAgIUcwEP5HP6psC+HGMXHZBwf3Y/++UwBQYDK2VwMFQxEDAO
+BgNVBAoMB0ZyaXBvc3QxETAPBgNVBAsMCFNTTGNlcnRzMQ0wCwYDVQQLDARMREFQ
+MREwDwYDVQQLDAhTeW5jUmVwbDELMAkGA1UEAwwCbXgwHhcNMjQwOTA4MTgzNTIw
+WhcNMzQwOTA2MTgzNTIwWjBUMRAwDgYDVQQKDAdGcmlwb3N0MREwDwYDVQQLDAhT
+U0xjZXJ0czENMAsGA1UECwwETERBUDERMA8GA1UECwwIU3luY1JlcGwxCzAJBgNV
+BAMMAm14MCowBQYDK2VwAyEAp7jKBb1mYic6E+k7awOmDU2HVV+Ly9BNSqoWPmoG
+XhCjXTBbMBwGA1UdEQQVMBOBEWFkbWluQGZyaXBvc3Qub3JnMAwGA1UdEwEB/wQC
+MAAwDgYDVR0PAQH/BAQDAgWgMB0GA1UdDgQWBBQUeRpdKnUN37/2HJElOEgOiYNp
+IzAFBgMrZXADQQADKZwI8lJT+o2tuJD9tbAyjgJU72IxVRNsV8jkE3SEmI0E6w/3
+gf7T9BSPKe1Z23+Sc7Y5lKwHdxGp0Toao/UL
+-----END CERTIFICATE-----
diff --git a/certs/ssh_known_hosts b/certs/ssh_known_hosts
index 0eebead..d6918bc 100644
--- a/certs/ssh_known_hosts
+++ b/certs/ssh_known_hosts
@@ -1,7 +1,5 @@
antilop.fripost.org ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCmmS3Cs0ldlSEfgaL1ltfWpu2xA+1vj2pP5/zNp0aCdwqKoD/wYIa9T2kZKTzFC3J65v8E3fn/tRyDRolqhCeXWDrfBgJstLGH4ZpDMblbDjWnYmz6SY86TvE15BqWqrzDxDgcewHZlCmAxUETBgFNHSVyb1OXsfW4OmqLilbkTxY6v2QzKYzxfZTWOK2yGTO+dnT6dCN54CCItsbExLlDgqQhS/cTitL4MwpPOnMZ1cNiVyTwfDu8sFK/mDA2O+chgmplQemmuSLqnBKlcpnERcySQTetSX/bnZBvCVsDzg1tFn0Zg0PzgPCYauQMRgpk7J4jcv8P0VCK31ppuGsY4a+snvKiHUnFK7DRrJcnqSpRfwV1uL3t0khfBYiogl+zoQJ4G2yE2vKiFHVSe8LKSjgSOcnn4VwvqBNFARXMEF3Wvy72d9ZX+0kzbzp3r95vcWwqMeYDG9QEDI5lgENdhzxTcZD3Pn1hYxf862NO6UIBQW4uUhEI54QLb4bsjl/ZJ1l9KPB7bH4n58tizXlXweimzlJA+PeUzfA5BFhKjIiX9fJkVMcIFi84JmbjGMgw/B9VHewhblN+0Q8UO1PqDSlFIhE3NfWCI+1wMH2Um+zv/7M5aJYfZJvuPsvOx6D9lXOns8+kSNcdYdjkbOsgq+tdHG0eWkBuC7CRdmiKzw==
antilop.fripost.org ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJ6R2d9q2fFtu7P4Br7z141ccR8yhY+hgyi2ylNvrcgQ
-benjamin.skangas.se ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEArhPJlY+UhU0CILq7EBDLFpZFIemGJsW+d2euZyyYKbZppEtLQHIhXpiW8de1MErT3bkOeS8v8L8v0ZQLvlI/uN6i4yuTDPcf2qYTnoL4P5lzNLDIyNq6YRd26FId0M1A9YJz6t9mORb/Opb3Nq033iz40T2VJ1iJPHlCAcGOyjuxfcaiIrgPWPsKShQNdLkp5k3V0EnJoraB+bgvDfBBH5Cs4cab3EMeWBeZXB2rrICRyKZkm2dXFdDGp9UgujEQazWF0uXKMVZw1A4ZeTKc6GN66Icz5ceBTnJu38pI8ogreVyyKV5WNHeJBTpKhIT6vNQSeu98y1hrF6jIXPuQkw==
-benjamin.skangas.se ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN7Y77PUARUSb10sGZE4/W+ULh+0AFbzThQzBVspa7zS
civett.fripost.org,git.fripost.org ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCmlIwAthHdsufAedoBpABqvdrRI6HK7Rl02gC/ErEmtF1TvLsO2IbC2H0jEl8l6yL6eADkmQP9N7xQvpr8EH8v6AKiU6ufo3lih0Xv/OYtyVN2TdD9zzJ6Y0PxeiBaMRM0blMnfxwcfGe6Q61YQE2sbRnfUHINbEODVw5nMBxc7349x6qvsIeleL6cgEA7WWAZvDgucxXZv5IgTBT1amWDfZIadvzz6s5C6EnrGm/XrrVo7P8yD7tT3wcMFEW65S4tx9xE54Z3UydSstiJ+ZMDv4hJsZ6LYj9hgpMDWRiIZxiq/f2AoV87D54T7nSI4txkeXVPgaS7loxPtaJOzRo0prnV3yYuBq/8HaVhAOKTOK2SYFUUNay5BduxrfrQiRIqpL3uUIBA3kyVxR2YQ+FVPDHcve294CPvtTj5IYffMxJnQhkXCFSMgHYFUt9NSKqpq/9Ti3MImUtqgTq7oubwCDeltIKmiOUF9EHTM25ukmcJDvH+r5fyuOddB4/h2D/RJJ75SvKhJnz/H/pIhtYnEDaSEa3Xv9bk6KGj4Y3s49km3lcLOHE909ov0B2m1xFDT3pAiQ2v68hHrbbM/luA/sura5+Ic0mRIA9ZfsTCU1HvBAHM3AtItbrgNAvQfbPlvbZ/6hvlDW0L2CaWNSWO/mc3lcQS5UQC44T1/zkd4w==
civett.fripost.org,git.fripost.org ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINCKzoiQ3Ue81kQKl3t1mE2MDuS2ffVfNpNgTI0xKF5B
elefant.fripost.org ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDQnJ9OqxH1Xe49NYUfriyHs4mz05ECMLADT0VKNGkBAG67DzRL0QyEdBaKM7tUvgBeL9NdtXgt9OUBbCd9aDE45W2Y51r6A94TQqzRtEmlneprEWMuMKigXBpx/Y7l5XyocNvPFBgFM6l3mpoQEX13dJtCtEq/EvF/GGmAjYBUsG2LGbNZdotKyjWOtoSYZRCrON0xyUrQNt/JEw9RdmftHNqvaa04Kj17WZRAg2NT98rniIMhkMMkHr8ONE69YbomP/hfmnwjUb3VHbqSNPdhSdW3+WW1sBAe2+0UMsPurQ+qEO3c/sn0BUg+y+f2If7GVv8hSQP5GEixx9q0aVJ62MJfrXarZRPQWhN5CRcP2gWrUZEG/GnLDixzBid3cP8dEOAXBslZS7wP2GCLYqE9vj/hQ6Wl1kecMsKGEYKfll3GjtzYvi2F1HkdhxhzETw/d+sVk9plVRCHI758uIkXDrcULO5QXzOUGRdytS15IihbpJil4anh9mgqfxN9DpnZ9ZPeWnWfu2qpwjxTlylayHT0d4v+t9XqYI577jy0/9yxFbALYzDEzYxrbp7oh8YQ4olrgjtWaflwSnz1kYtOrl6n5cKYbwIGLv9mGFWyBurpU5aSnyuyzmUYDYciCO0/xjEtb1Xntne+Mb4tbZT8m9AlSv39yOQ0oYZySvrg4Q==
@@ -12,3 +10,4 @@ mistral.fripost.org ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCzGR8+jafHmXZF7b7DuOe8
mistral.fripost.org ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKtVVGS/t8LBTinXuDIlVthaOTq9fyP79j1nBOchF4A4
calima.fripost.org ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCWqe+XY9I+a4hemK5wIlwbqdDFC+jMP+nJ0SA5wX+5Lsu1sdj2FO4ziNZ0zluLA/YLyGawaqWhMWSBvDLtYa4KAv/kwzuc0Zifj6KfeBYhQnWaUZWIJp4y0KvZyaw1/QBYyea56j93zI4H0Ea9ay1jPL3kPTF9x8ynKNi34PhrEpXrXzvv9jrCgKwrwG1s5iqznzE5Rg0xJQIoKSOJXE+3xAbAA9ZGYtaFemMG+fcm67isGPYKS7DBmaMEsAQF0ri/qNsQOo7vMhw5lmYRNzehq74GL/njXzugp8cmClRGGk0YNWA0b9qfzHRYocX25OzAEQ1JE3b3cvctVeZcimqj
calima.fripost.org ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJbr+FgV+fnwbDsFJ/oiM79ku3V8N+SQwxuHxODIpsmk
+levante.fripost.org ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN5mdV1rI/3BUxsGracqSNhn/cywW1o7yyMewICka8+e
diff --git a/group_vars/all.yml b/group_vars/all.yml
index 4fcfc39..f780262 100644
--- a/group_vars/all.yml
+++ b/group_vars/all.yml
@@ -11,7 +11,7 @@ ipsec:
# Virtual (non-routable) addresses for IPsec. They all need to be
# distinct and belong to the above subnet 'ipsec_subnet'.
antilop: 172.16.0.1
- benjamin: 172.16.0.2
+ levante: 172.16.0.2
civett: 172.16.0.3
elefant: 172.16.0.4
giraff: 172.16.0.5
@@ -45,7 +45,7 @@ postfix_instance:
, addr: "{{ (groups.all | length > 1) | ternary( ipsec[ hostvars[groups.lists[0]].inventory_hostname_short ], '127.0.0.1') }}"
, port: 2527 }
-imapsvr_addr: "{{ postfix_instance.IMAP.addr | ipaddr }}"
+imapsvr_addr: "{{ postfix_instance.IMAP.addr | ansible.utils.ipaddr }}"
dkim_keys:
giraff:
@@ -55,6 +55,51 @@ dkim_keys:
d: fripost.org
# selector (randomly generated with `xxd -p -l16 </dev/urandom`)
s: 8f00fb94ec6c37aacb48bd43e073f9b7
+ "lists.fripost.org":
+ d: lists.fripost.org
+ s: d3df4ddda85e3c927621b1b02a9cbb85
+ "guilhem@debian.org":
+ d: debian.org
+ s: 5d30c523ff3622ed454230a16a11ddf6.guilhem.user
+ "guilhem.org":
+ d: guilhem.org
+ s: d32231afe345182ae1a9b376fa912dca
+ "guilhem.se":
+ d: guilhem.se
+ s: 138abf7e73c88d8dc67ca2d26881bc81
+ "hemdal.se":
+ d: hemdal.se
+ s: f032227401564da2cee5d5d0965969c4
+ "tevs.net":
+ d: tevs.net
+ s: 5fd8ba74ecb12069964e21a0ba90a516
+ "jakmedlem.se":
+ d: jakmedlem.se
+ s: 0ef2a7235861d65c872faf4e72b29a29
+ "gbg.cmsmarx.org":
+ d: gbg.cmsmarx.org
+ s: a4b2e822cfcf594acd24f44587590eb1
+ "r0x.se":
+ d: r0x.se
+ s: 79992d8659ce1c2d3f5a9ad20d167c15
+ "ljhms.se":
+ d: ljhms.se
+ s: 9552b222c0c258daf13bd410f6b5a159
+ "dubre.me":
+ d: dubre.me
+ s: aa813339234ce48d3b3bbfa334fbf48e
+ "himmelkanten.se":
+ d: himmelkanten.se
+ s: caf0355abffeda8264045c3730362147
+ "vimmelkanten.se":
+ d: vimmelkanten.se
+ s: ccb92aa8f79aa6d76b2a9d6ecf6b30e6
+ "hemskaklubben.se":
+ d: hemskaklubben.se
+ s: 564736f16aac6a05b50ea67fd6259e16
+ "kodafritt.se":
+ d: kodafritt.se
+ s: ce3283cc9129cb6692174bd2ec480b88
"~": # catch-all, for our virtual domains
d: x.fripost.org
s: 9df9cdc7e101629b5003b587945afa70
diff --git a/lib/action_plugins/fetch_cmd.py b/lib/action_plugins/fetch_cmd.py
index 57d7220..93960eb 100644
--- a/lib/action_plugins/fetch_cmd.py
+++ b/lib/action_plugins/fetch_cmd.py
@@ -50,7 +50,7 @@ class ActionModule(ActionBase):
local_checksum = checksum(dest)
# calculate checksum for the remote file, don't bother if using become as slurp will be used
- remote_checksum = self._remote_checksum(stdout, all_vars=task_vars)
+ remote_checksum = self._execute_remote_stat(stdout, all_vars=task_vars, follow=True).get('checksum')
if remote_checksum != local_checksum:
makedirs_safe(os.path.dirname(dest))
diff --git a/lib/modules/mysql_user2 b/lib/modules/mysql_user2
deleted file mode 100644
index dc9a69e..0000000
--- a/lib/modules/mysql_user2
+++ /dev/null
@@ -1,495 +0,0 @@
-#!/usr/bin/python3
-
-# (c) 2012, Mark Theunissen <mark.theunissen@gmail.com>
-# Sponsored by Four Kitchens http://fourkitchens.com.
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-
-DOCUMENTATION = '''
----
-module: mysql_user2
-short_description: Adds or removes a user from a MySQL database.
-description:
- - Adds or removes a user from a MySQL database.
-version_added: "0.6"
-options:
- name:
- description:
- - name of the user (role) to add or remove
- required: true
- default: null
- password:
- description:
- - set the user's password
- required: false
- default: null
- host:
- description:
- - the 'host' part of the MySQL username
- required: false
- default: localhost
- login_user:
- description:
- - The username used to authenticate with
- required: false
- default: null
- login_password:
- description:
- - The password used to authenticate with
- required: false
- default: null
- login_host:
- description:
- - Host running the database
- required: false
- default: localhost
- login_port:
- description:
- - Port of the MySQL server
- required: false
- default: 3306
- version_added: '1.4'
- login_unix_socket:
- description:
- - The path to a Unix domain socket for local connections
- required: false
- default: null
- priv:
- description:
- - "MySQL privileges string in the format: C(db.table:priv1,priv2)"
- required: false
- default: null
- append_privs:
- description:
- - Append the privileges defined by priv to the existing ones for this
- user instead of overwriting existing ones.
- required: false
- choices: [ "yes", "no" ]
- default: "no"
- version_added: "1.4"
- state:
- description:
- - Whether the user should exist. When C(absent), removes
- the user.
- required: false
- default: present
- choices: [ "present", "absent" ]
- check_implicit_admin:
- description:
- - Check if mysql allows login as root/nopassword before trying supplied credentials.
- required: false
- type: bool
- default: no
- version_added: "1.3"
-notes:
- - Requires the MySQLdb Python package on the remote host. For Ubuntu, this
- is as easy as apt-get install python-mysqldb.
- - Both C(login_password) and C(login_username) are required when you are
- passing credentials. If none are present, the module will attempt to read
- the credentials from C(~/.my.cnf), and finally fall back to using the MySQL
- default login of 'root' with no password.
- - "MySQL server installs with default login_user of 'root' and no password. To secure this user
- as part of an idempotent playbook, you must create at least two tasks: the first must change the root user's password,
- without providing any login_user/login_password details. The second must drop a ~/.my.cnf file containing
- the new root credentials. Subsequent runs of the playbook will then succeed by reading the new credentials from
- the file."
-
-requirements: [ "ConfigParser", "MySQLdb" ]
-author: Mark Theunissen
-'''
-
-EXAMPLES = """
-# Create database user with name 'bob' and password '12345' with all database privileges
-- mysql_user: name=bob password=12345 priv=*.*:ALL state=present
-
-# Ensure no user named 'sally' exists, also passing in the auth credentials.
-- mysql_user: login_user=root login_password=123456 name=sally state=absent
-
-# Example privileges string format
-mydb.*:INSERT,UPDATE/anotherdb.*:SELECT/yetanotherdb.*:ALL
-
-# Example using login_unix_socket to connect to server
-- mysql_user: name=root password=abc123 login_unix_socket=/var/run/mysqld/mysqld.sock
-
-# Example .my.cnf file for setting the root password
-# Note: don't use quotes around the password, because the mysql_user module
-# will include them in the password but the mysql client will not
-
-[client]
-user=root
-password=n<_665{vS43y
-"""
-
-import ConfigParser
-import getpass
-import tempfile
-try:
- import MySQLdb
-except ImportError:
- mysqldb_found = False
-else:
- mysqldb_found = True
-
-# ===========================================
-# MySQL module specific support methods.
-#
-
-def user_exists(cursor, user, host):
- cursor.execute("SELECT count(*) FROM user WHERE user = %s AND host = %s", (user,host))
- count = cursor.fetchone()
- return count[0] > 0
-
-def load_plugin(cursor, plugin, soname):
- cursor.execute("SELECT count(*) FROM information_schema.plugins WHERE plugin_name = %s", plugin)
- count = cursor.fetchone()
- if count[0] == 0:
- if soname is None:
- module.fail_json(msg="missing plugin 'soname' parameter")
- cursor.execute("INSTALL PLUGIN %s SONAME %s", (plugin, soname))
-
-def user_add(cursor, user, host, password, new_priv, auth_plugin, soname):
- if password is None:
- # Automatically loaded on first first use.
- load_plugin(cursor, auth_plugin, soname)
- cursor.execute("CREATE USER %s@%s IDENTIFIED WITH %s", (user,host,auth_plugin))
- else:
- cursor.execute("CREATE USER %s@%s IDENTIFIED BY %s", (user,host,password))
- if new_priv is not None:
- for db_table, priv in new_priv.iteritems():
- privileges_grant(cursor, user,host,db_table,priv)
- return True
-
-def user_mod(cursor, user, host, password, new_priv, append_privs, auth_plugin):
- changed = False
- grant_option = False
-
- # Handle plugin.
- if auth_plugin is not None:
- cursor.execute("SELECT plugin FROM user WHERE user = %s AND host = %s", (user,host))
- if cursor.fetchone()[0] != auth_plugin:
- # Sadly there is no proper way to updade the authentication plugin:
- # http://bugs.mysql.com/bug.php?id=67449
- cursor.execute( "UPDATE user SET plugin = %s, password = '' WHERE user = %s AND host = %s"
- , (auth_plugin,user,host))
- cursor.execute("FLUSH PRIVILEGES")
- changed = True
-
- # Handle passwords.
- if password is not None:
- cursor.execute("SELECT password FROM user WHERE user = %s AND host = %s", (user,host))
- current_pass_hash = cursor.fetchone()
- cursor.execute("SELECT PASSWORD(%s)", (password,))
- new_pass_hash = cursor.fetchone()
- if current_pass_hash[0] != new_pass_hash[0]:
- cursor.execute("SET PASSWORD FOR %s@%s = PASSWORD(%s)", (user,host,password))
- changed = True
-
- # Handle privileges.
- if new_priv is not None:
- curr_priv = privileges_get(cursor, user,host)
-
- # If the user has privileges on a db.table that doesn't appear at all in
- # the new specification, then revoke all privileges on it.
- for db_table, priv in curr_priv.iteritems():
- # If the user has the GRANT OPTION on a db.table, revoke it first.
- if "GRANT" in priv:
- grant_option = True
- if db_table not in new_priv:
- if user != "root" and "PROXY" not in priv and not append_privs:
- privileges_revoke(cursor, user,host,db_table,grant_option)
- changed = True
-
- # If the user doesn't currently have any privileges on a db.table, then
- # we can perform a straight grant operation.
- for db_table, priv in new_priv.iteritems():
- if db_table not in curr_priv:
- privileges_grant(cursor, user,host,db_table,priv)
- changed = True
-
- # If the db.table specification exists in both the user's current privileges
- # and in the new privileges, then we need to see if there's a difference.
- db_table_intersect = set(new_priv.keys()) & set(curr_priv.keys())
- for db_table in db_table_intersect:
- priv_diff = set(new_priv[db_table]) ^ set(curr_priv[db_table])
- if (len(priv_diff) > 0):
- privileges_revoke(cursor, user,host,db_table,grant_option)
- privileges_grant(cursor, user,host,db_table,new_priv[db_table])
- changed = True
-
- return changed
-
-def user_delete(cursor, user, host):
- cursor.execute("DROP USER %s@%s", (user,host))
- return True
-
-def privileges_get(cursor, user,host):
- """ MySQL doesn't have a better method of getting privileges aside from the
- SHOW GRANTS query syntax, which requires us to then parse the returned string.
- Here's an example of the string that is returned from MySQL:
-
- GRANT USAGE ON *.* TO 'user'@'localhost' IDENTIFIED BY 'pass';
-
- This function makes the query and returns a dictionary containing the results.
- The dictionary format is the same as that returned by privileges_unpack() below.
- """
- output = {}
- cursor.execute("SHOW GRANTS FOR %s@%s", (user,host))
- grants = cursor.fetchall()
-
- def pick(x):
- if x == 'ALL PRIVILEGES':
- return 'ALL'
- else:
- return x
-
- for grant in grants:
- res = re.match("GRANT (.+) ON (.+) TO '.+'@'.+'( IDENTIFIED BY PASSWORD '.+')? ?(.*)", grant[0])
- if res is None:
- module.fail_json(msg="unable to parse the MySQL grant string")
- privileges = res.group(1).split(", ")
- privileges = [ pick(x) for x in privileges]
- if "WITH GRANT OPTION" in res.group(4):
- privileges.append('GRANT')
- db = res.group(2)
- output[db] = privileges
- return output
-
-def privileges_unpack(priv):
- """ Take a privileges string, typically passed as a parameter, and unserialize
- it into a dictionary, the same format as privileges_get() above. We have this
- custom format to avoid using YAML/JSON strings inside YAML playbooks. Example
- of a privileges string:
-
- mydb.*:INSERT,UPDATE/anotherdb.*:SELECT/yetanother.*:ALL
-
- The privilege USAGE stands for no privileges, so we add that in on *.* if it's
- not specified in the string, as MySQL will always provide this by default.
- """
- output = {}
- for item in priv.split('/'):
- pieces = item.split(':')
- if pieces[0].find('.') != -1:
- pieces[0] = pieces[0].split('.')
- for idx, piece in enumerate(pieces):
- if pieces[0][idx] != "*":
- pieces[0][idx] = "`" + pieces[0][idx] + "`"
- pieces[0] = '.'.join(pieces[0])
-
- output[pieces[0]] = [ g.strip() for g in pieces[1].upper().split(',') ]
-
- if '*.*' not in output:
- output['*.*'] = ['USAGE']
-
- return output
-
-def privileges_revoke(cursor, user,host,db_table,grant_option):
- if grant_option:
- query = "REVOKE GRANT OPTION ON %s FROM '%s'@'%s'" % (db_table,user,host)
- cursor.execute(query)
- query = "REVOKE ALL PRIVILEGES ON %s FROM '%s'@'%s'" % (db_table,user,host)
- cursor.execute(query)
-
-def privileges_grant(cursor, user,host,db_table,priv):
-
- priv_string = ",".join(filter(lambda x: x != 'GRANT', priv))
- query = "GRANT %s ON %s TO '%s'@'%s'" % (priv_string,db_table,user,host)
- if 'GRANT' in priv:
- query = query + " WITH GRANT OPTION"
- cursor.execute(query)
-
-
-def strip_quotes(s):
- """ Remove surrounding single or double quotes
-
- >>> print strip_quotes('hello')
- hello
- >>> print strip_quotes('"hello"')
- hello
- >>> print strip_quotes("'hello'")
- hello
- >>> print strip_quotes("'hello")
- 'hello
-
- """
- single_quote = "'"
- double_quote = '"'
-
- if s.startswith(single_quote) and s.endswith(single_quote):
- s = s.strip(single_quote)
- elif s.startswith(double_quote) and s.endswith(double_quote):
- s = s.strip(double_quote)
- return s
-
-
-def config_get(config, section, option):
- """ Calls ConfigParser.get and strips quotes
-
- See: http://dev.mysql.com/doc/refman/5.0/en/option-files.html
- """
- return strip_quotes(config.get(section, option))
-
-
-def _safe_cnf_load(config, path):
-
- data = {'user':'', 'password':''}
-
- # read in user/pass
- f = open(path, 'r')
- for line in f.readlines():
- line = line.strip()
- if line.startswith('user='):
- data['user'] = line.split('=', 1)[1].strip()
- if line.startswith('password=') or line.startswith('pass='):
- data['password'] = line.split('=', 1)[1].strip()
- f.close()
-
- # write out a new cnf file with only user/pass
- fh, newpath = tempfile.mkstemp(prefix=path + '.')
- f = open(newpath, 'wb')
- f.write('[client]\n')
- f.write('user=%s\n' % data['user'])
- f.write('password=%s\n' % data['password'])
- f.close()
-
- config.readfp(open(newpath))
- os.remove(newpath)
- return config
-
-def load_mycnf():
- config = ConfigParser.RawConfigParser()
- mycnf = os.path.expanduser('~/.my.cnf')
- if not os.path.exists(mycnf):
- return False
- try:
- config.readfp(open(mycnf))
- except (IOError):
- return False
- except:
- config = _safe_cnf_load(config, mycnf)
-
- # We support two forms of passwords in .my.cnf, both pass= and password=,
- # as these are both supported by MySQL.
- try:
- passwd = config_get(config, 'client', 'password')
- except (ConfigParser.NoOptionError):
- try:
- passwd = config_get(config, 'client', 'pass')
- except (ConfigParser.NoOptionError):
- return False
-
- # If .my.cnf doesn't specify a user, default to user login name
- try:
- user = config_get(config, 'client', 'user')
- except (ConfigParser.NoOptionError):
- user = getpass.getuser()
- creds = dict(user=user,passwd=passwd)
- return creds
-
-def connect(module, login_user, login_password):
- if module.params["login_unix_socket"]:
- db_connection = MySQLdb.connect(host=module.params["login_host"], unix_socket=module.params["login_unix_socket"], user=login_user, passwd=login_password, db="mysql")
- else:
- db_connection = MySQLdb.connect(host=module.params["login_host"], port=int(module.params["login_port"]), user=login_user, passwd=login_password, db="mysql")
- return db_connection.cursor()
-
-# ===========================================
-# Module execution.
-#
-
-def main():
- module = AnsibleModule(
- argument_spec = dict(
- login_user=dict(default=None),
- login_password=dict(default=None, no_log=True),
- login_host=dict(default="localhost"),
- login_port=dict(default=3306, type='int'),
- login_unix_socket=dict(default=None),
- user=dict(required=True, aliases=['name']),
- password=dict(default=None, no_log=True, type='str'),
- host=dict(default="localhost"),
- state=dict(default="present", choices=["absent", "present"]),
- priv=dict(default=None),
- append_privs=dict(default=False, type="bool"),
- check_implicit_admin=dict(default=False, type="bool"),
- auth_plugin=dict(default=None),
- soname=dict(default=None)
- )
- )
- user = module.params["user"]
- password = module.params["password"]
- host = module.params["host"]
- state = module.params["state"]
- priv = module.params["priv"]
- check_implicit_admin = module.params['check_implicit_admin']
- append_privs = module.boolean(module.params["append_privs"])
- auth_plugin = module.params['auth_plugin']
- soname = module.params['soname']
-
- if not mysqldb_found:
- module.fail_json(msg="the python mysqldb module is required")
-
- if priv is not None:
- try:
- priv = privileges_unpack(priv)
- except:
- module.fail_json(msg="invalid privileges string")
-
- # Either the caller passes both a username and password with which to connect to
- # mysql, or they pass neither and allow this module to read the credentials from
- # ~/.my.cnf.
- login_password = module.params["login_password"]
- login_user = module.params["login_user"]
- if login_user is None and login_password is None:
- mycnf_creds = load_mycnf()
- if mycnf_creds is False:
- login_user = "root"
- login_password = ""
- else:
- login_user = mycnf_creds["user"]
- login_password = mycnf_creds["passwd"]
- elif login_password is None or login_user is None:
- module.fail_json(msg="when supplying login arguments, both login_user and login_password must be provided")
-
- cursor = None
- try:
- if check_implicit_admin:
- try:
- cursor = connect(module, 'root', '')
- except:
- pass
-
- if not cursor:
- cursor = connect(module, login_user, login_password)
- except Exception as e:
- module.fail_json(msg="unable to connect to database, check login_user and login_password are correct or ~/.my.cnf has the credentials")
-
- if state == "present":
- if user_exists(cursor, user, host):
- changed = user_mod(cursor, user, host, password, priv, append_privs, auth_plugin)
- else:
- if (password is None and auth_plugin is None) or (password is not None and auth_plugin is not None):
- module.fail_json(msg="password xor auth_plugin is required when adding a user")
- changed = user_add(cursor, user, host, password, priv, auth_plugin, soname)
- elif state == "absent":
- if user_exists(cursor, user, host):
- changed = user_delete(cursor, user, host)
- else:
- changed = False
- module.exit_json(changed=changed, user=user)
-
-# this is magic, see lib/ansible/module_common.py
-#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
-main()
diff --git a/lib/modules/openldap b/lib/modules/openldap
index 9afe1f1..f24a802 100644
--- a/lib/modules/openldap
+++ b/lib/modules/openldap
@@ -38,6 +38,7 @@ indexedAttributes = frozenset([
'olcOverlay',
'olcLimits',
'olcAuthzRegexp',
+ 'olcDlAttrSet',
'olcDbConfig',
])
@@ -49,10 +50,10 @@ indexedAttributes = frozenset([
# ('%s' in the attribute value is replaced with the value of the source
# entry.)
indexedDN = {
- 'olcSchemaConfig': [('cn', '{*}%s')],
- 'olcMdbConfig': [('olcDbDirectory', '%s' )],
- 'olcOverlayConfig': [('olcOverlay', '%s' )],
- 'olcMonitorConfig': [],
+ b'olcSchemaConfig': [('cn', '{*}%s')],
+ b'olcMdbConfig': [('olcDbDirectory', '%s' )],
+ b'olcOverlayConfig': [('olcOverlay', '%s' )],
+ b'olcMonitorConfig': [],
}
# Allow for flexible ACLs for user using SASL's EXTERNAL mechanism.
@@ -60,23 +61,23 @@ indexedDN = {
# "gidNumber=106+uidNumber=102,cn=peercred,cn=external,cn=auth" where
# 102 is postfix's UID and 106 its primary GID.
# (Regular expressions are not allowed.)
-sasl_ext_re = re.compile( r"""(?P<start>\sby\s+dn(?:\.exact)?)=
- (?P<quote>['\"]?)username=(?P<user>[a-z][-a-z0-9_]*),
+sasl_ext_re = re.compile( b"""(?P<start>\sby\s+dn(?:\.exact)?)=
+ (?P<quote>['\"]?)username=(?P<user>_?[a-z][-a-z0-9_]*),
(?P<end>cn=peercred,cn=external,cn=auth)
(?P=quote)\s"""
, re.VERBOSE )
-multispaces = re.compile( r"\s+" )
+multispaces = re.compile( b"\s+" )
pwd_dict = {}
def acl_sasl_ext(m):
- u = m.group('user')
+ u = m.group('user').decode("utf-8")
if u not in pwd_dict.keys():
pwd_dict[u] = pwd.getpwnam(u)
- return '%s="gidNumber=%d+uidNumber=%d,%s" ' % ( m.group('start')
- , pwd_dict[u].pw_gid
- , pwd_dict[u].pw_uid
- , m.group('end')
- )
+ return b'%s="gidNumber=%d+uidNumber=%d,%s" ' % ( m.group('start')
+ , pwd_dict[u].pw_gid
+ , pwd_dict[u].pw_uid
+ , m.group('end')
+ )
# Run the given callback on each DN seen. If its return value is not
@@ -109,14 +110,14 @@ def flexibleSearch(module, l, dn, entry):
scope = ldap.SCOPE_ONELEVEL
f = []
for c in idxClasses:
- f.append ( filter_format('objectClass=%s', [c]) )
+ f.append ( filter_format('objectClass=%s', [c.decode("utf-8")]) )
for a,v in indexedDN[c]:
if a == h:
v2 = t
elif a not in entry.keys() or len(entry[a]) > 1:
module.fail_json(msg="Multiple values found! This is a bug. Please report.")
else:
- v2 = entry[a][0]
+ v2 = entry[a][0].decode("utf-8")
f.append ( filter_format(a+'='+v, [v2]) )
if len(f) == 1:
f = f[0]
@@ -139,7 +140,7 @@ def processEntry(module, l, dn, entry):
for x in indexedAttributes.intersection(entry.keys()):
# remove useless extra spaces in ACLs etc
- entry[x] = list(map( partial(multispaces.sub, ' '), entry[x] ))
+ entry[x] = list(map( partial(multispaces.sub, b' '), entry[x] ))
r = flexibleSearch( module, l, dn, entry )
if r is None:
@@ -156,7 +157,8 @@ def processEntry(module, l, dn, entry):
d,e = r
fst = str2dn(dn).pop(0)[0][0]
diff = []
- for a,v in e.iteritems():
+ re1 = re.compile( b'^(\{[0-9]+\})', re.I )
+ for a,v in e.items():
if a not in entry.keys():
if a != fst:
# delete all values except for the first attribute,
@@ -168,11 +170,22 @@ def processEntry(module, l, dn, entry):
# by a DN with proper gidNumber and uidNumber
entry[a] = list(map ( partial(sasl_ext_re.sub, acl_sasl_ext)
, entry[a] ))
- # add explicit indices in the entry from the LDIF
- entry[a] = list(map( (lambda x: '{%d}%s' % x)
- , zip(range(len(entry[a])),entry[a])))
- if v != entry[a]:
- diff.append(( ldap.MOD_REPLACE, a, entry[a] ))
+ if a == fst:
+ if len(entry[a]) != 1 or len(v) != 1:
+ module.fail_json(msg=f'{len(entry[a])} != 1 or {len(v)} != 1')
+ m1 = re1.match(v[0])
+ if m1 is None:
+ module.fail_json(msg=f'{v[0]} is not indexed??')
+ else:
+ entry[a][0] = m1.group(1) + entry[a][0]
+ if entry[a] != v:
+ module.fail_json(msg=f'{entry[a]} != {v}, use modrdn to modifify the RDN (unimplemented)')
+ else:
+ # add explicit indices in the entry from the LDIF
+ entry[a] = list(map( (lambda x: b'{%d}%s' % x)
+ , zip(range(len(entry[a])),entry[a])))
+ if v != entry[a]:
+ diff.append(( ldap.MOD_REPLACE, a, entry[a] ))
elif v != entry[a]:
# for non-indexed attribute, we update values in the
# symmetric difference only
@@ -231,31 +244,31 @@ def getDN_DB(module, l, a, v, attrlist=['']):
# Convert a *.schema file into *.ldif format. The algorithm can be found
# in /etc/ldap/schema/openldap.ldif .
def slapd_to_ldif(src, name):
- s = open( src, 'r' )
+ s = open( src, 'rb' )
d = tempfile.NamedTemporaryFile(delete=False)
atexit.register(lambda: os.unlink( d.name ))
- d.write('dn: cn=%s,cn=schema,cn=config\n' % name)
- d.write('objectClass: olcSchemaConfig\n')
+ d.write(b'dn: cn=%s,cn=schema,cn=config\n' % name.encode("utf-8"))
+ d.write(b'objectClass: olcSchemaConfig\n')
- re1 = re.compile( r'^objectIdentifier\s(.*)', re.I )
- re2 = re.compile( r'^objectClass\s(.*)', re.I )
- re3 = re.compile( r'^attributeType\s(.*)', re.I )
- reSp = re.compile( r'^\s+' )
+ re1 = re.compile( b'^objectIdentifier\s(.*)', re.I )
+ re2 = re.compile( b'^objectClass\s(.*)', re.I )
+ re3 = re.compile( b'^attributeType\s(.*)', re.I )
+ reSp = re.compile( b'^\s+' )
for line in s.readlines():
- if line == '\n':
- line = '#\n'
+ if line == b'\n':
+ line = b'#\n'
m1 = re1.match(line)
m2 = re2.match(line)
m3 = re3.match(line)
if m1 is not None:
- line = 'olcObjectIdentifier: %s' % m1.group(1)
+ line = b'olcObjectIdentifier: %s' % m1.group(1)
elif m2 is not None:
- line = 'olcObjectClasses: %s' % m2.group(1)
+ line = b'olcObjectClasses: %s' % m2.group(1)
elif m3 is not None:
- line = 'olcAttributeTypes: %s' % m3.group(1)
+ line = b'olcAttributeTypes: %s' % m3.group(1)
- d.write( reSp.sub(line, ' ') )
+ d.write( reSp.sub(line, b' ') )
s.close()
diff --git a/lib/modules/postmulti b/lib/modules/postmulti
index 3c0a522..e6f58e3 100644
--- a/lib/modules/postmulti
+++ b/lib/modules/postmulti
@@ -30,7 +30,7 @@ def postconf(k, instance=None):
cmd.extend([ os.path.join(os.sep, 'usr', 'sbin', 'postconf')
, '-h', k ])
- return subprocess.check_output(cmd, stderr=subprocess.STDOUT).rstrip()
+ return subprocess.check_output(cmd, stderr=subprocess.STDOUT).rstrip().decode("utf-8")
# To destroy an existing instance:
@@ -55,7 +55,7 @@ def main():
enable = postconf('multi_instance_enable')
wrapper = postconf('multi_instance_wrapper')
- if enable != "yes" or not wrapper:
+ if enable != "yes" or wrapper == "":
# Initiate postmulti
changed = True
if module.check_mode:
diff --git a/production b/production
index ec655ab..970dafa 100644
--- a/production
+++ b/production
@@ -13,8 +13,8 @@ antilop.fripost.org geoip=se
[civett]
civett.fripost.org geoip=se mxno=2
-[benjamin]
-benjamin.skangas.se geoip=se
+[levante]
+levante.fripost.org geoip=se
[calima]
calima.fripost.org geoip=se
@@ -49,10 +49,10 @@ IMAP
giraff
[bacula_dir:children]
-benjamin
+levante
[bacula_sd:children]
-benjamin
+levante
# webmail.fripost.org
[webmail:children]
@@ -72,17 +72,19 @@ wiki
calima
[munin_master:children]
-benjamin
+levante
+[backports:children]
+
# machines behind NAT
[NATed:children]
-benjamin
+levante
# hostnames resolving to a dynamic IP
[DynDNS:children]
-benjamin
+levante
# need dhcp client
[dhclient:children]
-benjamin
+levante
diff --git a/roles/IMAP/files/etc/dovecot/conf.d/10-auth.conf b/roles/IMAP/files/etc/dovecot/conf.d/10-auth.conf
index 7213fbb..f34bdeb 100644
--- a/roles/IMAP/files/etc/dovecot/conf.d/10-auth.conf
+++ b/roles/IMAP/files/etc/dovecot/conf.d/10-auth.conf
@@ -10,7 +10,7 @@
#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.
+# bsdauth and PAM require cache_key to be set for caching to be used.
#auth_cache_size = 0
# Time to live for cached data. After TTL expires the cached record is no
# longer used, *except* if the main database lookup returns internal failure.
@@ -30,7 +30,7 @@
# Default realm/domain to use if none was specified. This is used for both
# SASL realms and appending @domain to username in plaintext logins.
-auth_default_realm = fripost.org
+#auth_default_realm =
# List of allowed characters in username. If the user-given username contains
# a character not listed in here, the login automatically fails. This is just
@@ -48,7 +48,7 @@ auth_default_realm = fripost.org
# the standard variables here, eg. %Lu would lowercase the username, %n would
# drop away the domain if it was given, or "%n-AT-%d" would change the '@' into
# "-AT-". This translation is done after auth_username_translation changes.
-auth_username_format = %Lu
+#auth_username_format = %Lu
# If you want to allow master users to log in by specifying the master
# username within the normal username string (ie. not using SASL mechanism's
@@ -73,7 +73,7 @@ auth_username_format = %Lu
# Kerberos keytab to use for the GSSAPI mechanism. Will use the system
# default (usually /etc/krb5.keytab) if not specified. You may need to change
# the auth service to run as root to be able to read this file.
-#auth_krb5_keytab =
+#auth_krb5_keytab =
# Do NTLM and GSS-SPNEGO authentication using Samba's winbind daemon and
# ntlm_auth helper. <doc/wiki/Authentication/Mechanisms/Winbind.txt>
@@ -88,16 +88,16 @@ auth_username_format = %Lu
# Require a valid SSL client certificate or the authentication fails.
#auth_ssl_require_client_cert = no
-# Take the username from client's SSL certificate, using
+# Take the username from client's SSL certificate, using
# X509_NAME_get_text_by_NID() which returns the subject's DN's
-# CommonName.
+# CommonName.
#auth_ssl_username_from_cert = no
# Space separated list of wanted authentication mechanisms:
-# plain login digest-md5 cram-md5 ntlm rpa apop anonymous gssapi otp skey
+# plain login digest-md5 cram-md5 ntlm rpa apop anonymous gssapi otp
# gss-spnego
# NOTE: See also disable_plaintext_auth setting.
-auth_mechanisms = plain login
+auth_mechanisms = plain
##
## Password and user databases
@@ -124,5 +124,4 @@ auth_mechanisms = plain login
!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/roles/IMAP/files/etc/dovecot/conf.d/10-logging.conf b/roles/IMAP/files/etc/dovecot/conf.d/10-logging.conf
deleted file mode 100644
index 848fe69..0000000
--- a/roles/IMAP/files/etc/dovecot/conf.d/10-logging.conf
+++ /dev/null
@@ -1,85 +0,0 @@
-##
-## Log destination.
-##
-
-# Log file to use for error messages. "syslog" logs to syslog,
-# /dev/stderr logs to stderr.
-#log_path = syslog
-
-# Log file to use for informational messages. Defaults to log_path.
-#info_log_path =
-# Log file to use for debug messages. Defaults to info_log_path.
-#debug_log_path =
-
-# Syslog facility to use if you're logging to syslog. Usually if you don't
-# want to use "mail", you'll use local0..local7. Also other standard
-# facilities are supported.
-#syslog_facility = mail
-
-##
-## Logging verbosity and debugging.
-##
-
-# Log unsuccessful authentication attempts and the reasons why they failed.
-#auth_verbose = no
-
-# In case of password mismatches, log the attempted password. Valid values are
-# no, plain and sha1. sha1 can be useful for detecting brute force password
-# attempts vs. user simply trying the same password over and over again.
-# You can also truncate the value to n chars by appending ":n" (e.g. sha1:6).
-#auth_verbose_passwords = no
-
-# Even more verbose logging for debugging purposes. Shows for example SQL
-# queries.
-#auth_debug = no
-
-# In case of password mismatches, log the passwords and used scheme so the
-# problem can be debugged. Enabling this also enables auth_debug.
-#auth_debug_passwords = no
-
-# Enable mail process debugging. This can help you figure out why Dovecot
-# isn't finding your mails.
-#mail_debug = no
-
-# Show protocol level SSL errors.
-#verbose_ssl = no
-
-# mail_log plugin provides more event logging for mail processes.
-plugin {
- # Events to log. Also available: flag_change append
- #mail_log_events = delete undelete expunge copy mailbox_delete mailbox_rename
- # Available fields: uid, box, msgid, from, subject, size, vsize, flags
- # size and vsize are available only for expunge and copy events.
- #mail_log_fields = uid box msgid size
-}
-
-##
-## Log formatting.
-##
-
-# Prefix for each line written to log file. % codes are in strftime(3)
-# format.
-log_timestamp = "%Y-%m-%d %H:%M:%S "
-
-# Space-separated list of elements we want to log. The elements which have
-# a non-empty variable value are joined together to form a comma-separated
-# string.
-#login_log_format_elements = user=<%u> method=%m rip=%r lip=%l mpid=%e %c
-
-# Login log format. %s contains login_log_format_elements string, %$ contains
-# the data we want to log.
-#login_log_format = %$: %s
-
-# Log prefix for mail processes. See doc/wiki/Variables.txt for list of
-# possible variables you can use.
-#mail_log_prefix = "%s(%u): "
-
-# Format to use for logging mail deliveries. See doc/wiki/Variables.txt for
-# list of all variables you can use. Some of the common ones include:
-# %$ - Delivery status message (e.g. "saved to INBOX")
-# %m - Message-ID
-# %s - Subject
-# %f - From address
-# %p - Physical size
-# %w - Virtual size
-#deliver_log_format = msgid=%m: %$
diff --git a/roles/IMAP/files/etc/dovecot/conf.d/10-mail.conf b/roles/IMAP/files/etc/dovecot/conf.d/10-mail.conf
deleted file mode 100644
index a781402..0000000
--- a/roles/IMAP/files/etc/dovecot/conf.d/10-mail.conf
+++ /dev/null
@@ -1,392 +0,0 @@
-##
-## Mailbox locations and namespaces
-##
-
-# Location for users' mailboxes. The default is empty, which means that Dovecot
-# tries to find the mailboxes automatically. This won't work if the user
-# doesn't yet have any mail, so you should explicitly tell Dovecot the full
-# location.
-#
-# If you're using mbox, giving a path to the INBOX file (eg. /var/mail/%u)
-# isn't enough. You'll also need to tell Dovecot where the other mailboxes are
-# kept. This is called the "root mail directory", and it must be the first
-# path given in the mail_location setting.
-#
-# There are a few special variables you can use, eg.:
-#
-# %u - username
-# %n - user part in user@domain, same as %u if there's no domain
-# %d - domain part in user@domain, empty if there's no domain
-# %h - home directory
-#
-# See doc/wiki/Variables.txt for full list. Some examples:
-#
-# mail_location = maildir:~/Maildir
-# mail_location = mbox:~/mail:INBOX=/var/mail/%u
-# mail_location = mbox:/var/mail/%d/%1n/%n:INDEX=/var/indexes/%d/%1n/%n
-#
-# <doc/wiki/MailLocation.txt>
-#
-mail_location = mdbox:~/mail
-
-# If you need to set multiple mailbox locations or want to change default
-# namespace settings, you can do it by defining namespace sections.
-#
-# You can have private, shared and public namespaces. Private namespaces
-# are for user's personal mails. Shared namespaces are for accessing other
-# users' mailboxes that have been shared. Public namespaces are for shared
-# mailboxes that are managed by sysadmin. If you create any shared or public
-# namespaces you'll typically want to enable ACL plugin also, otherwise all
-# users can access all the shared mailboxes, assuming they have permissions
-# on filesystem level to do so.
-namespace inbox {
- # Namespace type: private, shared or public
- #type = private
-
- # 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 = /
-
- # Prefix required to access this namespace. This needs to be different for
- # all namespaces. For example "Public/".
- #prefix =
-
- # Physical location of the mailbox. This is in same format as
- # mail_location, which is also the default for it.
- #location =
-
- # There can be only one INBOX, and this setting defines which namespace
- # has it.
- inbox = yes
-
- # If namespace is hidden, it's not advertised to clients via NAMESPACE
- # extension. You'll most likely also want to set list=no. This is mostly
- # useful when converting from another server with different namespaces which
- # you want to deprecate but still keep working. For example you can create
- # hidden namespaces with prefixes "~/mail/", "~%u/mail/" and "mail/".
- #hidden = no
-
- # Show the mailboxes under this namespace with LIST command. This makes the
- # namespace visible for clients that don't support NAMESPACE extension.
- # "children" value lists child mailboxes, but hides the namespace prefix.
- #list = yes
-
- # Namespace handles its own subscriptions. If set to "no", the parent
- # namespace handles them (empty prefix should always have this as "yes")
- #subscriptions = yes
-}
-
-namespace virtual {
- prefix = virtual/
- separator = /
- location = virtual:/etc/dovecot/virtual:INDEX=MEMORY
- list = no
- hidden = no
- subscriptions = no
-}
-
-# Example shared namespace configuration
-#namespace {
- #type = shared
- #separator = /
-
- # Mailboxes are visible under "shared/user@domain/"
- # %%n, %%d and %%u are expanded to the destination user.
- #prefix = shared/%%u/
-
- # Mail location for other users' mailboxes. Note that %variables and ~/
- # expands to the logged in user's data. %%n, %%d, %%u and %%h expand to the
- # destination user's data.
- #location = maildir:%%h/Maildir:INDEX=~/Maildir/shared/%%u
-
- # Use the default namespace for saving subscriptions.
- #subscriptions = no
-
- # List the shared/ namespace only if there are visible shared mailboxes.
- #list = children
-#}
-# Should shared INBOX be visible as "shared/user" or "shared/user/INBOX"?
-#mail_shared_explicit_inbox = no
-
-# System user and group used to access mails. If you use multiple, userdb
-# can override these by returning uid or gid fields. You can use either numbers
-# or names. <doc/wiki/UserIds.txt>
-mail_uid = vmail
-mail_gid = vmail
-
-# Group to enable temporarily for privileged operations. Currently this is
-# used only with INBOX when either its initial creation or dotlocking fails.
-# Typically this is set to "mail" to give access to /var/mail.
-#mail_privileged_group =
-
-# Grant access to these supplementary groups for mail processes. Typically
-# these are used to set up access to shared mailboxes. Note that it may be
-# dangerous to set these if users can create symlinks (e.g. if "mail" group is
-# set here, ln -s /var/mail ~/mail/var could allow a user to delete others'
-# mailboxes, or ln -s /secret/shared/box ~/mail/mybox would allow reading it).
-#mail_access_groups =
-
-# Allow full filesystem access to clients. There's no access checks other than
-# what the operating system does for the active UID/GID. It works with both
-# maildir and mboxes, allowing you to prefix mailboxes names with eg. /path/
-# or ~user/.
-#mail_full_filesystem_access = no
-
-# Dictionary for key=value mailbox attributes. This is used for example by
-# URLAUTH and METADATA extensions.
-#mail_attribute_dict =
-
-# A comment or note that is associated with the server. This value is
-# accessible for authenticated users through the IMAP METADATA server
-# entry "/shared/comment".
-mail_server_comment = "fripost - demokratisk e-post"
-
-# Indicates a method for contacting the server administrator. According to
-# RFC 5464, this value MUST be a URI (e.g., a mailto: or tel: URL), but that
-# 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 = mailto:postmaster@fripost.org
-
-##
-## Mail processes
-##
-
-# Don't use mmap() at all. This is required if you store indexes to shared
-# filesystems (NFS or clustered filesystem).
-#mmap_disable = no
-
-# Rely on O_EXCL to work when creating dotlock files. NFS supports O_EXCL
-# since version 3, so this should be safe to use nowadays by default.
-#dotlock_use_excl = yes
-
-# When to use fsync() or fdatasync() calls:
-# optimized (default): Whenever necessary to avoid losing important data
-# always: Useful with e.g. NFS when write()s are delayed
-# never: Never use it (best performance, but crashes can lose data)
-#mail_fsync = optimized
-
-# Locking method for index files. Alternatives are fcntl, flock and dotlock.
-# Dotlocking uses some tricks which may create more disk I/O than other locking
-# methods. NFS users: flock doesn't work, remember to change mmap_disable.
-#lock_method = fcntl
-
-# Directory in which LDA/LMTP temporarily stores incoming mails >128 kB.
-#mail_temp_dir = /tmp
-
-# Valid UID range for users, defaults to 500 and above. This is mostly
-# 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 = 1
-#last_valid_uid = 0
-
-# 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
-# belongs to supplementary groups with non-valid GIDs, those groups are
-# not set.
-#first_valid_gid = 1
-#last_valid_gid = 0
-
-# Maximum allowed length for mail keyword name. It's only forced when trying
-# to create new keywords.
-#mail_max_keyword_length = 50
-
-# ':' separated list of directories under which chrooting is allowed for mail
-# processes (ie. /var/mail will allow chrooting to /var/mail/foo/bar too).
-# This setting doesn't affect login_chroot, mail_chroot or auth chroot
-# settings. If this setting is empty, "/./" in home dirs are ignored.
-# WARNING: Never add directories here which local users can modify, that
-# may lead to root exploit. Usually this should be done only if you don't
-# allow shell access for users. <doc/wiki/Chrooting.txt>
-#valid_chroot_dirs =
-
-# Default chroot directory for mail processes. This can be overridden for
-# specific users in user database by giving /./ in user's home directory
-# (eg. /home/./user chroots into /home). Note that usually there is no real
-# need to do chrooting, Dovecot doesn't allow users to access files outside
-# their mail directory anyway. If your home directories are prefixed with
-# the chroot directory, append "/." to mail_chroot. <doc/wiki/Chrooting.txt>
-#mail_chroot =
-
-# UNIX socket path to master authentication server to find users.
-# This is used by imap (for shared users) and lda.
-#auth_socket_path = /var/run/dovecot/auth-userdb
-
-# Directory where to look up mail plugins.
-#mail_plugin_dir = /usr/lib/dovecot/modules
-
-# 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.
-mail_plugins = quota stats virtual zlib
-
-##
-## Mailbox handling optimizations
-##
-
-# Mailbox list indexes can be used to optimize IMAP STATUS commands. They are
-# also required for IMAP NOTIFY extension to be enabled.
-mailbox_list_index = yes
-
-# The minimum number of mails in a mailbox before updates are done to cache
-# file. This allows optimizing Dovecot's behavior to do less disk writes at
-# the cost of more disk reads.
-#mail_cache_min_mail_count = 0
-
-# When IDLE command is running, mailbox is checked once in a while to see if
-# there are any new mails or other changes. This setting defines the minimum
-# time to wait between those checks. Dovecot can also use inotify and
-# kqueue to find out immediately when changes occur.
-#mailbox_idle_check_interval = 30 secs
-
-# Save mails with CR+LF instead of plain LF. This makes sending those mails
-# take less CPU, especially with sendfile() syscall with Linux and FreeBSD.
-# But it also creates a bit more disk I/O which may just make it slower.
-# Also note that if other software reads the mboxes/maildirs, they may handle
-# the extra CRs wrong and cause problems.
-#mail_save_crlf = no
-
-# Max number of mails to keep open and prefetch to memory. This only works with
-# some mailbox formats and/or operating systems.
-#mail_prefetch_count = 0
-
-# How often to scan for stale temporary files and delete them (0 = never).
-# These should exist only after Dovecot dies in the middle of saving mails.
-#mail_temp_scan_interval = 1w
-
-##
-## Maildir-specific settings
-##
-
-# By default LIST command returns all entries in maildir beginning with a dot.
-# Enabling this option makes Dovecot return only entries which are directories.
-# This is done by stat()ing each entry, so it causes more disk I/O.
-# (For systems setting struct dirent->d_type, this check is free and it's
-# done always regardless of this setting)
-#maildir_stat_dirs = no
-
-# When copying a message, do it with hard links whenever possible. This makes
-# the performance much better, and it's unlikely to have any side effects.
-#maildir_copy_with_hardlinks = yes
-
-# Assume Dovecot is the only MUA accessing Maildir: Scan cur/ directory only
-# when its mtime changes unexpectedly or when we can't find the mail otherwise.
-#maildir_very_dirty_syncs = no
-
-# If enabled, Dovecot doesn't use the S=<size> in the Maildir filenames for
-# getting the mail's physical size, except when recalculating Maildir++ quota.
-# This can be useful in systems where a lot of the Maildir filenames have a
-# broken size. The performance hit for enabling this is very small.
-#maildir_broken_filename_sizes = no
-
-# Always move mails from new/ directory to cur/, even when the \Recent flags
-# aren't being reset.
-#maildir_empty_new = no
-
-##
-## mbox-specific settings
-##
-
-# Which locking methods to use for locking mbox. There are four available:
-# dotlock: Create <mailbox>.lock file. This is the oldest and most NFS-safe
-# solution. If you want to use /var/mail/ like directory, the users
-# will need write access to that directory.
-# dotlock_try: Same as dotlock, but if it fails because of permissions or
-# because there isn't enough disk space, just skip it.
-# fcntl : Use this if possible. Works with NFS too if lockd is used.
-# flock : May not exist in all systems. Doesn't work with NFS.
-# lockf : May not exist in all systems. Doesn't work with NFS.
-#
-# You can use multiple locking methods; if you do the order they're declared
-# in is important to avoid deadlocks if other MTAs/MUAs are using multiple
-# locking methods as well. Some operating systems don't allow using some of
-# them simultaneously.
-#
-# The Debian value for mbox_write_locks differs from upstream Dovecot. It is
-# changed to be compliant with Debian Policy (section 11.6) for NFS safety.
-# Dovecot: mbox_write_locks = dotlock fcntl
-# Debian: mbox_write_locks = fcntl dotlock
-#
-#mbox_read_locks = fcntl
-#mbox_write_locks = fcntl dotlock
-
-# Maximum time to wait for lock (all of them) before aborting.
-#mbox_lock_timeout = 5 mins
-
-# If dotlock exists but the mailbox isn't modified in any way, override the
-# lock file after this much time.
-#mbox_dotlock_change_timeout = 2 mins
-
-# When mbox changes unexpectedly we have to fully read it to find out what
-# changed. If the mbox is large this can take a long time. Since the change
-# is usually just a newly appended mail, it'd be faster to simply read the
-# new mails. If this setting is enabled, Dovecot does this but still safely
-# fallbacks to re-reading the whole mbox file whenever something in mbox isn't
-# how it's expected to be. The only real downside to this setting is that if
-# some other MUA changes message flags, Dovecot doesn't notice it immediately.
-# Note that a full sync is done with SELECT, EXAMINE, EXPUNGE and CHECK
-# commands.
-#mbox_dirty_syncs = yes
-
-# Like mbox_dirty_syncs, but don't do full syncs even with SELECT, EXAMINE,
-# EXPUNGE or CHECK commands. If this is set, mbox_dirty_syncs is ignored.
-#mbox_very_dirty_syncs = no
-
-# Delay writing mbox headers until doing a full write sync (EXPUNGE and CHECK
-# commands and when closing the mailbox). This is especially useful for POP3
-# where clients often delete all mails. The downside is that our changes
-# aren't immediately visible to other MUAs.
-#mbox_lazy_writes = yes
-
-# If mbox size is smaller than this (e.g. 100k), don't write index files.
-# If an index file already exists it's still read, just not updated.
-#mbox_min_index_size = 0
-
-# Mail header selection algorithm to use for MD5 POP3 UIDLs when
-# pop3_uidl_format=%m. For backwards compatibility we use apop3d inspired
-# algorithm, but it fails if the first Received: header isn't unique in all
-# mails. An alternative algorithm is "all" that selects all headers.
-#mbox_md5 = apop3d
-
-##
-## mdbox-specific settings
-##
-
-# Maximum dbox file size until it's rotated.
-#mdbox_rotate_size = 2M
-
-# Maximum dbox file age until it's rotated. Typically in days. Day begins
-# from midnight, so 1d = today, 2d = yesterday, etc. 0 = check disabled.
-#mdbox_rotate_interval = 0
-
-# When creating new mdbox files, immediately preallocate their size to
-# mdbox_rotate_size. This setting currently works only in Linux with some
-# filesystems (ext4, xfs).
-mdbox_preallocate_space = yes
-
-##
-## Mail attachments
-##
-
-# sdbox and mdbox support saving mail attachments to external files, which
-# also allows single instance storage for them. Other backends don't support
-# this for now.
-
-# Directory root where to store mail attachments. Disabled, if empty.
-mail_attachment_dir = /home/mail/attachments
-
-# Attachments smaller than this aren't saved externally. It's also possible to
-# write a plugin to disable saving specific attachments externally.
-#mail_attachment_min_size = 128k
-
-# Filesystem backend to use for saving attachments:
-# posix : No SiS done by Dovecot (but this might help FS's own deduplication)
-# sis posix : SiS with immediate byte-by-byte comparison during saving
-# sis-queue posix : SiS with delayed comparison and deduplication
-mail_attachment_fs = sis-queue /home/mail/attachments/queue:posix
-
-# Hash format to use in attachment filenames. You can add any text and
-# variables: %{md4}, %{md5}, %{sha1}, %{sha256}, %{sha512}, %{size}.
-# Variables can be truncated, e.g. %{sha256:80} returns only first 80 bits
-mail_attachment_hash = %{sha256}
diff --git a/roles/IMAP/files/etc/dovecot/conf.d/10-ssl.conf b/roles/IMAP/files/etc/dovecot/conf.d/10-ssl.conf
deleted file mode 100644
index 250eec5..0000000
--- a/roles/IMAP/files/etc/dovecot/conf.d/10-ssl.conf
+++ /dev/null
@@ -1,62 +0,0 @@
-##
-## SSL settings
-##
-
-# SSL/TLS support: yes, no, required. <doc/wiki/SSL.txt>
-ssl = required
-
-# PEM encoded X.509 SSL/TLS certificate and private key. They're opened before
-# 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 = </etc/dovecot/ssl/imap.fripost.org.pem
-ssl_key = </etc/dovecot/ssl/imap.fripost.org.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
-# world-readable, you may want to place this setting instead to a different
-# root owned 0600 file by using ssl_key_password = <path.
-#ssl_key_password =
-
-# PEM encoded trusted certificate authority. Set this only if you intend to use
-# ssl_verify_client_cert=yes. The file should contain the CA certificate(s)
-# followed by the matching CRL(s). (e.g. ssl_ca = </etc/ssl/certs/ca.pem)
-#ssl_ca =
-
-# Require that CRL check succeeds for client certificates.
-#ssl_require_crl = yes
-
-# Directory and/or file for trusted SSL CA certificates. These are used only
-# 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_file =
-
-# Request client to send a certificate. If you also want to require it, set
-# auth_ssl_require_client_cert=yes in auth section.
-#ssl_verify_client_cert = no
-
-# Which field from certificate to use for username. commonName and
-# x500UniqueIdentifier are the usual choices. You'll also need to set
-# auth_ssl_username_from_cert=yes.
-#ssl_cert_username_field = commonName
-
-# DH parameters length to use.
-ssl_dh_parameters_length = 2048
-
-# SSL protocols to use
-#ssl_protocols = !SSLv3
-
-# SSL ciphers to use
-ssl_cipher_list = HIGH:!aNULL:!eNULL:!3DES:!MD5:@STRENGTH
-
-# Prefer the server's order of ciphers over client's.
-#ssl_prefer_server_ciphers = no
-
-# SSL crypto device to use, for valid values run "openssl engine"
-#ssl_crypto_device =
-
-# SSL extra options. Currently supported options are:
-# no_compression - Disable compression.
-ssl_options = no_compression
diff --git a/roles/IMAP/files/etc/dovecot/conf.d/15-lda.conf b/roles/IMAP/files/etc/dovecot/conf.d/15-lda.conf
deleted file mode 100644
index 2a7bd27..0000000
--- a/roles/IMAP/files/etc/dovecot/conf.d/15-lda.conf
+++ /dev/null
@@ -1,48 +0,0 @@
-##
-## 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/postmulti -i msa -x /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
-}
diff --git a/roles/IMAP/files/etc/dovecot/conf.d/15-mailboxes.conf b/roles/IMAP/files/etc/dovecot/conf.d/15-mailboxes.conf
deleted file mode 100644
index 9c330be..0000000
--- a/roles/IMAP/files/etc/dovecot/conf.d/15-mailboxes.conf
+++ /dev/null
@@ -1,76 +0,0 @@
-##
-## Mailbox definitions
-##
-
-# Each mailbox is specified in a separate mailbox section. The section name
-# specifies the mailbox name. If it has spaces, you can put the name
-# "in quotes". These sections can contain the following mailbox settings:
-#
-# auto:
-# Indicates whether the mailbox with this name is automatically created
-# implicitly when it is first accessed. The user can also be automatically
-# subscribed to the mailbox after creation. The following values are
-# defined for this setting:
-#
-# no - Never created automatically.
-# create - Automatically created, but no automatic subscription.
-# subscribe - Automatically created and subscribed.
-#
-# special_use:
-# A space-separated list of SPECIAL-USE flags (RFC 6154) to use for the
-# mailbox. There are no validity checks, so you could specify anything
-# you want in here, but it's not a good idea to use flags other than the
-# standard ones specified in the RFC:
-#
-# \All - This (virtual) mailbox presents all messages in the
-# user's message store.
-# \Archive - This mailbox is used to archive messages.
-# \Drafts - This mailbox is used to hold draft messages.
-# \Flagged - This (virtual) mailbox presents all messages in the
-# user's message store marked with the IMAP \Flagged flag.
-# \Junk - This mailbox is where messages deemed to be junk mail
-# are held.
-# \Sent - This mailbox is used to hold copies of messages that
-# have been sent.
-# \Trash - This mailbox is used to hold messages that have been
-# deleted.
-#
-# comment:
-# Defines a default comment or note associated with the mailbox. This
-# value is accessible through the IMAP METADATA mailbox entries
-# "/shared/comment" and "/private/comment". Users with sufficient
-# privileges can override the default value for entries with a custom
-# value.
-
-# NOTE: Assumes "namespace inbox" has been defined in 10-mail.conf.
-namespace inbox {
- # These mailboxes are widely used and could perhaps be created automatically:
- mailbox Trash {
- auto = create
- special_use = \Trash
- }
- mailbox Drafts {
- auto = create
- special_use = \Drafts
- }
- mailbox Sent {
- auto = subscribe
- special_use = \Sent
- }
- mailbox Junk {
- auto = create
- special_use = \Junk
- }
-
- # If you have a virtual "All messages" mailbox:
- mailbox virtual/All {
- special_use = \All
- comment = All messages
- }
-
- # If you have a virtual "Flagged" mailbox:
- mailbox virtual/Flagged {
- special_use = \Flagged
- comment = All flagged messages
- }
-}
diff --git a/roles/IMAP/files/etc/dovecot/conf.d/20-imap.conf b/roles/IMAP/files/etc/dovecot/conf.d/20-imap.conf
deleted file mode 100644
index 3ddedce..0000000
--- a/roles/IMAP/files/etc/dovecot/conf.d/20-imap.conf
+++ /dev/null
@@ -1,85 +0,0 @@
-##
-## IMAP specific settings
-##
-
-# If nothing happens for this long while client is IDLEing, move the connection
-# to imap-hibernate process and close the old imap process. This saves memory,
-# because connections use very little memory in imap-hibernate process. The
-# downside is that recreating the imap process back uses some resources.
-imap_hibernate_timeout = 15s
-
-# Maximum IMAP command line length. Some clients generate very long command
-# lines with huge mailboxes, so you may need to raise this if you get
-# "Too long argument" or "IMAP command line too large" errors often.
-#imap_max_line_length = 64k
-
-# IMAP logout format string:
-# %i - total number of bytes read from client
-# %o - total number of bytes sent to client
-# %{fetch_hdr_count} - Number of mails with mail header data sent to client
-# %{fetch_hdr_bytes} - Number of bytes with mail header data sent to client
-# %{fetch_body_count} - Number of mails with mail body data sent to client
-# %{fetch_body_bytes} - Number of bytes with mail body data sent to client
-# %{deleted} - Number of mails where client added \Deleted flag
-# %{expunged} - Number of mails that client expunged
-# %{trashed} - Number of mails that client copied/moved to the
-# special_use=\Trash mailbox.
-#imap_logout_format = in=%i out=%o
-
-# Override the IMAP CAPABILITY response. If the value begins with '+',
-# add the given capabilities on top of the defaults (e.g. +XFOO XBAR).
-#imap_capability =
-
-# How long to wait between "OK Still here" notifications when client is
-# IDLEing.
-#imap_idle_notify_interval = 2 mins
-
-# ID field names and values to send to clients. Using * as the value makes
-# Dovecot use the default value. The following fields have default values
-# currently: name, version, os, os-version, support-url, support-email.
-#imap_id_send =
-
-# ID fields sent by client to log. * means everything.
-#imap_id_log =
-
-# Workarounds for various client bugs:
-# delay-newmail:
-# Send EXISTS/RECENT new mail notifications only when replying to NOOP
-# and CHECK commands. Some clients ignore them otherwise, for example OSX
-# Mail (<v2.1). Outlook Express breaks more badly though, without this it
-# may show user "Message no longer in server" errors. Note that OE6 still
-# breaks even with this workaround if synchronization is set to
-# "Headers Only".
-# tb-extra-mailbox-sep:
-# Thunderbird gets somehow confused with LAYOUT=fs (mbox and dbox) and
-# adds extra '/' suffixes to mailbox names. This option causes Dovecot to
-# ignore the extra '/' instead of treating it as invalid mailbox name.
-# tb-lsub-flags:
-# Show \Noselect flags for LSUB replies with LAYOUT=fs (e.g. mbox).
-# This makes Thunderbird realize they aren't selectable and show them
-# greyed out, instead of only later giving "not selectable" popup error.
-#
-# The list is space-separated.
-#imap_client_workarounds =
-
-# Host allowed in URLAUTH URLs sent by client. "*" allows all.
-#imap_urlauth_host =
-
-protocol imap {
- # Space separated list of plugins to load (default is global mail_plugins).
- mail_plugins = $mail_plugins imap_stats imap_zlib
-
- # Maximum number of IMAP connections allowed for a user from each IP address.
- # NOTE: The username is compared case-sensitively.
- mail_max_userip_connections = 16
-
-# # TODO Load the 'antispam' plugin for people using the content filter.
-# # (Otherwise fallback to the static userdb.)
-# userdb {
-# driver = ldap
-# args = /etc/dovecot/dovecot-ldap-userdb.conf.ext
-#
-# # Default fields can be used to specify defaults that LDAP may override
-# default_fields = home=/home/mail/virtual/%d/%n
-# }
-}
diff --git a/roles/IMAP/files/etc/dovecot/conf.d/20-lmtp.conf b/roles/IMAP/files/etc/dovecot/conf.d/20-lmtp.conf
deleted file mode 100644
index 8fc5fa0..0000000
--- a/roles/IMAP/files/etc/dovecot/conf.d/20-lmtp.conf
+++ /dev/null
@@ -1,27 +0,0 @@
-##
-## LMTP specific settings
-##
-
-# Support proxying to other LMTP/SMTP servers by performing passdb lookups.
-#lmtp_proxy = no
-
-# When recipient address includes the detail (e.g. user+detail), try to save
-# the mail to the detail mailbox. See also recipient_delimiter and
-# lda_mailbox_autocreate settings.
-#lmtp_save_to_detail_mailbox = no
-
-# Verify quota before replying to RCPT TO. This adds a small overhead.
-#lmtp_rcpt_check_quota = no
-
-# Which recipient address to use for Delivered-To: header and Received:
-# header. The default is "final", which is the same as the one given to
-# RCPT TO command. "original" uses the address given in RCPT TO's ORCPT
-# parameter, "none" uses nothing. Note that "none" is currently always used
-# when a mail has multiple recipients.
-#lmtp_hdr_delivery_address = final
-
-protocol lmtp {
- postmaster_address = postmaster@fripost.org
- # Space separated list of plugins to load (default is global mail_plugins).
- mail_plugins = $mail_plugins sieve
-}
diff --git a/roles/IMAP/files/etc/dovecot/conf.d/90-plugin.conf b/roles/IMAP/files/etc/dovecot/conf.d/90-plugin.conf
deleted file mode 100644
index 9583b6d..0000000
--- a/roles/IMAP/files/etc/dovecot/conf.d/90-plugin.conf
+++ /dev/null
@@ -1,33 +0,0 @@
-##
-## Plugin settings
-##
-
-# All wanted plugins must be listed in mail_plugins setting before any of the
-# settings take effect. See <doc/wiki/Plugins.txt> for list of plugins and
-# their configuration. Note that %variable expansion is done for all values.
-
-plugin {
- antispam_backend = spool2dir
-
- antispam_trash = Trash
- antispam_unsure_pattern_ignorecase = MailTrain;MailTrain/*
- antispam_spam = Junk
-
- # The first %%lu is replaced by the current time.
- # The second %%lu is replaced by a counter to generate unique names.
- # These two tokens MUST be present in the template!
- antispam_spool2dir_spam = /home/mail/spamspool/%u-%%10lu-%%06lu.spam
- antispam_spool2dir_notspam = /home/mail/spamspool/%u-%%10lu-%%06lu.ham
-
- quota_rule = *:storage=0
- quota = count:User quota
- quota_vsizes = yes
-
- # how often to session statistics
- stats_refresh = 30 secs
- # track per-IMAP command statistics
- stats_track_cmds = yes
-
- zlib_save = gz
- zlib_save_level = 6
-}
diff --git a/roles/IMAP/files/etc/dovecot/conf.d/90-sieve.conf b/roles/IMAP/files/etc/dovecot/conf.d/90-sieve.conf
deleted file mode 100644
index c1ff93e..0000000
--- a/roles/IMAP/files/etc/dovecot/conf.d/90-sieve.conf
+++ /dev/null
@@ -1,214 +0,0 @@
-##
-## Settings for the Sieve interpreter
-##
-
-# Do not forget to enable the Sieve plugin in 15-lda.conf and 20-lmtp.conf
-# by adding it to the respective mail_plugins= settings.
-
-# The Sieve interpreter can retrieve Sieve scripts from several types of
-# locations. The default `file' location type is a local filesystem path
-# pointing to a Sieve script file or a directory containing multiple Sieve
-# script files. More complex setups can use other location types such as
-# `ldap' or `dict' to fetch Sieve scripts from remote databases.
-#
-# All settings that specify the location of one ore more Sieve scripts accept
-# the following syntax:
-#
-# location = [<type>:]path[;<option>[=<value>][;...]]
-#
-# If the type prefix is omitted, the script location type is 'file' and the
-# location is interpreted as a local filesystem path pointing to a Sieve script
-# file or directory. Refer to Pigeonhole wiki or INSTALL file for more
-# information.
-
-plugin {
- # The location of the user's main Sieve script or script storage. The LDA
- # Sieve plugin uses this to find the active script for Sieve filtering at
- # delivery. The "include" extension uses this location for retrieving
- # :personal" scripts. This is also where the ManageSieve service will store
- # the user's scripts, if supported.
- #
- # Currently only the 'file:' location type supports ManageSieve operation.
- # Other location types like 'dict:' and 'ldap:' can currently only
- # be used as a read-only script source ().
- #
- # For the 'file:' type: use the ';active=' parameter to specify where the
- # active script symlink is located.
- # For other types: use the ';name=' parameter to specify the name of the
- # default/active script.
- sieve = file:~/sieve;active=~/dovecot.sieve
-
- # The default Sieve script when the user has none. This is the location of a
- # global sieve script file, which gets executed ONLY if user's personal Sieve
- # script doesn't exist. Be sure to pre-compile this script manually using the
- # sievec command line tool if the binary is not stored in a global location.
- # --> See sieve_before for executing scripts before the user's personal
- # script.
- #sieve_default = /var/lib/dovecot/sieve/default.sieve
-
- # The name by which the default Sieve script (as configured by the
- # sieve_default setting) is visible to the user through ManageSieve.
- #sieve_default_name =
-
- # Location for ":global" include scripts as used by the "include" extension.
- #sieve_global =
-
- # The location of a Sieve script that is run for any message that is about to
- # be discarded; i.e., it is not delivered anywhere by the normal Sieve
- # execution. This only happens when the "implicit keep" is canceled, by e.g.
- # the "discard" action, and no actions that deliver the message are executed.
- # This "discard script" can prevent discarding the message, by executing
- # alternative actions. If the discard script does nothing, the message is
- # still discarded as it would be when no discard script is configured.
- #sieve_discard =
-
- # Location Sieve of scripts that need to be executed before the user's
- # personal script. If a 'file' location path points to a directory, all the
- # Sieve scripts contained therein (with the proper `.sieve' extension) are
- # executed. The order of execution within that directory is determined by the
- # file names, using a normal 8bit per-character comparison.
- #
- # Multiple script locations can be specified by appending an increasing number
- # to the setting name. The Sieve scripts found from these locations are added
- # to the script execution sequence in the specified order. Reading the
- # numbered sieve_before settings stops at the first missing setting, so no
- # numbers may be skipped.
- #sieve_before = /var/lib/dovecot/sieve.d/
- #sieve_before2 = ldap:/etc/sieve-ldap.conf;name=ldap-domain
- #sieve_before3 = (etc...)
-
- # Identical to sieve_before, only the specified scripts are executed after the
- # user's script (only when keep is still in effect!). Multiple script
- # locations can be specified by appending an increasing number.
- #sieve_after =
- #sieve_after2 =
- #sieve_after2 = (etc...)
-
- # Which Sieve language extensions are available to users. By default, all
- # supported extensions are available, except for deprecated extensions or
- # those that are still under development. Some system administrators may want
- # to disable certain Sieve extensions or enable those that are not available
- # by default. This setting can use '+' and '-' to specify differences relative
- # to the default. For example `sieve_extensions = +imapflags' will enable the
- # deprecated imapflags extension in addition to all extensions were already
- # enabled by default.
- sieve_extensions = +editheader
-
- # Which Sieve language extensions are ONLY available in global scripts. This
- # can be used to restrict the use of certain Sieve extensions to administrator
- # control, for instance when these extensions can cause security concerns.
- # This setting has higher precedence than the `sieve_extensions' setting
- # (above), meaning that the extensions enabled with this setting are never
- # available to the user's personal script no matter what is specified for the
- # `sieve_extensions' setting. The syntax of this setting is similar to the
- # `sieve_extensions' setting, with the difference that extensions are
- # enabled or disabled for exclusive use in global scripts. Currently, no
- # extensions are marked as such by default.
- #sieve_global_extensions =
-
- # The Pigeonhole Sieve interpreter can have plugins of its own. Using this
- # setting, the used plugins can be specified. Check the Dovecot wiki
- # (wiki2.dovecot.org) or the pigeonhole website
- # (http://pigeonhole.dovecot.org) for available plugins.
- # The sieve_extprograms plugin is included in this release.
- #sieve_plugins =
-
- # The separator that is expected between the :user and :detail
- # address parts introduced by the subaddress extension. This may
- # also be a sequence of characters (e.g. '--'). The current
- # implementation looks for the separator from the left of the
- # localpart and uses the first one encountered. The :user part is
- # left of the separator and the :detail part is right. This setting
- # is also used by Dovecot's LMTP service.
- recipient_delimiter = +
-
- # The maximum size of a Sieve script. The compiler will refuse to compile any
- # script larger than this limit. If set to 0, no limit on the script size is
- # enforced.
- #sieve_max_script_size = 1M
-
- # The maximum number of actions that can be performed during a single script
- # execution. If set to 0, no limit on the total number of actions is enforced.
- #sieve_max_actions = 32
-
- # The maximum number of redirect actions that can be performed during a single
- # script execution. If set to 0, no redirect actions are allowed.
- #sieve_max_redirects = 4
-
- # The maximum number of personal Sieve scripts a single user can have. If set
- # to 0, no limit on the number of scripts is enforced.
- # (Currently only relevant for ManageSieve)
- #sieve_quota_max_scripts = 0
-
- # The maximum amount of disk storage a single user's scripts may occupy. If
- # set to 0, no limit on the used amount of disk storage is enforced.
- # (Currently only relevant for ManageSieve)
- #sieve_quota_max_storage = 0
-
- # The primary e-mail address for the user. This is used as a default when no
- # other appropriate address is available for sending messages. If this setting
- # is not configured, either the postmaster or null "<>" address is used as a
- # sender, depending on the action involved. This setting is important when
- # there is no message envelope to extract addresses from, such as when the
- # script is executed in IMAP.
- #sieve_user_email =
-
- # The path to the file where the user log is written. If not configured, a
- # default location is used. If the main user's personal Sieve (as configured
- # with sieve=) is a file, the logfile is set to <filename>.log by default. If
- # it is not a file, the default user log file is ~/.dovecot.sieve.log.
- #sieve_user_log =
-
- # Specifies what envelope sender address is used for redirected messages.
- # The following values are supported for this setting:
- #
- # "sender" - The sender address is used (default).
- # "recipient" - The final recipient address is used.
- # "orig_recipient" - The original recipient is used.
- # "user_email" - The user's primary address is used. This is
- # configured with the "sieve_user_email" setting. If
- # that setting is unconfigured, "user_mail" is equal to
- # "recipient".
- # "postmaster" - The postmaster_address configured for the LDA.
- # "<user@domain>" - Redirected messages are always sent from user@domain.
- # The angle brackets are mandatory. The null "<>" address
- # is also supported.
- #
- # This setting is ignored when the envelope sender is "<>". In that case the
- # sender of the redirected message is also always "<>".
- #sieve_redirect_envelope_from = sender
-
- ## TRACE DEBUGGING
- # Trace debugging provides detailed insight in the operations performed by
- # the Sieve script. These settings apply to both the LDA Sieve plugin and the
- # IMAPSIEVE plugin.
- #
- # WARNING: On a busy server, this functionality can quickly fill up the trace
- # directory with a lot of trace files. Enable this only temporarily and as
- # selective as possible.
-
- # The directory where trace files are written. Trace debugging is disabled if
- # this setting is not configured or if the directory does not exist. If the
- # path is relative or it starts with "~/" it is interpreted relative to the
- # current user's home directory.
- #sieve_trace_dir =
-
- # The verbosity level of the trace messages. Trace debugging is disabled if
- # this setting is not configured. Possible values are:
- #
- # "actions" - Only print executed action commands, like keep,
- # fileinto, reject and redirect.
- # "commands" - Print any executed command, excluding test commands.
- # "tests" - Print all executed commands and performed tests.
- # "matching" - Print all executed commands, performed tests and the
- # values matched in those tests.
- #sieve_trace_level =
-
- # Enables highly verbose debugging messages that are usually only useful for
- # developers.
- #sieve_trace_debug = no
-
- # Enables showing byte code addresses in the trace output, rather than only
- # the source line numbers.
- #sieve_trace_addresses = no
-}
diff --git a/roles/IMAP/files/etc/dovecot/dovecot-dict-auth.conf.ext b/roles/IMAP/files/etc/dovecot/dovecot-dict-auth.conf.ext
index ecd7134..a054ffe 100644
--- a/roles/IMAP/files/etc/dovecot/dovecot-dict-auth.conf.ext
+++ b/roles/IMAP/files/etc/dovecot/dovecot-dict-auth.conf.ext
@@ -2,7 +2,7 @@
# conf.d/auth-dict.conf.ext
# Dictionary URI
-uri = proxy:/var/run/dovecot/auth-proxy:
+uri = proxy:/run/dovecot/auth-proxy:
# Username iteration prefix. Keys under this are assumed to contain usernames.
iterate_prefix = userdb/
diff --git a/roles/IMAP/files/etc/dovecot/dovecot-ldap.conf.ext b/roles/IMAP/files/etc/dovecot/dovecot-ldap.conf.ext
index 1b97a0e..a455616 100644
--- a/roles/IMAP/files/etc/dovecot/dovecot-ldap.conf.ext
+++ b/roles/IMAP/files/etc/dovecot/dovecot-ldap.conf.ext
@@ -130,7 +130,7 @@ pass_attrs =
#pass_attrs = uid=user,userPassword=password,\
# homeDirectory=userdb_home,uidNumber=userdb_uid,gidNumber=userdb_gid
-# Filter for password lookups (ignored for auth binds)
+# Filter for password lookups
pass_filter = (&(objectClass=FripostVirtualUser)(fvl=%n)(fripostIsStatusActive=TRUE))
# Attributes and filter to get a list of all users
@@ -140,3 +140,12 @@ pass_filter = (&(objectClass=FripostVirtualUser)(fvl=%n)(fripostIsStatusActive=T
# Default password scheme. "{scheme}" before password overrides this.
# List of supported schemes is in: http://wiki2.dovecot.org/Authentication
#default_pass_scheme = CRYPT
+
+# By default all LDAP lookups are performed by the auth master process.
+# If blocking=yes, auth worker processes are used to perform the lookups.
+# Each auth worker process creates its own LDAP connection so this can
+# increase parallelism. With blocking=no the auth master process can
+# keep 8 requests pipelined for the LDAP connection, while with blocking=yes
+# each connection has a maximum of 1 request running. For small systems the
+# blocking=no is sufficient and uses less resources.
+#blocking = no
diff --git a/roles/IMAP/files/etc/dovecot/ssl/config b/roles/IMAP/files/etc/dovecot/ssl/config
new file mode 100644
index 0000000..e5359de
--- /dev/null
+++ b/roles/IMAP/files/etc/dovecot/ssl/config
@@ -0,0 +1,2 @@
+ssl_cert = </etc/dovecot/ssl/imap.fripost.org.pem
+ssl_key = </etc/dovecot/ssl/imap.fripost.org.key
diff --git a/roles/IMAP/files/etc/systemd/system/dovecot-auth-proxy.service b/roles/IMAP/files/etc/systemd/system/dovecot-auth-proxy.service
index d20f9c2..3ac0b31 100644
--- a/roles/IMAP/files/etc/systemd/system/dovecot-auth-proxy.service
+++ b/roles/IMAP/files/etc/systemd/system/dovecot-auth-proxy.service
@@ -4,8 +4,7 @@ After=dovecot.target
Requires=dovecot-auth-proxy.socket
[Service]
-User=vmail
-Group=vmail
+User=_dovecot-auth-proxy
StandardInput=null
SyslogFacility=mail
ExecStart=/usr/local/bin/dovecot-auth-proxy.pl
@@ -13,14 +12,13 @@ ExecStart=/usr/local/bin/dovecot-auth-proxy.pl
# Hardening
NoNewPrivileges=yes
PrivateDevices=yes
-ProtectSystem=strict
-ProtectHome=read-only
-PrivateDevices=yes
PrivateNetwork=yes
+ProtectHome=yes
+ProtectSystem=strict
ProtectControlGroups=yes
ProtectKernelModules=yes
ProtectKernelTunables=yes
-RestrictAddressFamilies=
+RestrictAddressFamilies=AF_UNIX
[Install]
WantedBy=multi-user.target
diff --git a/roles/IMAP/files/usr/local/bin/dovecot-auth-proxy.pl b/roles/IMAP/files/usr/local/bin/dovecot-auth-proxy.pl
index 5b2c74e..39d3762 100755
--- a/roles/IMAP/files/usr/local/bin/dovecot-auth-proxy.pl
+++ b/roles/IMAP/files/usr/local/bin/dovecot-auth-proxy.pl
@@ -1,8 +1,8 @@
-#!/usr/bin/perl
+#!/usr/bin/perl -T
#----------------------------------------------------------------------
# Dovecot userdb lookup proxy table for user iteration
-# Copyright © 2017 Guilhem Moulin <guilhem@fripost.org>
+# Copyright © 2017,2020 Guilhem Moulin <guilhem@fripost.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -21,14 +21,22 @@
use warnings;
use strict;
-use Errno 'EINTR';
+use Errno qw/EINTR/;
+use Net::LDAPI;
+use Net::LDAP::Constant qw/LDAP_CONTROL_PAGED LDAP_SUCCESS/;
+use Net::LDAP::Control::Paged ();
+use Net::LDAP::Util qw/ldap_explode_dn/;
+use Authen::SASL;
+
+my $BASE = "ou=virtual,dc=fripost,dc=org";
# clean up PATH
$ENV{PATH} = join ':', qw{/usr/bin /bin};
delete @ENV{qw/IFS CDPATH ENV BASH_ENV/};
-# number of pre-forked servers
+# number of pre-forked servers and maximum requests per worker
my $nProc = 1;
+my $maxRequests = 1;
sub server();
# fdopen(3) the file descriptor FD
@@ -37,12 +45,6 @@ die "This service must be socket-activated.\n"
and defined $ENV{LISTEN_FDS} and $ENV{LISTEN_FDS} == 1;
open my $S, '+<&=', 3 or die "fdopen: $!";
-do {
- my $dir = (getpwnam('vmail'))[7] // die "No such user: vmail";
- $dir .= '/virtual';
- chdir($dir) or die "chdir($dir): $!";
-};
-
my @CHILDREN;
for (my $i = 0; $i < $nProc-1; $i++) {
my $pid = fork() // die "fork: $!";
@@ -61,7 +63,7 @@ exit $?;
#############################################################################
sub server() {
- for (my $n = 0; $n < 1; $n++) {
+ for (my $n = 0; $n < $maxRequests; $n++) {
accept(my $conn, $S) or do {
next if $! == EINTR;
die "accept: $!";
@@ -74,7 +76,7 @@ sub server() {
next;
}
# <major-version> <minor-version> <value type>
- unless ($1 == 2 and $2 == 1 and $3 == 0) {
+ unless ($1 == 2 and $2 == 2 and $3 == 0) {
warn "Unsupported protocol version $1.$2 (or value type $3)\n";
close $conn or warn "Can't close: $!";
next;
@@ -94,10 +96,20 @@ sub server() {
sub fail($;$) {
my ($fh, $msg) = @_;
$fh->printflush("F\n");
- warn "$msg\n" if defined $msg;
+ print STDERR $msg, "\n" if defined $msg;
}
-# list all users, even the inactive ones
+sub dn2user($) {
+ my $dn = shift;
+ $dn = ldap_explode_dn($dn, casefold => "lower");
+ if (defined $dn and $#$dn == 4
+ and defined (my $l = $dn->[0]->{fvl})
+ and defined (my $d = $dn->[1]->{fvd})) {
+ return $l ."@". $d;
+ }
+}
+
+# list all users (even the inactive ones)
sub iterate($$$$) {
my ($fh, $flags, $max_rows, $prefix) = @_;
unless ($flags == 0) {
@@ -105,27 +117,55 @@ sub iterate($$$$) {
return;
}
- opendir my $dh, '.' or do {
- fail($fh => "opendir: $!");
- return;
- };
- my $count = 0;
- while (defined (my $d = readdir $dh)) {
- next if $d eq '.' or $d eq '..';
- opendir my $dh, $d or do {
- fail($fh => "opendir: $!");
- return;
- };
- while (defined (my $l = readdir $dh) and ($max_rows <= 0 or $count < $max_rows)) {
- next if $l eq '.' or $l eq '..';
- my $user = $l.'@'.$d;
- next unless $user =~ /\A[a-zA-Z0-9\.\-_@]+\z/; # skip invalid user names
+ my $ldap = Net::LDAPI::->new();
+ $ldap->bind( undef, sasl => Authen::SASL::->new(mechanism => "EXTERNAL") )
+ or do { fail($fh => "Error: Couldn't bind"); return; };
+ my $page = Net::LDAP::Control::Paged::->new(size => 100);
+
+ my $callback = sub($$) {
+ my ($mesg, $entry) = @_;
+ return unless defined $entry;
+
+ my $dn = $entry->dn();
+ if (defined (my $user = dn2user($dn))) {
$fh->printf("O%s%s\t\n", $prefix, $user);
- $count++;
+ } else {
+ print STDERR "Couldn't extract username from dn: ", $dn, "\n";
}
- closedir $dh or warn "closedir: $!";
+ $mesg->pop_entry;
+ };
+
+ my @search_args = (
+ base => $BASE,
+ , scope => "children"
+ , deref => "never"
+ , filter => "(objectClass=FripostVirtualUser)"
+ , sizelimit => $max_rows
+ , control => [$page]
+ , callback => $callback
+ , attrs => ["1.1"]
+ );
+
+ my $cookie;
+ while (1) {
+ my $mesg = $ldap->search(@search_args);
+ last unless $mesg->code == LDAP_SUCCESS;
+
+ my ($resp) = $mesg->control(LDAP_CONTROL_PAGED) or last;
+ $cookie = $resp->cookie();
+ goto SEARCH_DONE unless defined $cookie and length($cookie) > 0;
+
+ $page->cookie($cookie);
+ }
+
+ if (defined $cookie and length($cookie) > 0) {
+ fail($fh => "Abnormal exit from LDAP search, aborting");
+ $page->cookie($cookie);
+ $page->size(0);
+ $ldap->search(@search_args);
}
- closedir $dh or warn "closedir: $!";
+ SEARCH_DONE:
+ $ldap->unbind();
$fh->printflush("\n");
}
diff --git a/roles/IMAP/files/usr/local/bin/list-users.pl b/roles/IMAP/files/usr/local/bin/list-users.pl
deleted file mode 100755
index 1bcab35..0000000
--- a/roles/IMAP/files/usr/local/bin/list-users.pl
+++ /dev/null
@@ -1,45 +0,0 @@
-#!/usr/bin/perl
-
-# Copyright © 2017 Guilhem Moulin <guilhem@fripost.org>
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-use warnings;
-use strict;
-use Net::LDAPI;
-use Net::LDAP::Util qw/ldap_explode_dn escape_dn_value/;
-use Authen::SASL;
-
-my $BASE = 'ou=virtual,dc=fripost,dc=org';
-
-my $LDAP = Net::LDAPI::->new();
-$LDAP->bind( undef, sasl => Authen::SASL::->new(mechanism => 'EXTERNAL') )
- or die "Error: Couldn't bind";
-
-my $mesg = $LDAP->search( base => $BASE, scope => 'children', deref => 'never'
- , filter => '(objectClass=FripostVirtualUser)'
- , attrs => ['1.1']
- );
-die $mesg->error if $mesg->code;
-
-while (defined (my $entry = $mesg->pop_entry())) {
- my $dn = $entry->dn() // next;
- $dn = ldap_explode_dn($dn, casefold => 'lower');
- next unless defined $dn and $#$dn == 4;
- my $l = $dn->[0]->{fvl} // next;
- my $d = $dn->[1]->{fvd} // next;
- printf "%s@%s\n", $l, $d;
-}
-
-$LDAP->unbind;
diff --git a/roles/IMAP/tasks/imap.yml b/roles/IMAP/tasks/imap.yml
index 231c759..c2bdca9 100644
--- a/roles/IMAP/tasks/imap.yml
+++ b/roles/IMAP/tasks/imap.yml
@@ -18,6 +18,13 @@
password=!
state=present
+- name: Install Net::LDAP and Authen::SASL
+ apt: pkg={{ packages }}
+ vars:
+ packages:
+ - libnet-ldap-perl
+ - libauthen-sasl-perl
+
- name: Copy dovecot auth proxy
copy: src=usr/local/bin/dovecot-auth-proxy.pl
dest=/usr/local/bin/dovecot-auth-proxy.pl
@@ -30,6 +37,15 @@
tags:
- sysctl
+- name: Create '_dovecot-auth-proxy' user
+ user: name=_dovecot-auth-proxy system=yes
+ group=nogroup
+ createhome=no
+ home=/nonexistent
+ shell=/usr/sbin/nologin
+ password=!
+ state=present
+
- name: Copy dovecot auth proxy systemd unit files
copy: src=etc/systemd/system/{{ item }}
dest=/etc/systemd/system/{{ item }}
@@ -123,16 +139,6 @@
register: r1
with_items:
- conf.d/10-auth.conf
- - conf.d/10-logging.conf
- - conf.d/10-mail.conf
- - conf.d/10-ssl.conf
- - conf.d/15-mailboxes.conf
- # LDA is also used by LMTP
- - conf.d/15-lda.conf
- - conf.d/20-imap.conf
- - conf.d/20-lmtp.conf
- - conf.d/90-plugin.conf
- - conf.d/90-sieve.conf
- conf.d/auth-ldap.conf.ext
- dovecot-ldap.conf.ext
- dovecot-ldap-userdb.conf.ext
@@ -146,7 +152,16 @@
mode=0644
register: r2
with_items:
- - conf.d/10-master.conf
+ - conf.d/99-local.conf
+ notify:
+ - Restart Dovecot
+
+# TODO bookworm remove the below and inline the !include_try
+- name: Copy /etc/dovecot/ssl/config workaround
+ copy: src=etc/dovecot/ssl/config
+ dest=/etc/dovecot/ssl/config
+ owner=root group=root
+ mode=0600
notify:
- Restart Dovecot
diff --git a/roles/IMAP/tasks/mda.yml b/roles/IMAP/tasks/mda.yml
index f705fe7..0e8690d 100644
--- a/roles/IMAP/tasks/mda.yml
+++ b/roles/IMAP/tasks/mda.yml
@@ -3,7 +3,7 @@
vars:
packages:
- postfix
- - postfix-ldap
+ - postfix-lmdb
- name: Configure Postfix
template: src=etc/postfix/{{ item }}.j2
diff --git a/roles/IMAP/tasks/spam.yml b/roles/IMAP/tasks/spam.yml
index c275b55..d70ccc9 100644
--- a/roles/IMAP/tasks/spam.yml
+++ b/roles/IMAP/tasks/spam.yml
@@ -63,8 +63,8 @@
- name: Create a 'amavis' SQL user
# This *must* be the user we run spamd as
# See https://svn.apache.org/repos/asf/spamassassin/trunk/sql/README.bayes
- mysql_user2: >
- name=amavis password= auth_plugin=auth_socket
+ mysql_user: >
+ name=amavis password= plugin=auth_socket
priv="spamassassin.awl: SELECT,INSERT,UPDATE,DELETE
/spamassassin.bayes_seen: SELECT,INSERT, DELETE
/spamassassin.bayes_token: SELECT,INSERT,UPDATE,DELETE
diff --git a/roles/IMAP/templates/etc/dovecot/conf.d/10-master.conf.j2 b/roles/IMAP/templates/etc/dovecot/conf.d/10-master.conf.j2
index 8eef8a1..d61c11b 100644
--- a/roles/IMAP/templates/etc/dovecot/conf.d/10-master.conf.j2
+++ b/roles/IMAP/templates/etc/dovecot/conf.d/10-master.conf.j2
@@ -4,7 +4,7 @@
# Default VSZ (virtual memory size) limit for service processes. This is mainly
# intended to catch and kill processes that leak memory before they eat up
# everything.
-default_vsz_limit = 512M
+default_vsz_limit = 1024M
# Login user is internally used by login processes. This is the most untrusted
# user in Dovecot system. It shouldn't have access to anything at all.
@@ -53,6 +53,19 @@ service pop3-login {
}
}
+service stats {
+ unix_listener stats-writer {
+ user = vmail
+ mode = 0600
+ }
+}
+
+service submission-login {
+ inet_listener submission {
+ port = 0
+ }
+}
+
service lmtp {
user = vmail
@@ -88,6 +101,8 @@ service imap {
service imap-hibernate {
unix_listener imap-hibernate {
+ # Match user running imap processes, cf.
+ # https://dovecot.org/pipermail/dovecot/2015-August/101783.html
user = vmail
mode = 0600
}
@@ -98,6 +113,11 @@ service pop3 {
#process_limit = 1024
}
+service submission {
+ # Max. number of SMTP Submission processes (connections)
+ #process_limit = 1024
+}
+
service auth {
# auth_socket_path points to this userdb socket by default. It's typically
# used by dovecot-lda, doveadm, possibly imap process, etc. Users that have
@@ -120,6 +140,7 @@ service auth {
# Postfix smtp-auth
unix_listener /var/spool/postfix-{{ postfix_instance.MSA.name }}/private/dovecot-auth {
user = postfix
+ group = postfix
mode = 0600
}
@@ -143,10 +164,3 @@ service dict {
#group =
}
}
-
-service stats {
- fifo_listener stats-mail {
- user = vmail
- mode = 0600
- }
-}
diff --git a/roles/IMAP/templates/etc/dovecot/conf.d/15-lda.conf b/roles/IMAP/templates/etc/dovecot/conf.d/15-lda.conf
deleted file mode 100644
index e69de29..0000000
--- a/roles/IMAP/templates/etc/dovecot/conf.d/15-lda.conf
+++ /dev/null
diff --git a/roles/IMAP/templates/etc/dovecot/conf.d/99-local.conf.j2 b/roles/IMAP/templates/etc/dovecot/conf.d/99-local.conf.j2
new file mode 100644
index 0000000..3560193
--- /dev/null
+++ b/roles/IMAP/templates/etc/dovecot/conf.d/99-local.conf.j2
@@ -0,0 +1,204 @@
+auth_default_realm = fripost.org
+auth_username_format = %Lu
+auth_mechanisms = plain login
+
+mail_uid = vmail
+mail_gid = vmail
+mail_privileged_group =
+
+first_valid_uid = 1
+last_valid_uid = 0
+
+default_vsz_limit = 1024M
+
+service imap-login {
+ inet_listener imap {
+{% if groups.all | length > 1 %}
+ address = {{ ipsec[inventory_hostname_short] }}
+ port = 143
+{% else %}
+ port = 0
+{% endif %}
+ }
+ process_limit = 256
+ process_min_avail = 4
+}
+
+service stats {
+ unix_listener stats-writer {
+ user = vmail
+ mode = 0600
+ }
+}
+
+service submission-login {
+ inet_listener submission {
+ port = 0
+ }
+}
+
+service lmtp {
+ user = vmail
+ unix_listener lmtp {
+ mode = 0
+ }
+ unix_listener /var/spool/postfix-mda/private/dovecot-lmtpd {
+ user = postfix
+ mode = 0600
+ }
+ process_min_avail = 4
+}
+
+service imap {
+ unix_listener imap-master {
+ user = $default_internal_user
+ mode = 0600
+ }
+}
+service imap-hibernate {
+ unix_listener imap-hibernate {
+ # Match user running imap processes, cf.
+ # https://dovecot.org/pipermail/dovecot/2015-August/101783.html
+ user = vmail
+ mode = 0600
+ }
+}
+
+service auth {
+ unix_listener auth-userdb {
+ user = vmail
+ mode = 0600
+ }
+
+ # Postfix smtp-auth
+ unix_listener /var/spool/postfix-msa/private/dovecot-auth {
+ user = postfix
+ group = postfix
+ mode = 0600
+ }
+}
+
+service auth-worker {
+ user = $default_internal_user
+}
+
+
+mail_server_comment = "fripost - demokratisk e-post"
+mail_server_admin = mailto:postmaster@fripost.org
+
+mail_plugins = quota virtual zlib
+
+mail_location = mdbox:~/mail
+mdbox_preallocate_space = yes
+
+mail_attachment_dir = /home/mail/attachments
+mail_attachment_fs = sis-queue /home/mail/attachments/queue:posix
+mail_attachment_hash = %{sha256}
+
+sendmail_path = /usr/sbin/postmulti -i msa -x /usr/sbin/sendmail
+
+ssl = required
+# XXX `doveadm exec imap` fails with "ssl_key: Can't open file
+# /etc/dovecot/ssl/imap.fripost.org.key"
+# https://dovecot.org/pipermail/dovecot/2020-August/119642.html
+# TODO bookworm inline the include_try
+!include_try ../ssl/config
+ssl_dh = </etc/ssl/dhparams.pem
+ssl_min_protocol = TLSv1.2
+ssl_cipher_list = ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
+
+namespace inbox {
+ inbox = yes
+ separator = /
+
+ mailbox Drafts {
+ auto = create
+ special_use = \Drafts
+ }
+ mailbox Junk {
+ auto = create
+ special_use = \Junk
+ }
+ mailbox "Sent Messages" {
+ auto = no
+ special_use = \Sent
+ }
+ mailbox Sent {
+ auto = subscribe
+ special_use = \Sent
+ }
+ mailbox Trash {
+ auto = create
+ special_use = \Trash
+ }
+ mailbox virtual/All {
+ comment = All messages
+ special_use = \All
+ }
+ mailbox virtual/Flagged {
+ comment = All flagged messages
+ special_use = \Flagged
+ }
+}
+
+namespace virtual {
+ prefix = virtual/
+ separator = /
+ location = virtual:/etc/dovecot/virtual:INDEX=MEMORY
+ list = no
+ hidden = no
+ subscriptions = no
+}
+
+imap_hibernate_timeout = 15s
+protocol imap {
+ mail_plugins = $mail_plugins imap_zlib
+ mail_max_userip_connections = 16
+
+ ## TODO Load the 'antispam' plugin for people using the content filter.
+ ## (Otherwise fallback to the static userdb.)
+ #userdb {
+ # driver = ldap
+ # args = /etc/dovecot/dovecot-ldap-userdb.conf.ext
+ #
+ # # Default fields can be used to specify defaults that LDAP may override
+ # default_fields = home=/home/mail/virtual/%d/%n
+ #}
+}
+
+protocol lmtp {
+ postmaster_address = postmaster@fripost.org
+ # Space separated list of plugins to load (default is global mail_plugins).
+ mail_plugins = $mail_plugins sieve
+}
+
+plugin {
+ antispam_backend = spool2dir
+
+ antispam_trash = Trash
+ antispam_unsure_pattern_ignorecase = MailTrain;MailTrain/*
+ antispam_spam = Junk
+
+ # The first %%lu is replaced by the current time.
+ # The second %%lu is replaced by a counter to generate unique names.
+ # These two tokens MUST be present in the template!
+ antispam_spool2dir_spam = /home/mail/spamspool/%u-%%10lu-%%06lu.spam
+ antispam_spool2dir_notspam = /home/mail/spamspool/%u-%%10lu-%%06lu.ham
+}
+
+plugin {
+ quota_rule = *:storage=0
+ quota = count:User quota
+ quota_vsizes = yes
+}
+
+plugin {
+ sieve = file:~/sieve;active=~/dovecot.sieve
+ sieve_extensions = +editheader
+ recipient_delimiter = +
+}
+
+plugin {
+ zlib_save = gz
+ zlib_save_level = 6
+}
diff --git a/roles/IMAP/templates/etc/postfix/main.cf.j2 b/roles/IMAP/templates/etc/postfix/main.cf.j2
index 2105d29..64a2a40 100644
--- a/roles/IMAP/templates/etc/postfix/main.cf.j2
+++ b/roles/IMAP/templates/etc/postfix/main.cf.j2
@@ -21,7 +21,7 @@ append_dot_mydomain = no
mynetworks = 127.0.0.0/8, [::1]/128
{%- if groups.all | length > 1 -%}
{%- for mx in groups.MX | sort -%}
- , {{ ipsec[ hostvars[mx].inventory_hostname_short ] | ipaddr }}
+ , {{ ipsec[ hostvars[mx].inventory_hostname_short ] | ansible.utils.ipaddr }}
{%- endfor %}
{% endif %}
diff --git a/roles/LDAP-provider/files/etc/ldap/dynlist.ldif b/roles/LDAP-provider/files/etc/ldap/dynlist.ldif
new file mode 100644
index 0000000..df9a806
--- /dev/null
+++ b/roles/LDAP-provider/files/etc/ldap/dynlist.ldif
@@ -0,0 +1,26 @@
+# References:
+# - https://www.openldap.org/doc/admin24/overlays.html#Dynamic%20Lists
+# - man 5 slapo-dynlist
+
+# TODO bookworm (slapd 2.5)
+# “The dynlist overlay has been reworked with the 2.5 release to use a
+# consistent namespace as with other overlays. As a side-effect the
+# following cn=config parameters are deprecated and will be removed in a
+# future release: olcDlAttrSet is replaced with olcDynListAttrSet
+# olcDynamicList is replaced with olcDynListConfig”
+#
+# XXX that didn't solve the spaming from nextcloud's user_ldap plugin,
+# so we disable activity mails for “Your group memberships were
+# modified“ for now. See also
+#
+# https://github.com/nextcloud/server/issues/42195
+# https://github.com/nextcloud/server/issues/29832
+#
+# TODO bookworm: use “dynlist-attrset groupOfURLs memberURL
+# member+memberOf@groupOfNames” to also populate memberOf
+#
+dn: olcOverlay=dynlist,olcDatabase={*}mdb,cn=config
+objectClass: olcOverlayConfig
+objectClass: olcDynamicList
+olcOverlay: dynlist
+olcDlAttrSet: groupOfURLs memberURL member
diff --git a/roles/LDAP-provider/tasks/main.yml b/roles/LDAP-provider/tasks/main.yml
index af46c51..8d4e327 100644
--- a/roles/LDAP-provider/tasks/main.yml
+++ b/roles/LDAP-provider/tasks/main.yml
@@ -4,6 +4,18 @@
target=etc/ldap/syncprov.ldif
local=file
+#- name: Load dyngroup schema
+# openldap: target=/etc/ldap/schema/dyngroup.ldif
+
+- name: Load and configure the dynlist overlay
+ openldap: module=dynlist
+ suffix=dc=fripost,dc=org
+ target=etc/ldap/dynlist.ldif
+ local=file
+
+## XXX should be /etc/sasl2/slapd.conf ideally, but it doesn't work with
+## Stretch, cf #211156 and #798462:
+## ldapsearch -LLLx -H ldapi:// -b "" -s base supportedSASLMechanisms
- name: Enable the EXTERNAL SASL mechanism
lineinfile: dest=/usr/lib/sasl2/slapd.conf
regexp='^mech_list{{':'}}'
@@ -12,7 +24,4 @@
owner=root group=root
mode=0644
-#- name: Load dyngroup schema
-# openldap: target=/etc/ldap/schema/dyngroup.ldif
-
# TODO: authz constraint
diff --git a/roles/MSA/files/etc/postfix/anonymize_sender.pcre b/roles/MSA/files/etc/postfix/anonymize_sender.pcre
index 7c11f4e..b91b981 100644
--- a/roles/MSA/files/etc/postfix/anonymize_sender.pcre
+++ b/roles/MSA/files/etc/postfix/anonymize_sender.pcre
@@ -1,5 +1,6 @@
/^Received:\s+from\s+(?:\S+\s+\(\S+\s+\[(?:IPv6:)?[[:xdigit:].:]{3,39}\]\))
- (\s+\(using\s+(?:TLS|SSL)(?:v\S+)?\s+with\s+cipher\s+\S+\s+\(\S+\s+bits\)\)\s+).*
+ (\s+\(using\s+(?:TLS|SSL)(?:v\S+)?\s+with\s+cipher\s+\S+\s+\(\S+\s+bits\)
+ (?:\s+key-exchange\s+\S+\s+(?:\([^)]+\)\s+)?server-signature\s+\S+\s+\(\d+\s+bits\)(?:\s+server-[[:alnum:]]+\s+\S+)*)?\)\s+).*
(\bby\s+(?:\S+\.)?fripost\.org\s+\([^)]+\)
\s+with\s+E?SMTPS?A\s+id\s+[[:xdigit:]]+;?\s.*)/x
REPLACE Received: from [127.0.0.1] (localhost [127.0.0.1])${1}${2}
diff --git a/roles/MSA/files/etc/systemd/system/postfix-sender-login.service b/roles/MSA/files/etc/systemd/system/postfix-sender-login.service
index f5e6d89..d652f75 100644
--- a/roles/MSA/files/etc/systemd/system/postfix-sender-login.service
+++ b/roles/MSA/files/etc/systemd/system/postfix-sender-login.service
@@ -4,8 +4,7 @@ After=mail-transport-agent.target
Requires=postfix-sender-login.socket
[Service]
-User=postfix
-Group=postfix
+User=_postfix-sender-login
StandardInput=null
SyslogFacility=mail
ExecStart=/usr/local/bin/postfix-sender-login.pl
@@ -13,10 +12,9 @@ ExecStart=/usr/local/bin/postfix-sender-login.pl
# Hardening
NoNewPrivileges=yes
PrivateDevices=yes
+PrivateNetwork=yes
ProtectHome=yes
ProtectSystem=strict
-PrivateDevices=yes
-PrivateNetwork=yes
ProtectControlGroups=yes
ProtectKernelModules=yes
ProtectKernelTunables=yes
diff --git a/roles/MSA/files/usr/local/bin/postfix-sender-login.pl b/roles/MSA/files/usr/local/bin/postfix-sender-login.pl
index 374cc70..a37f872 100755
--- a/roles/MSA/files/usr/local/bin/postfix-sender-login.pl
+++ b/roles/MSA/files/usr/local/bin/postfix-sender-login.pl
@@ -3,7 +3,7 @@
#----------------------------------------------------------------------
# socketmap lookup table returning the SASL login name(s) owning a given
# sender address
-# Copyright © 2017 Guilhem Moulin <guilhem@fripost.org>
+# Copyright © 2017,2020 Guilhem Moulin <guilhem@fripost.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -33,12 +33,13 @@ use Authen::SASL ();
$ENV{PATH} = join ':', qw{/usr/bin /bin};
delete @ENV{qw/IFS CDPATH ENV BASH_ENV/};
-my $nProc = 2; # number of pre-forked servers
-my $POSTMASTER = 'postmaster@fripost.org'; # returned for forbidden envelope sender addresses
+my $nProc = 2; # number of pre-forked servers
+my $maxRequests = 32; # maximum number of requests per worker
+my $POSTMASTER = 'postmaster@fripost.org'; # returned for forbidden envelope sender addresses
-my $BASEDN = 'ou=virtual,dc=fripost,dc=org';
+my $BASEDN = "ou=virtual,dc=fripost,dc=org";
my $BUFSIZE = 65536; # try to read that many bytes at the time
-my $LDAPI = 'ldapi://%2Fvar%2Fspool%2Fpostfix-msa%2Fprivate%2Fldapi/';
+my $LDAPI = "ldapi://";
sub server();
@@ -66,7 +67,7 @@ exit $?;
#############################################################################
sub server() {
- for (my $n = 0; $n < 32; $n++) {
+ for (my $n = 0; $n < $maxRequests; $n++) {
accept(my $conn, $S) or do {
next if $! == EINTR;
die "accept: $!";
diff --git a/roles/MSA/tasks/main.yml b/roles/MSA/tasks/main.yml
index c78139a..bf17702 100644
--- a/roles/MSA/tasks/main.yml
+++ b/roles/MSA/tasks/main.yml
@@ -3,15 +3,32 @@
vars:
packages:
- postfix
+ - postfix-lmdb
- postfix-pcre
- postfix-policyd-spf-python
+- name: Install Net::LDAP and Authen::SASL
+ apt: pkg={{ packages }}
+ vars:
+ packages:
+ - libnet-ldap-perl
+ - libauthen-sasl-perl
+
- name: Copy Postfix sender login socketmap
copy: src=usr/local/bin/postfix-sender-login.pl
dest=/usr/local/bin/postfix-sender-login.pl
owner=root group=staff
mode=0755
+- name: Create '_postfix-sender-login' user
+ user: name=_postfix-sender-login system=yes
+ group=nogroup
+ createhome=no
+ home=/nonexistent
+ shell=/usr/sbin/nologin
+ password=!
+ state=present
+
- name: Copy Postfix sender login socketmap systemd unit files
copy: src=etc/systemd/system/{{ item }}
dest=/etc/systemd/system/{{ item }}
@@ -23,6 +40,19 @@
notify:
- systemctl daemon-reload
+- name: Copy the SMTP TLS policy maps
+ template: src=etc/postfix/smtp_tls_policy.j2
+ dest=/etc/postfix-{{ postfix_instance[inst].name }}/smtp_tls_policy
+ owner=root group=root
+ mode=0644
+
+- name: Compile the SMTP TLS policy maps
+ postmap: cmd=postmap src=/etc/postfix-{{ postfix_instance[inst].name }}/smtp_tls_policy db=lmdb
+ owner=root group=root
+ mode=0644
+ notify:
+ - Reload Postfix
+
- meta: flush_handlers
- name: Enable Postfix sender login socketmap
diff --git a/roles/MSA/templates/etc/postfix/main.cf.j2 b/roles/MSA/templates/etc/postfix/main.cf.j2
index 65a0339..6a544ac 100644
--- a/roles/MSA/templates/etc/postfix/main.cf.j2
+++ b/roles/MSA/templates/etc/postfix/main.cf.j2
@@ -20,7 +20,7 @@ append_dot_mydomain = no
mynetworks = 127.0.0.0/8, [::1]/128
{%- for h in groups.webmail | difference([inventory_hostname]) | sort -%}
- , {{ ipsec[ hostvars[h].inventory_hostname_short ] | ipaddr }}
+ , {{ ipsec[ hostvars[h].inventory_hostname_short ] | ansible.utils.ipaddr }}
{% endfor %}
queue_directory = /var/spool/postfix-{{ postfix_instance[inst].name }}
@@ -40,7 +40,7 @@ message_size_limit = 67108864
recipient_delimiter = +
# Forward everything to our internal outgoing proxy
-relayhost = [{{ postfix_instance.out.addr | ipaddr }}]:{{ postfix_instance.out.port }}
+relayhost = [{{ postfix_instance.out.addr | ansible.utils.ipaddr }}]:{{ postfix_instance.out.port }}
relay_domains =
@@ -60,14 +60,14 @@ header_checks = pcre:$config_directory/anonymize_sender.pcre
# TLS
smtp_tls_security_level = none
smtpd_tls_security_level = encrypt
-smtpd_tls_ciphers = high
-smtpd_tls_protocols = !SSLv2, !SSLv3
-smtpd_tls_exclude_ciphers = EXPORT, LOW, MEDIUM, aNULL, eNULL, DES, RC4, MD5
+smtpd_tls_mandatory_ciphers = high
+smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
smtpd_tls_cert_file = $config_directory/ssl/smtp.fripost.org.pem
smtpd_tls_key_file = $config_directory/ssl/smtp.fripost.org.key
smtpd_tls_dh1024_param_file = /etc/ssl/dhparams.pem
smtpd_tls_session_cache_database=
smtpd_tls_received_header = yes
+tls_high_cipherlist = ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
# SASL
smtpd_sasl_auth_enable = yes
@@ -121,4 +121,7 @@ smtpd_relay_restrictions =
smtpd_data_restrictions =
reject_unauth_pipelining
+smtpd_forbid_bare_newline = normalize
+smtpd_forbid_bare_newline_exclusions = $mynetworks
+
# vim: set filetype=pfmain :
diff --git a/roles/MSA/templates/etc/postfix/smtp_tls_policy.j2 b/roles/MSA/templates/etc/postfix/smtp_tls_policy.j2
new file mode 120000
index 0000000..b40876f
--- /dev/null
+++ b/roles/MSA/templates/etc/postfix/smtp_tls_policy.j2
@@ -0,0 +1 @@
+../../../../out/templates/etc/postfix/smtp_tls_policy.j2 \ No newline at end of file
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/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 507a4f2..57f17f8 100644
--- a/roles/MX/tasks/main.yml
+++ b/roles/MX/tasks/main.yml
@@ -137,3 +137,48 @@
- 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/main.cf.j2 b/roles/MX/templates/etc/postfix/main.cf.j2
index a2cc2a8..d10f901 100644
--- a/roles/MX/templates/etc/postfix/main.cf.j2
+++ b/roles/MX/templates/etc/postfix/main.cf.j2
@@ -37,7 +37,7 @@ message_size_limit = 67108864
recipient_delimiter = +
# Forward everything to our internal outgoing proxy
-relayhost = [{{ postfix_instance.out.addr | ipaddr }}]:{{ postfix_instance.out.port }}
+relayhost = [{{ postfix_instance.out.addr | ansible.utils.ipaddr }}]:{{ postfix_instance.out.port }}
relay_domains =
@@ -123,6 +123,7 @@ postscreen_dnsbl_sites =
postscreen_greet_action = enforce
postscreen_whitelist_interfaces = static:all
+smtpd_milters = { unix:public/opendmarc, protocol=6, default_action=accept }
smtpd_client_restrictions =
permit_mynetworks
@@ -148,10 +149,6 @@ smtpd_recipient_restrictions =
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]
- # defer if "abused legit": DBL return code in the 127.0.1.100+ range
- defer_if_reject
- reject_rhsbl_reverse_client dbl.spamhaus.org=127.0.1.[100..254]
- reject_rhsbl_sender dbl.spamhaus.org=127.0.1.[100..254]
smtpd_data_restrictions =
reject_unauth_pipelining
diff --git a/roles/MX/templates/etc/postfix/virtual/transport.j2 b/roles/MX/templates/etc/postfix/virtual/transport.j2
index 126cb72..536748a 100644
--- a/roles/MX/templates/etc/postfix/virtual/transport.j2
+++ b/roles/MX/templates/etc/postfix/virtual/transport.j2
@@ -17,5 +17,5 @@
reserved.fripost.org reserved-alias:
discard.fripost.org discard:
-mda.fripost.org smtp:[{{ postfix_instance.IMAP.addr | ipaddr }}]:{{ postfix_instance.IMAP.port }}
-sympa.fripost.org smtp:[{{ postfix_instance.lists.addr | ipaddr }}]:{{ postfix_instance.lists.port }}
+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 }}
diff --git a/roles/amavis/tasks/main.yml b/roles/amavis/tasks/main.yml
index 3036c52..7fc44c7 100644
--- a/roles/amavis/tasks/main.yml
+++ b/roles/amavis/tasks/main.yml
@@ -17,8 +17,6 @@
- unrar-free
- arj
- nomarch
- - zoo
- - ripole
- cabextract
- unar
- tnef
@@ -52,14 +50,12 @@
- dkim
- name: Generate a private key for DKIM signing
- command: genkeypair.sh dkim --privkey="/etc/amavis/dkim/{{ item.s }}:{{ item.d }}.pem" -t rsa -b 2048
+ command: genkeypair.sh dkim --owner=amavis --group=root --privkey="/etc/amavis/dkim/{{ item.s }}:{{ item.d }}.pem" -t rsa -b 2048
with_items: "{{ (dkim_keys[inventory_hostname_short] | default({})).values() | list }}"
register: dkim
changed_when: dkim.rc == 0
failed_when: dkim.rc > 1
when: "'out' in group_names"
- notify:
- - Restart Amavis
tags:
- genkey
- dkim
diff --git a/roles/amavis/templates/etc/amavis/conf.d/50-user.j2 b/roles/amavis/templates/etc/amavis/conf.d/50-user.j2
index a09c366..8563a8c 100644
--- a/roles/amavis/templates/etc/amavis/conf.d/50-user.j2
+++ b/roles/amavis/templates/etc/amavis/conf.d/50-user.j2
@@ -33,12 +33,13 @@ $enable_dkim_signing = 1;
# Sign *all* outgoing mails with *our* key (yes, amavis complains, but this is
# safe as we force our domain with the 'd' tag).
{% for x,k in dkim_keys[inventory_hostname_short] | default({}) | dictsort() -%}
-dkim_key({{ (x == "~") | ternary('qr/./', "'"+x+"'") }}, '{{ k.s }}', '/etc/amavis/dkim/{{ k.s }}:{{ k.d }}.pem');
+dkim_key({{ (x == "~") | ternary('qr/./', "'"+(x | regex_replace('^.*@',''))+"'") }}, '{{ k.s }}', '/etc/amavis/dkim/{{ k.s }}:{{ k.d }}.pem');
{% endfor -%}
@dkim_signature_options_bysender_maps = (
{% for x,k in dkim_keys[inventory_hostname_short] | default({}) | dictsort() %}
{ '{{ (x == "~") | ternary('.', x) }}' => {
d => '{{ k.d }}'
+ , s => '{{ k.s }}'
, a => 'rsa-sha256'
, ttl => 21*24*3600
, c => 'relaxed/simple' }
diff --git a/roles/bacula-dir/files/etc/systemd/system/bacula-director.service b/roles/bacula-dir/files/etc/systemd/system/bacula-director.service.d/override.conf
index 4873689..f0d36c4 100644
--- a/roles/bacula-dir/files/etc/systemd/system/bacula-director.service
+++ b/roles/bacula-dir/files/etc/systemd/system/bacula-director.service.d/override.conf
@@ -1,14 +1,4 @@
-[Unit]
-Description=Bacula Director service
-After=network.target
-
[Service]
-Type=simple
-StandardOutput=syslog
-User=bacula
-Group=bacula
-ExecStart=/usr/sbin/bacula-dir -f -c /etc/bacula/bacula-dir.conf
-
# Hardening
NoNewPrivileges=yes
PrivateDevices=yes
@@ -16,12 +6,8 @@ ProtectHome=yes
ProtectSystem=strict
ReadWriteDirectories=-/var/lib/bacula
ReadWriteDirectories=-/var/log/bacula
-ReadWriteDirectories=-/var/run/bacula
PrivateDevices=yes
ProtectControlGroups=yes
ProtectKernelModules=yes
ProtectKernelTunables=yes
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
-
-[Install]
-WantedBy=multi-user.target
diff --git a/roles/bacula-dir/tasks/main.yml b/roles/bacula-dir/tasks/main.yml
index 2f7ab25..53d44ee 100644
--- a/roles/bacula-dir/tasks/main.yml
+++ b/roles/bacula-dir/tasks/main.yml
@@ -7,12 +7,12 @@
- bacula-director-mysql
- name: Create a 'bacula' SQL user
- mysql_user2: name=bacula password= auth_plugin=unix_socket
- state=present
+ mysql_user: name=bacula password= plugin=unix_socket
+ state=present
notify:
- Restart bacula-director
-# Create with:
+# Populate with:
# echo bconsole $(pwgen -sn 64 1) | sudo tee -a /etc/bacula/passwords-dir
# echo $sd-sd $(pwgen -sn 64 1) | sudo tee -a /etc/bacula/passwords-dir
# echo $fd-fd $(pwgen -sn 64 1) | sudo tee -a /etc/bacula/passwords-dir
@@ -41,9 +41,15 @@
notify:
- Restart bacula-director
-- name: Copy bacula-director.service
- copy: src=etc/systemd/system/bacula-director.service
- dest=/etc/systemd/system/bacula-director.service
+- name: Create /etc/systemd/system/bacula-director.service.d
+ file: path=/etc/systemd/system/bacula-director.service.d
+ state=directory
+ owner=root group=root
+ mode=0755
+
+- name: Copy bacula-director.service override
+ copy: src=etc/systemd/system/bacula-director.service.d/override.conf
+ dest=/etc/systemd/system/bacula-director.service.d/override.conf
owner=root group=root
mode=0644
notify:
diff --git a/roles/bacula-dir/templates/etc/bacula/bacula-dir.conf.j2 b/roles/bacula-dir/templates/etc/bacula/bacula-dir.conf.j2
index f2ffd17..7d862d3 100644
--- a/roles/bacula-dir/templates/etc/bacula/bacula-dir.conf.j2
+++ b/roles/bacula-dir/templates/etc/bacula/bacula-dir.conf.j2
@@ -1,6 +1,6 @@
#
# Default Bacula Director Configuration file
-# For Bacula release 5.2.6 (21 February 2012) -- debian jessie/sid
+# For Bacula release 9.4.2 (04 February 2019) -- debian buster/sid
#
Director { # define myself
@@ -8,7 +8,7 @@ Director { # define myself
@|"sed -n '/^bconsole\\s/ {s//Password = /p; q}' /etc/bacula/passwords-dir"
Messages = Daemon
Working Directory = /var/lib/bacula
- Pid Directory = /var/run/bacula
+ Pid Directory = /run/bacula
QueryFile = "/etc/bacula/scripts/query.sql"
Maximum Concurrent Jobs = 1
DirAddress = 127.0.0.1
@@ -79,7 +79,7 @@ JobDefs {
Runs On Success = yes
Runs On Failure = yes
Runs When = after
- Command = "/usr/bin/find /var/lib/bacula/tmp -type f -name '*.ldif' -delete"
+ Command = "/usr/bin/find /var/lib/bacula/tmp -type f \( -name \"*.ldif\" -o -name \"slapd-*\" \) -delete"
}
Pool = database
Priority = 20
@@ -112,6 +112,21 @@ Job {
}
{% endfor %}
+# Backup the Nextcloud data
+{% for h in groups.nextcloud | sort %}
+Job {
+ Name = {{ hostvars[h].inventory_hostname_short }}-nextcloud
+ Client = {{ hostvars[h].inventory_hostname_short }}-fd
+ JobDefs = DefaultJob
+ FileSet = NextcloudData
+ Pool = nextcloud-inc
+ Full Backup Pool = nextcloud-full
+ Schedule = Nextcloud13WeeksCycle
+ Max Start Delay = 50 min # To avoid too many overlaps
+ Max Full Interval = 15 weeks
+}
+{% endfor %}
+
# Backup each machine
{% for fd in groups.all | sort %}
Job {
@@ -133,7 +148,7 @@ Job {
}
{% endfor %}
-{% for fd in groups['MDA'] | union(groups['MSA']) | union(groups['LDAP-provider']) | union(groups['MX']) | sort %}
+{% for fd in groups['MDA'] | union(groups['MSA']) | union(groups['LDAP_provider']) | union(groups['MX']) | sort %}
Job {
Name = {{ hostvars[fd].inventory_hostname_short }}-slapd
Client = {{ hostvars[fd].inventory_hostname_short }}-fd
@@ -175,33 +190,71 @@ Schedule {
Run = Level=Full Pool=mailboxes-full w17 mon at 02:00
Run = Level=Full Pool=mailboxes-full w30 mon at 02:00
Run = Level=Full Pool=mailboxes-full w43 mon at 02:00
- Run = Level=Incremental Pool=mailboxes-inc FullPool=mailboxes-full Messages=Quiet mon-sun at 01:00
- Run = Level=Incremental Pool=mailboxes-inc FullPool=mailboxes-full Messages=Quiet w05-w16 mon-sun at 02:00
- Run = Level=Incremental Pool=mailboxes-inc FullPool=mailboxes-full Messages=Quiet w18-w29 mon-sun at 02:00
- Run = Level=Incremental Pool=mailboxes-inc FullPool=mailboxes-full Messages=Quiet w31-w42 mon-sun at 02:00
- Run = Level=Incremental Pool=mailboxes-inc FullPool=mailboxes-full Messages=Quiet w44-w03 mon-sun at 02:00
- Run = Level=Incremental Pool=mailboxes-inc FullPool=mailboxes-full Messages=Quiet mon-sun at 03:00
- Run = Level=Incremental Pool=mailboxes-inc FullPool=mailboxes-full Messages=Quiet mon-sun at 04:00
- Run = Level=Incremental Pool=mailboxes-inc FullPool=mailboxes-full Messages=Quiet mon-sun at 05:00
- Run = Level=Incremental Pool=mailboxes-inc FullPool=mailboxes-full Messages=Quiet mon-sun at 06:00
- Run = Level=Incremental Pool=mailboxes-inc FullPool=mailboxes-full Messages=Quiet mon-sun at 07:00
- Run = Level=Incremental Pool=mailboxes-inc FullPool=mailboxes-full Messages=Quiet mon-sun at 08:00
- Run = Level=Incremental Pool=mailboxes-inc FullPool=mailboxes-full Messages=Quiet mon-sun at 09:00
- Run = Level=Incremental Pool=mailboxes-inc FullPool=mailboxes-full Messages=Quiet mon-sun at 10:00
- Run = Level=Incremental Pool=mailboxes-inc FullPool=mailboxes-full Messages=Quiet mon-sun at 11:00
- Run = Level=Incremental Pool=mailboxes-inc FullPool=mailboxes-full Messages=Quiet mon-sun at 12:00
- Run = Level=Incremental Pool=mailboxes-inc FullPool=mailboxes-full Messages=Quiet mon-sun at 13:00
- Run = Level=Incremental Pool=mailboxes-inc FullPool=mailboxes-full Messages=Quiet mon-sun at 14:00
- Run = Level=Incremental Pool=mailboxes-inc FullPool=mailboxes-full Messages=Quiet mon-sun at 15:00
- Run = Level=Incremental Pool=mailboxes-inc FullPool=mailboxes-full Messages=Quiet mon-sun at 16:00
- Run = Level=Incremental Pool=mailboxes-inc FullPool=mailboxes-full Messages=Quiet mon-sun at 17:00
- Run = Level=Incremental Pool=mailboxes-inc FullPool=mailboxes-full Messages=Quiet mon-sun at 18:00
- Run = Level=Incremental Pool=mailboxes-inc FullPool=mailboxes-full Messages=Quiet mon-sun at 19:00
- Run = Level=Incremental Pool=mailboxes-inc FullPool=mailboxes-full Messages=Quiet mon-sun at 20:00
- Run = Level=Incremental Pool=mailboxes-inc FullPool=mailboxes-full Messages=Quiet mon-sun at 21:00
- Run = Level=Incremental Pool=mailboxes-inc FullPool=mailboxes-full Messages=Quiet mon-sun at 22:00
- Run = Level=Incremental Pool=mailboxes-inc FullPool=mailboxes-full Messages=Quiet mon-sun at 23:00
- Run = Level=Incremental Pool=mailboxes-inc FullPool=mailboxes-full Messages=Quiet mon-sun at 00:00
+ Run = Level=Differential Pool=mailboxes-diff FullPool=mailboxes-full Messages=Quiet w05-w16 mon at 02:00
+ Run = Level=Differential Pool=mailboxes-diff FullPool=mailboxes-full Messages=Quiet w18-w29 mon at 02:00
+ Run = Level=Differential Pool=mailboxes-diff FullPool=mailboxes-full Messages=Quiet w31-w42 mon at 02:00
+ Run = Level=Differential Pool=mailboxes-diff FullPool=mailboxes-full Messages=Quiet w44-w03 mon at 02:00
+ Run = Level=Incremental Pool=mailboxes-inc DifferentialPool=mailboxes-diff FullPool=mailboxes-full Messages=Quiet mon-sun at 00:00
+ Run = Level=Incremental Pool=mailboxes-inc DifferentialPool=mailboxes-diff FullPool=mailboxes-full Messages=Quiet mon-sun at 01:00
+ Run = Level=Incremental Pool=mailboxes-inc DifferentialPool=mailboxes-diff FullPool=mailboxes-full Messages=Quiet tue-sun at 02:00
+ Run = Level=Incremental Pool=mailboxes-inc DifferentialPool=mailboxes-diff FullPool=mailboxes-full Messages=Quiet mon-sun at 03:00
+ Run = Level=Incremental Pool=mailboxes-inc DifferentialPool=mailboxes-diff FullPool=mailboxes-full Messages=Quiet mon-sun at 04:00
+ Run = Level=Incremental Pool=mailboxes-inc DifferentialPool=mailboxes-diff FullPool=mailboxes-full Messages=Quiet mon-sun at 05:00
+ Run = Level=Incremental Pool=mailboxes-inc DifferentialPool=mailboxes-diff FullPool=mailboxes-full Messages=Quiet mon-sun at 06:00
+ Run = Level=Incremental Pool=mailboxes-inc DifferentialPool=mailboxes-diff FullPool=mailboxes-full Messages=Quiet mon-sun at 07:00
+ Run = Level=Incremental Pool=mailboxes-inc DifferentialPool=mailboxes-diff FullPool=mailboxes-full Messages=Quiet mon-sun at 08:00
+ Run = Level=Incremental Pool=mailboxes-inc DifferentialPool=mailboxes-diff FullPool=mailboxes-full Messages=Quiet mon-sun at 09:00
+ Run = Level=Incremental Pool=mailboxes-inc DifferentialPool=mailboxes-diff FullPool=mailboxes-full Messages=Quiet mon-sun at 10:00
+ Run = Level=Incremental Pool=mailboxes-inc DifferentialPool=mailboxes-diff FullPool=mailboxes-full Messages=Quiet mon-sun at 11:00
+ Run = Level=Incremental Pool=mailboxes-inc DifferentialPool=mailboxes-diff FullPool=mailboxes-full Messages=Quiet mon-sun at 12:00
+ Run = Level=Incremental Pool=mailboxes-inc DifferentialPool=mailboxes-diff FullPool=mailboxes-full Messages=Quiet mon-sun at 13:00
+ Run = Level=Incremental Pool=mailboxes-inc DifferentialPool=mailboxes-diff FullPool=mailboxes-full Messages=Quiet mon-sun at 14:00
+ Run = Level=Incremental Pool=mailboxes-inc DifferentialPool=mailboxes-diff FullPool=mailboxes-full Messages=Quiet mon-sun at 15:00
+ Run = Level=Incremental Pool=mailboxes-inc DifferentialPool=mailboxes-diff FullPool=mailboxes-full Messages=Quiet mon-sun at 16:00
+ Run = Level=Incremental Pool=mailboxes-inc DifferentialPool=mailboxes-diff FullPool=mailboxes-full Messages=Quiet mon-sun at 17:00
+ Run = Level=Incremental Pool=mailboxes-inc DifferentialPool=mailboxes-diff FullPool=mailboxes-full Messages=Quiet mon-sun at 18:00
+ Run = Level=Incremental Pool=mailboxes-inc DifferentialPool=mailboxes-diff FullPool=mailboxes-full Messages=Quiet mon-sun at 19:00
+ Run = Level=Incremental Pool=mailboxes-inc DifferentialPool=mailboxes-diff FullPool=mailboxes-full Messages=Quiet mon-sun at 20:00
+ Run = Level=Incremental Pool=mailboxes-inc DifferentialPool=mailboxes-diff FullPool=mailboxes-full Messages=Quiet mon-sun at 21:00
+ Run = Level=Incremental Pool=mailboxes-inc DifferentialPool=mailboxes-diff FullPool=mailboxes-full Messages=Quiet mon-sun at 22:00
+ Run = Level=Incremental Pool=mailboxes-inc DifferentialPool=mailboxes-diff FullPool=mailboxes-full Messages=Quiet mon-sun at 23:00
+}
+
+# Backup Nextcloud data: full backup every 3 months, hourly incremental backup
+Schedule {
+ Name = Nextcloud13WeeksCycle
+ Run = Level=Full Pool=nextcloud-full w05 mon at 02:30
+ Run = Level=Full Pool=nextcloud-full w18 mon at 02:30
+ Run = Level=Full Pool=nextcloud-full w31 mon at 02:30
+ Run = Level=Full Pool=nextcloud-full w44 mon at 02:30
+ Run = Level=Differential Pool=nextcloud-diff FullPool=nextcloud-full Messages=Quiet w06-w17 mon at 02:30
+ Run = Level=Differential Pool=nextcloud-diff FullPool=nextcloud-full Messages=Quiet w19-w30 mon at 02:30
+ Run = Level=Differential Pool=nextcloud-diff FullPool=nextcloud-full Messages=Quiet w32-w43 mon at 02:30
+ Run = Level=Differential Pool=nextcloud-diff FullPool=nextcloud-full Messages=Quiet w45-w04 mon at 02:30
+ Run = Level=Incremental Pool=nextcloud-inc DifferentialPool=nextcloud-diff FullPool=nextcloud-full Messages=Quiet mon-sun at 00:30
+ Run = Level=Incremental Pool=nextcloud-inc DifferentialPool=nextcloud-diff FullPool=nextcloud-full Messages=Quiet mon-sun at 01:30
+ Run = Level=Incremental Pool=nextcloud-inc DifferentialPool=nextcloud-diff FullPool=nextcloud-full Messages=Quiet tue-sun at 02:30
+ Run = Level=Incremental Pool=nextcloud-inc DifferentialPool=nextcloud-diff FullPool=nextcloud-full Messages=Quiet mon-sun at 03:30
+ Run = Level=Incremental Pool=nextcloud-inc DifferentialPool=nextcloud-diff FullPool=nextcloud-full Messages=Quiet mon-sun at 04:30
+ Run = Level=Incremental Pool=nextcloud-inc DifferentialPool=nextcloud-diff FullPool=nextcloud-full Messages=Quiet mon-sun at 05:30
+ Run = Level=Incremental Pool=nextcloud-inc DifferentialPool=nextcloud-diff FullPool=nextcloud-full Messages=Quiet mon-sun at 06:30
+ Run = Level=Incremental Pool=nextcloud-inc DifferentialPool=nextcloud-diff FullPool=nextcloud-full Messages=Quiet mon-sun at 07:30
+ Run = Level=Incremental Pool=nextcloud-inc DifferentialPool=nextcloud-diff FullPool=nextcloud-full Messages=Quiet mon-sun at 08:30
+ Run = Level=Incremental Pool=nextcloud-inc DifferentialPool=nextcloud-diff FullPool=nextcloud-full Messages=Quiet mon-sun at 09:30
+ Run = Level=Incremental Pool=nextcloud-inc DifferentialPool=nextcloud-diff FullPool=nextcloud-full Messages=Quiet mon-sun at 10:30
+ Run = Level=Incremental Pool=nextcloud-inc DifferentialPool=nextcloud-diff FullPool=nextcloud-full Messages=Quiet mon-sun at 11:30
+ Run = Level=Incremental Pool=nextcloud-inc DifferentialPool=nextcloud-diff FullPool=nextcloud-full Messages=Quiet mon-sun at 12:30
+ Run = Level=Incremental Pool=nextcloud-inc DifferentialPool=nextcloud-diff FullPool=nextcloud-full Messages=Quiet mon-sun at 13:30
+ Run = Level=Incremental Pool=nextcloud-inc DifferentialPool=nextcloud-diff FullPool=nextcloud-full Messages=Quiet mon-sun at 14:30
+ Run = Level=Incremental Pool=nextcloud-inc DifferentialPool=nextcloud-diff FullPool=nextcloud-full Messages=Quiet mon-sun at 15:30
+ Run = Level=Incremental Pool=nextcloud-inc DifferentialPool=nextcloud-diff FullPool=nextcloud-full Messages=Quiet mon-sun at 16:30
+ Run = Level=Incremental Pool=nextcloud-inc DifferentialPool=nextcloud-diff FullPool=nextcloud-full Messages=Quiet mon-sun at 17:30
+ Run = Level=Incremental Pool=nextcloud-inc DifferentialPool=nextcloud-diff FullPool=nextcloud-full Messages=Quiet mon-sun at 18:30
+ Run = Level=Incremental Pool=nextcloud-inc DifferentialPool=nextcloud-diff FullPool=nextcloud-full Messages=Quiet mon-sun at 19:30
+ Run = Level=Incremental Pool=nextcloud-inc DifferentialPool=nextcloud-diff FullPool=nextcloud-full Messages=Quiet mon-sun at 20:30
+ Run = Level=Incremental Pool=nextcloud-inc DifferentialPool=nextcloud-diff FullPool=nextcloud-full Messages=Quiet mon-sun at 21:30
+ Run = Level=Incremental Pool=nextcloud-inc DifferentialPool=nextcloud-diff FullPool=nextcloud-full Messages=Quiet mon-sun at 22:30
+ Run = Level=Incremental Pool=nextcloud-inc DifferentialPool=nextcloud-diff FullPool=nextcloud-full Messages=Quiet mon-sun at 23:30
}
# This schedule does the databases. It starts after the WeeklyCycle
@@ -318,6 +371,7 @@ FileSet {
File = /exports
File = /misc
File = /media
+ File = /lost+found
}
}
@@ -353,9 +407,26 @@ FileSet {
FileSet {
Name = Mailboxes
Include {
+ # NOTE: debug FileSet with:
+ # `sudo -u bacula bconsole <<<"estimate job=mistral-mailboxes level=Full listing" | grep -F -e.{log,cache}`
+ # we use RegexFile here since bacula's doesn't set FNM_PATHNAME so the `*' and `?' metacharacters match `/'
Options {
- WildDir = /home/mail/attachments/queue
Exclude = yes
+
+ # cached mailbox data: $mail_location/mailboxes/INBOX/dbox-Mails/dovecot.index.cache
+ RegexFile = "^/home/mail/virtual/[^/]+/[^/]+/mail/mailboxes/([^/]+/)+dbox-Mails/dovecot\\.index\\.cache$"
+ # transaction log file: $mail_location/mailboxes/INBOX/dbox-Mails/dovecot.index.log
+ RegexFile = "^/home/mail/virtual/[^/]+/[^/]+/mail/mailboxes/([^/]+/)+dbox-Mails/dovecot\\.index\\.log(\\.[0-9])?$"
+ RegexFile = "^/home/mail/virtual/[^/]+/[^/]+/mail/storage/dovecot\\.map\\.index\\.log(\\.[0-9])?$"
+ # mailbox list index files: $mail_location/dovecot.list.index.log
+ RegexFile = "^/home/mail/virtual/[^/]+/[^/]+/mail/dovecot\\.list\\.index\\.log(\\.[0-9])?$"
+ # mailbox changelog: $mail_location/dovecot.mailbox.log
+ RegexFile = "^/home/mail/virtual/[^/]+/[^/]+/mail/dovecot\\.mailbox\\.log(\\.[0-9])?$"
+ # sieve logfile: ~/dovecot.sieve
+ RegexFile = "^/home/mail/virtual/[^/]+/[^/]+/dovecot\\.sieve\\.log(\\.[0-9])?$"
+
+ # exclude queued files for SiS deduplication
+ Wild = "/home/mail/attachments/queue/*"
}
Options {
signature = SHA1
@@ -365,6 +436,37 @@ FileSet {
File = /home/mail/attachments
File = /home/mail/spamspool
}
+ Exclude {
+ File = "/home/mail/lost+found"
+ }
+}
+
+FileSet {
+ Name = NextcloudData
+ Include {
+ Options {
+ Exclude = yes
+ RegexFile = "^/mnt/nextcloud-data/nextcloud\\.log(\\.[0-9])?$"
+ RegexFile = "^/mnt/nextcloud-data/updater\\.log(\\.[0-9])?$"
+ RegexDir = "^/mnt/nextcloud-data/[a-z0-9\\-]+/files_trashbin$"
+ RegexDir = "^/mnt/nextcloud-data/[a-z0-9\\-]+/files_versions$"
+ RegexDir = "^/mnt/nextcloud-data/[a-z0-9\\-]+/cache$"
+ RegexDir = "^/mnt/nextcloud-data/[a-z0-9\\-]+/uploads$"
+ RegexDir = "^/mnt/nextcloud-data/__groupfolders/trash$"
+ RegexDir = "^/mnt/nextcloud-data/__groupfolders/versions$"
+ RegexDir = "^/mnt/nextcloud-data/updater-[[:alnum:]]+$"
+ RegexDir = "^/mnt/nextcloud-data/appdata_[[:alnum:]]+/preview$"
+ RegexDir = "^/mnt/nextcloud-data/appdata_[[:alnum:]]+/[^/]+/cache$"
+ }
+ Options {
+ signature = SHA1
+ verify = pins1
+ }
+ File = /mnt/nextcloud-data
+ }
+ Exclude {
+ File = "/mnt/nextcloud-data/lost+found"
+ }
}
@@ -435,9 +537,22 @@ Pool {
Pool Type = Backup
Recycle = yes
AutoPrune = yes
- Volume Retention = 26 weeks
- Maximum Volume Bytes = 5GB
- Label Format = "mailboxes-full-${NumVols:p/4/0/r}"
+ Volume Retention = 26 weeks # >13 weeks cycle
+ Maximum Volume Jobs = 1
+ Label Format = "mailboxes-full-"
+ Maximum Volumes = 3 # >2 volumes used at the end of retention period
+}
+
+# Mailbox pool definition (diff backup)
+Pool {
+ Name = mailboxes-diff
+ Pool Type = Backup
+ Recycle = yes
+ AutoPrune = yes
+ Volume Retention = 15 weeks # >13 weeks cycle
+ Maximum Volume Jobs = 1
+ Label Format = "mailboxes-diff-"
+ Maximum Volumes = 20 # >15 volumes used at the end of retention period
}
# Mailbox pool definition (inc backup)
@@ -446,9 +561,46 @@ Pool {
Pool Type = Backup
Recycle = yes
AutoPrune = yes
- Volume Retention = 26 weeks
- Maximum Volume Bytes = 5GB
- Label Format = "mailboxes-inc-${NumVols:p/4/0/r}"
+ Volume Retention = 8 days # >1 week cycle
+ Maximum Volume Jobs = 24 # group by day
+ Label Format = "mailboxes-inc-"
+ Maximum Volumes = 10 # >8 volumes used at the end of retention period
+}
+
+# Nextcloud pool definition (full backup)
+Pool {
+ Name = nextcloud-full
+ Pool Type = Backup
+ Recycle = yes
+ AutoPrune = yes
+ Volume Retention = 26 weeks # >13 weeks cycle
+ Maximum Volume Jobs = 1
+ Label Format = "nextcloud-full-"
+ Maximum Volumes = 3 # >2 volumes used at the end of retention period
+}
+
+# Nextcloud pool definition (diff backup)
+Pool {
+ Name = nextcloud-diff
+ Pool Type = Backup
+ Recycle = yes
+ AutoPrune = yes
+ Volume Retention = 15 weeks # >13 weeks cycle
+ Maximum Volume Jobs = 1
+ Label Format = "nextcloud-diff-"
+ Maximum Volumes = 20 # >15 volumes used at the end of retention period
+}
+
+# Nextcloud pool definition (inc backup)
+Pool {
+ Name = nextcloud-inc
+ Pool Type = Backup
+ Recycle = yes
+ AutoPrune = yes
+ Volume Retention = 8 days # >1 week cycle
+ Maximum Volume Jobs = 24 # group by day
+ Label Format = "nextcloud-inc-"
+ Maximum Volumes = 10 # >8 volumes used at the end of retention period
}
# Database pool definition
@@ -476,9 +628,9 @@ Catalog {
Messages {
Name = Standard
MailCommand = "/usr/sbin/bsmtp -h localhost:16132 -f \"\(Bacula\) \<bacula@fripost.org\>\" -s \"Bacula: %t %e of %n %l\" %r"
- Mail = admin@fripost.org = all, !skipped
+ Mail = root@fripost.org = all, !skipped
OperatorCommand = "/usr/sbin/bsmtp -h localhost:16132 -f \"\(Bacula\) \<bacula@fripost.org\>\" -s \"Bacula: Intervention needed for %j\" %r"
- Operator = admin@fripost.org = mount
+ Operator = root@fripost.org = mount
Console = all, !skipped, !saved
Append = "/var/log/bacula/bacula.log" = all, !skipped
Catalog = all
@@ -488,11 +640,11 @@ Messages {
Messages {
Name = Quiet
MailCommand = "/usr/sbin/bsmtp -h localhost:16132 -f \"\(Bacula\) \<bacula@fripost.org\>\" -s \"Bacula: %t %e of %n %l\" %r"
- Mail On Success = admin@fripost.org = all, !info, !fatal, !skipped, !notsaved, !restored
+ Mail On Success = root@fripost.org = all, !info, !fatal, !skipped, !notsaved, !restored
MailCommand = "/usr/sbin/bsmtp -h localhost:16132 -f \"\(Bacula\) \<bacula@fripost.org\>\" -s \"Bacula: %t %e of %n %l\" %r"
- Mail On Error = admin@fripost.org = all, !skipped
+ Mail On Error = root@fripost.org = all, !skipped
OperatorCommand = "/usr/sbin/bsmtp -h localhost:16132 -f \"\(Bacula\) \<bacula@fripost.org\>\" -s \"Bacula: Intervention needed for %j\" %r"
- Operator = admin@fripost.org = mount
+ Operator = root@fripost.org = mount
Console = all, !info, !restored, !skipped, !saved
Append = "/var/lib/bacula/log" = all, !skipped
Catalog = all
@@ -502,7 +654,7 @@ Messages {
Messages {
Name = Daemon
MailCommand = "/usr/sbin/bsmtp -h localhost:16132 -f \"\(Bacula\) \<bacula@fripost.org\>\" -s \"Bacula daemon message\" %r"
- Mail = admin@fripost.org = all, !skipped
+ Mail = root@fripost.org = all, !skipped
Console = all, !skipped, !saved
Append = "/var/log/bacula/bacula.log" = all, !skipped
}
diff --git a/roles/bacula-sd/files/etc/systemd/system/bacula-sd.service b/roles/bacula-sd/files/etc/systemd/system/bacula-sd.service.d/override.conf
index 30fa562..b228078 100644
--- a/roles/bacula-sd/files/etc/systemd/system/bacula-sd.service
+++ b/roles/bacula-sd/files/etc/systemd/system/bacula-sd.service.d/override.conf
@@ -1,27 +1,13 @@
-[Unit]
-Description=Bacula Storage Daemon service
-After=network.target
-
[Service]
-Type=simple
-StandardOutput=syslog
-User=bacula
-Group=tape
-ExecStart=/usr/sbin/bacula-sd -f -c /etc/bacula/bacula-sd.conf
-
# Hardening
NoNewPrivileges=yes
PrivateDevices=yes
ProtectHome=yes
ProtectSystem=strict
ReadWriteDirectories=-/var/lib/bacula
-ReadWriteDirectories=-/var/run/bacula
ReadWriteDirectories=/mnt/backup/bacula
PrivateDevices=yes
ProtectControlGroups=yes
ProtectKernelModules=yes
ProtectKernelTunables=yes
RestrictAddressFamilies=AF_INET AF_INET6
-
-[Install]
-WantedBy=multi-user.target
diff --git a/roles/bacula-sd/tasks/main.yml b/roles/bacula-sd/tasks/main.yml
index 93958a8..f30fe7f 100644
--- a/roles/bacula-sd/tasks/main.yml
+++ b/roles/bacula-sd/tasks/main.yml
@@ -1,7 +1,7 @@
- name: Install bacula-sd
apt: pkg=bacula-sd
-# Create with:
+# Populate with:
# echo $director-dir $(pwgen -sn 64 1) | sudo tee -a /etc/bacula/passwords-sd
- name: Ensure /etc/bacula/passwords-sd exists
file: path=/etc/bacula/passwords-sd
@@ -17,9 +17,15 @@
notify:
- Restart bacula-sd
-- name: Copy bacula-sd.service
- copy: src=etc/systemd/system/bacula-sd.service
- dest=/etc/systemd/system/bacula-sd.service
+- name: Create /etc/systemd/system/bacula-sd.service.d
+ file: path=/etc/systemd/system/bacula-sd.service.d
+ state=directory
+ owner=root group=root
+ mode=0755
+
+- name: Copy bacula-sd.service override
+ copy: src=etc/systemd/system/bacula-sd.service.d/override.conf
+ dest=/etc/systemd/system/bacula-sd.service.d/override.conf
owner=root group=root
mode=0644
notify:
diff --git a/roles/bacula-sd/templates/etc/bacula/bacula-sd.conf.j2 b/roles/bacula-sd/templates/etc/bacula/bacula-sd.conf.j2
index 3cbf7fe..a898e0d 100644
--- a/roles/bacula-sd/templates/etc/bacula/bacula-sd.conf.j2
+++ b/roles/bacula-sd/templates/etc/bacula/bacula-sd.conf.j2
@@ -1,7 +1,7 @@
#
# Default Bacula Storage Daemon Configuration file
#
-# For Bacula release 5.2.6 (21 February 2012) -- debian jessie/sid
+# For Bacula release 9.4.2 (04 February 2019) -- debian buster/sid
#
# You may need to change the name of your tape drive
# on the "Archive Device" directive in the Device
@@ -13,7 +13,7 @@
Storage { # define myself
Name = {{ inventory_hostname_short }}-sd
Working Directory = /var/lib/bacula
- Pid Directory = /var/run/bacula
+ Pid Directory = /run/bacula
Maximum Concurrent Jobs = 20
SDAddress = {{ ipsec[inventory_hostname_short] }}
SDPort = 9103
diff --git a/roles/common-LDAP/files/usr/local/sbin/slapcat-all.sh b/roles/common-LDAP/files/usr/local/sbin/slapcat-all.sh
index cd5abd9..db128c9 100755
--- a/roles/common-LDAP/files/usr/local/sbin/slapcat-all.sh
+++ b/roles/common-LDAP/files/usr/local/sbin/slapcat-all.sh
@@ -1,20 +1,31 @@
#!/bin/sh
# Usage: slapcat-all.sh DIR
-# Save all LDAP databases in DIR: DIR/0.ldif, DIR/1.ldif, ...
+# Save all LDAP databases in DIR: DIR/SUFFIX0.ldif, DIR/SUFFIX1.ldif, ...
set -ue
-PATH=/usr/sbin:/sbin:/usr/bin:/bin
+PATH="/usr/bin:/bin"
+export PATH
-target="$1"
+TARGET="$1"
umask 0077
-prefix=slapcat-
-slapcat -n0 -l"$target/${prefix}0.ldif"
-n=$(grep -Ec '^dn:\s+olcDatabase={[1-9][0-9]*}' "$target/${prefix}0.ldif")
+ldapsearch() {
+ command ldapsearch -H "ldapi://" -QY EXTERNAL "$@"
+}
-while [ $n -gt 0 ]; do
- # the Monitor backend can't be slapcat(8)'ed
- grep -qE "^dn:\s+olcDatabase=\{$n\}monitor,cn=config$" "$target/${prefix}0.ldif" || slapcat -n$n -l"$target/${prefix}$n.ldif"
- n=$(( $n - 1 ))
-done
+backup_database() {
+ local base="$1"
+ ldapsearch -b "$base" \+ \* >"$TARGET/$base.ldif"
+}
+
+backup_database "cn=config"
+
+SUFFIXES="$TARGET/slapd-suffixes"
+ldapsearch -LLL -oldif-wrap="no" -b "cn=config" "(&(objectClass=olcDatabaseConfig)(objectClass=olcMdbConfig))" "olcSuffix" >"$SUFFIXES"
+sed -n -i "s/^olcSuffix:\\s*//p" "$SUFFIXES"
+
+while IFS= read -r b; do
+ [ "${b%,dc=fripost-test,dc=org}" = "$b" ] || continue
+ backup_database "$b"
+done <"$SUFFIXES"
diff --git a/roles/common-LDAP/tasks/main.yml b/roles/common-LDAP/tasks/main.yml
index 5255cdf..e17bc3a 100644
--- a/roles/common-LDAP/tasks/main.yml
+++ b/roles/common-LDAP/tasks/main.yml
@@ -8,7 +8,7 @@
- ldap-utils
- ldapvi
- db-util
- - python-ldap
+ - python3-ldap
# for the 'slapd2' munin plugin
- libnet-ldap-perl
- libauthen-sasl-perl
@@ -30,28 +30,34 @@
tags:
- genkey
-# XXX: It's ugly to list all roles here, and to prunes them with a
-# conditional...
- name: Generate a private key and a X.509 certificate for slapd
- # XXX: GnuTLS (libgnutls26 2.12.20-8+deb7u2, found in Wheezy) doesn't
- # support ECDSA; and slapd doesn't seem to support DHE (!?) so
- # we're stuck with "plain RSA" Key-Exchange. Also, there is a bug with
- # SHA-512.
command: genkeypair.sh x509
--pubkey=/etc/ldap/ssl/{{ item.name }}.pem
--privkey=/etc/ldap/ssl/{{ item.name }}.key
--ou=LDAP {{ item.ou }} --cn={{ item.name }}
- --usage=digitalSignature,keyEncipherment,keyCertSign
- -t rsa -b 4096 -h sha256
+ --usage=digitalSignature,keyEncipherment
+ -t ed25519
--owner=root --group=openldap --mode=0640
register: r2
changed_when: r2.rc == 0
failed_when: r2.rc > 1
with_items:
- - { group: 'LDAP-provider', name: ldap.fripost.org, ou: }
+ - { group: 'LDAP_provider', name: ldap.fripost.org, ou: }
- { group: 'MX', name: mx, ou: --ou=SyncRepl }
- { group: 'lists', name: lists, ou: --ou=SyncRepl }
when: "item.group in group_names"
+ notify:
+ - Restart slapd
+ tags:
+ - genkey
+
+- name: Fetch the SyncProv's X.509 certificate
+ # Ensure we don't fetch private data
+ become: False
+ fetch_cmd: cmd="openssl x509"
+ stdin=/etc/ldap/ssl/ldap.fripost.org.pem
+ dest=certs/ldap/ldap.fripost.org.pem
+ when: "'LDAP_provider' in group_names"
tags:
- genkey
@@ -60,9 +66,8 @@
become: False
fetch_cmd: cmd="openssl x509"
stdin=/etc/ldap/ssl/{{ item.name }}.pem
- dest=certs/ldap/{{ item.name }}.pem
+ dest=certs/ldap/syncrepl/{{ item.name }}@{{ inventory_hostname_short }}.pem
with_items:
- - { group: 'LDAP-provider', name: ldap.fripost.org }
- { group: 'MX', name: mx }
- { group: 'lists', name: lists }
when: "item.group in group_names"
@@ -74,22 +79,25 @@
dest=/etc/ldap/ssl/ldap.fripost.org.pem
owner=root group=root
mode=0644
- when: "'LDAP-provider' not in group_names"
+ when: "'LDAP_provider' not in group_names"
tags:
- genkey
- name: Copy the SyncRepls's client certificates
- assemble: src=certs/ldap remote_src=no
- dest=/etc/ldap/ssl/clients.pem
+ assemble: src=certs/ldap/syncrepl remote_src=no
+ dest=/etc/ldap/ssl/syncrepl.pem
owner=root group=root
mode=0644
- when: "'LDAP-provider' in group_names"
+ when: "'LDAP_provider' in group_names"
tags:
- genkey
+ register: r3
+ notify:
+ - Restart slapd
- name: Start slapd
service: name=slapd state=started
- when: not (r1.changed or r2.changed)
+ when: not (r1.changed or r2.changed or r3.changed)
- meta: flush_handlers
diff --git a/roles/common-LDAP/templates/etc/default/slapd.j2 b/roles/common-LDAP/templates/etc/default/slapd.j2
index fdd7481..dd3f87e 100644
--- a/roles/common-LDAP/templates/etc/default/slapd.j2
+++ b/roles/common-LDAP/templates/etc/default/slapd.j2
@@ -23,7 +23,7 @@ SLAPD_SERVICES="ldapi:///"
{% for i in group_names | intersect(['MX','lists','MSA']) | sort %}
SLAPD_SERVICES="$SLAPD_SERVICES ldapi://%2Fvar%2Fspool%2Fpostfix-{{ postfix_instance[i].name }}%2Fprivate%2Fldapi/"
{% endfor %}
-{% if 'LDAP-provider' in group_names %}
+{% if 'LDAP_provider' in group_names %}
SLAPD_SERVICES="$SLAPD_SERVICES ldaps:///"
{% endif %}
diff --git a/roles/common-LDAP/templates/etc/ldap/database.ldif.j2 b/roles/common-LDAP/templates/etc/ldap/database.ldif.j2
index b9f282f..f10bb33 100644
--- a/roles/common-LDAP/templates/etc/ldap/database.ldif.j2
+++ b/roles/common-LDAP/templates/etc/ldap/database.ldif.j2
@@ -17,8 +17,8 @@
dn: cn=config
objectClass: olcGlobal
cn: config
-olcArgsFile: /var/run/slapd/slapd.args
-olcPidFile: /var/run/slapd/slapd.pid
+olcArgsFile: /run/slapd/slapd.args
+olcPidFile: /run/slapd/slapd.pid
olcLogLevel: none
olcToolThreads: 1
{% if ansible_processor_vcpus > 4 %}
@@ -26,7 +26,7 @@ olcThreads: {{ 2 * ansible_processor_vcpus }}
{% else %}
olcThreads: 8
{% endif %}
-{% if 'LDAP-provider' in group_names %}
+{% if 'LDAP_provider' in group_names %}
olcTLSCertificateFile: /etc/ldap/ssl/ldap.fripost.org.pem
olcTLSCertificateKeyFile: /etc/ldap/ssl/ldap.fripost.org.key
# If we are being offered a client cert, it has to be trusted (in which
@@ -34,11 +34,12 @@ olcTLSCertificateKeyFile: /etc/ldap/ssl/ldap.fripost.org.key
# terminate the connection. Not providing a certificate is fine for
# TLS-protected simple binds, though.
olcTLSVerifyClient: try
-olcTLSCACertificateFile: /etc/ldap/ssl/clients.pem
+olcTLSCACertificateFile: /etc/ldap/ssl/syncrepl.pem
olcAuthzRegexp: "^(cn=[^,]+,ou=syncRepl),ou=LDAP,ou=SSLcerts,o=Fripost$"
"dn.exact:$1,dc=fripost,dc=org"
olcSaslSecProps: minssf=128,noanonymous,noplain,nodict
olcTLSCipherSuite: PFS:%LATEST_RECORD_VERSION:!CIPHER-ALL:+AES-128-GCM:+AES-256-GCM:!VERS-SSL3.0:!VERS-TLS1.0:!VERS-TLS1.1
+olcTLSDHParamFile: /etc/ssl/dhparams.pem
{% endif %}
olcLocalSSF: 128
# /!\ This is not portable! But we only use glibc's crypt(3), which
@@ -61,10 +62,10 @@ objectClass: olcDatabaseConfig
objectClass: olcMdbConfig
olcDbDirectory: /var/lib/ldap
olcSuffix: dc=fripost,dc=org
-{% if 'LDAP-provider' not in group_names and 'MX' in group_names %}
+{% if 'LDAP_provider' not in group_names and 'MX' in group_names %}
olcReadOnly: TRUE
{% endif %}
-{% if 'LDAP-provider' in group_names %}
+{% if 'LDAP_provider' in group_names %}
olcLastMod: TRUE
olcDbCheckpoint: 512 15
{% else %}
@@ -91,23 +92,23 @@ olcSecurity: simple_bind=128 ssf=128 update_ssf=128
#
olcDbIndex: objectClass eq
# Let us make Postfix's life easier.
-{% if 'LDAP-provider' in group_names %}
+{% if 'LDAP_provider' in group_names %}
olcDbIndex: fvd,fvl eq,sub
olcDbIndex: fripostIsStatusActive eq
{% elif 'MX' in group_names or 'MDA' in group_names %}
olcDbIndex: fripostIsStatusActive,fvd,fvl eq
{% endif %}
-{% if 'LDAP-provider' in group_names %}
+{% if 'LDAP_provider' in group_names %}
olcDbIndex: fripostOptionalMaildrop,fripostMaildrop eq,sub
olcDbIndex: fripostCanAddDomain,fripostCanAddAlias,fripostCanAddList,fripostOwner,fripostPostmaster,fripostListManager eq
{% elif 'MX' in group_names %}
olcDbIndex: fripostOptionalMaildrop pres
{% endif %}
-{% if 'LDAP-provider' in group_names %}
+{% if 'LDAP_provider' in group_names %}
olcDbIndex: member,cn eq
{% endif %}
-{% if ('LDAP-provider' not in group_names and 'MX' in group_names) or
- ('LDAP-provider' in group_names and groups.MX | difference([inventory_hostname])) %}
+{% if ('LDAP_provider' not in group_names and 'MX' in group_names) or
+ ('LDAP_provider' in group_names and groups.MX | difference([inventory_hostname])) %}
# SyncProv/SyncRepl specific indexing.
olcDbIndex: entryCSN,entryUUID eq
{% endif%}
@@ -128,14 +129,14 @@ olcDbIndex: entryCSN,entryUUID eq
# - http://www.openldap.org/doc/admin24/replication.html#Syncrepl
# - http://www.zytrax.com/books/ldap/ch7/#ol-syncrepl-rap
#
-{% if 'LDAP-provider' in group_names %}
+{% if 'LDAP_provider' in group_names %}
olcLimits: dn.onelevel="ou=syncRepl,dc=fripost,dc=org"
time.soft=unlimited
time.hard=unlimited
size.soft=unlimited
size.hard=unlimited
{% endif %}
-{% if 'MX' in group_names and 'LDAP-provider' not in group_names %}
+{% if 'MX' in group_names and 'LDAP_provider' not in group_names %}
# Test it:
# LDAPSASL_MECH=external LDAPTLS_CACERT=/etc/ldap/ssl/ldap.fripost.org.pem LDAPTLS_CERT=/etc/ldap/ssl/mx.pem LDAPTLS_KEY=/etc/ldap/ssl/mx.key sudo -u openldap ldapwhoami -H ldaps://ldap.fripost.org/
# LDAPSASL_MECH=external LDAPTLS_CACERT=/etc/ldap/ssl/ldap.fripost.org.pem LDAPTLS_CERT=/etc/ldap/ssl/mx.pem LDAPTLS_KEY=/etc/ldap/ssl/mx.key sudo -u openldap ldapsearch -H ldaps://ldap.fripost.org/ -b ou=virtual,dc=fripost,dc=org
@@ -215,7 +216,7 @@ olcAccess: to dn.regex="^fvl=[^,]+,(fvd=[^,]+,ou=virtual,dc=fripost,dc=org)$"
by group.exact="cn=admin,ou=groups,dc=fripost,dc=org" =w
#
# * Services can authenticate
-{% if 'LDAP-provider' in group_names -%}
+{% if 'LDAP_provider' in group_names -%}
olcAccess: to dn.onelevel="ou=services,dc=fripost,dc=org"
filter=(objectClass=simpleSecurityObject)
attrs=userPassword
@@ -233,7 +234,7 @@ olcAccess: to dn.subtree="dc=fripost,dc=org"
#
# * Only SyncRepl replicates may access operational attributes in the
# subtree, when using a TLS-protected connection.
-{% if 'LDAP-provider' in group_names -%}
+{% if 'LDAP_provider' in group_names -%}
olcAccess: to dn.subtree="ou=virtual,dc=fripost,dc=org"
attrs=entryCSN,structuralObjectClass,hasSubordinates,subschemaSubentry
by dn.onelevel="ou=syncRepl,dc=fripost,dc=org" tls_ssf=128 =rsd
@@ -256,20 +257,23 @@ olcAccess: to dn.children="ou=virtual,dc=fripost,dc=org"
# * Postfix may use the base as a searchBase on the MX:es, when
# connecting a local ldapi:// socket from the 'private' directory in
# one of the non-default instance's chroot.
-# * So may Dovecot on the MDA (needed for the iterate filter), when
-# SASL-binding using the EXTERNAL mechanism and connecting to a local
-# ldapi:// socket.
+# * So may _dovecot-auth-proxy on the MDA (needed for the iterate
+# logic), when SASL-binding using the EXTERNAL mechanism and
+# connecting to a local ldapi:// socket.
# * So may Nextcloud on the LDAP provider
olcAccess: to dn.exact="ou=virtual,dc=fripost,dc=org"
attrs=entry,objectClass
filter=(objectClass=FripostVirtual)
{% if 'MDA' in group_names -%}
- by dn.exact="username=dovecot,cn=peercred,cn=external,cn=auth" sockurl.regex="^ldapi://" =sd
+ by dn.exact="username=_dovecot-auth-proxy,cn=peercred,cn=external,cn=auth" sockurl.regex="^ldapi://" =sd
{% endif -%}
- {% if 'MX' in group_names or 'MSA' in group_names -%}
+ {% if 'MX' in group_names -%}
by dn.exact="username=postfix,cn=peercred,cn=external,cn=auth" sockurl.regex="^ldapi://%2Fvar%2Fspool%2Fpostfix-[-[:alnum:]]+%2Fprivate%2F" =sd
{% endif -%}
- {% if 'LDAP-provider' in group_names -%}
+ {% if 'MSA' in group_names -%}
+ by dn.exact="username=_postfix-sender-login,cn=peercred,cn=external,cn=auth" sockurl.regex="^ldapi://" =sd
+ {% endif -%}
+ {% if 'LDAP_provider' in group_names -%}
by dn.exact="cn=nextcloud,ou=services,dc=fripost,dc=org" tls_ssf=128 =sd
{% endif -%}
by users =0 break
@@ -281,30 +285,35 @@ olcAccess: to dn.exact="ou=virtual,dc=fripost,dc=org"
# using a TLS-protected connection.
# * So has Postfix, when connecting a local ldapi:// socket from the
# 'private' directory in one of the non-default instance's chroot.
-# * So has Dovecot on the MDA (for the iterate filter), when
-# SASL-binding using the EXTERNAL mechanism and connecting to a local
-# ldapi:// socket.
-# * Amavis may use the entry as searchBase (required to look for the
-# per-user preferences) but doesn't have read access to the entry.
# * The 'nobody' UNIX user has read access on the MX:es, when using
# SASL-binding using the EXTERNAL mechanism and connecting to a local
# ldapi:// socket. This is required for the 'reserved-alias.pl'
# script.
+# * Amavis may use the entry as searchBase (required to look for the
+# per-user preferences) but doesn't have read access to the entry.
+# * So has _dovecot-auth-proxy on the MDA (for the iterate logic), when
+# SASL-binding using the EXTERNAL mechanism and connecting to a local
+# ldapi:// socket.
+# * So has _postfix-sender-login on the submission service to verify
+# envelope sender ownership
olcAccess: to dn.regex="^fvd=[^,]+,ou=virtual,dc=fripost,dc=org$"
attrs=entry,objectClass,fvd
filter=(&(objectClass=FripostVirtualDomain)(!(objectClass=FripostPendingEntry)))
- {% if 'LDAP-provider' in group_names -%}
- {% if groups.MX | difference([inventory_hostname]) -%}
+ {% if 'LDAP_provider' in group_names and groups.MX | difference([inventory_hostname]) -%}
by dn.exact="cn=mX,ou=syncRepl,dc=fripost,dc=org" tls_ssf=128 =rsd
{% endif -%}
- {% endif -%}
+ {% if 'MX' in group_names -%}
by dn.exact="username=postfix,cn=peercred,cn=external,cn=auth" sockurl.regex="^ldapi://%2Fvar%2Fspool%2Fpostfix-[-[:alnum:]]+%2Fprivate%2F" =rsd
+ by dn.exact="username=nobody,cn=peercred,cn=external,cn=auth" sockurl.regex="^ldapi://" =rsd
+ {% endif -%}
{% if 'MDA' in group_names -%}
- by dn.exact="username=dovecot,cn=peercred,cn=external,cn=auth" sockurl.regex="^ldapi://" =rsd
by dn.exact="username=amavis,cn=peercred,cn=external,cn=auth" sockurl.regex="^ldapi://" =sd
{% endif -%}
- {% if 'MX' in group_names -%}
- by dn.exact="username=nobody,cn=peercred,cn=external,cn=auth" sockurl.regex="^ldapi://" =rsd
+ {% if 'IMAP' in group_names -%}
+ by dn.exact="username=_dovecot-auth-proxy,cn=peercred,cn=external,cn=auth" sockurl.regex="^ldapi://" =rsd
+ {% endif -%}
+ {% if 'MSA' in group_names -%}
+ by dn.exact="username=_postfix-sender-login,cn=peercred,cn=external,cn=auth" sockurl.regex="^ldapi://" =rsd
{% endif -%}
by users =0 break
#
@@ -314,11 +323,11 @@ olcAccess: to dn.regex="^fvd=[^,]+,ou=virtual,dc=fripost,dc=org$"
# * So can Postfix on the MX:es, when connecting a local ldapi:// socket
# from the 'private' directory in one of the non-default instance's
# chroot.
-{% if 'MX' in group_names or ('LDAP-provider' in group_names and groups.MX | difference([inventory_hostname])) %}
+{% if 'MX' in group_names or ('LDAP_provider' in group_names and groups.MX | difference([inventory_hostname])) %}
olcAccess: to dn.regex="^fvd=[^,]+,ou=virtual,dc=fripost,dc=org$"
attrs=fripostIsStatusActive,fripostOptionalMaildrop
filter=(&(objectClass=FripostVirtualDomain)(!(objectClass=FripostPendingEntry)))
- {% if 'LDAP-provider' in group_names and groups.MX | difference([inventory_hostname]) -%}
+ {% if 'LDAP_provider' in group_names and groups.MX | difference([inventory_hostname]) -%}
by dn.exact="cn=mX,ou=syncRepl,dc=fripost,dc=org" tls_ssf=128 =rsd
{% endif -%}
{% if 'MX' in group_names -%}
@@ -334,7 +343,7 @@ olcAccess: to dn.regex="^fvd=[^,]+,ou=virtual,dc=fripost,dc=org$"
olcAccess: to dn.regex="^fvd=[^,]+,ou=virtual,dc=fripost,dc=org$"
attrs=fripostOwner,fripostPostmaster
filter=(&(objectClass=FripostVirtualDomain)(!(objectClass=FripostPendingEntry)))
- {% if 'LDAP-provider' in group_names and groups.MX | difference([inventory_hostname]) -%}
+ {% if 'LDAP_provider' in group_names and groups.MX | difference([inventory_hostname]) -%}
by dn.exact="cn=mX,ou=syncRepl,dc=fripost,dc=org" tls_ssf=128 =rsd
{% endif -%}
{% if 'MX' in group_names %}
@@ -351,11 +360,11 @@ olcAccess: to dn.regex="^fvd=[^,]+,ou=virtual,dc=fripost,dc=org$"
# * So has Postfix on the MX:es, when connecting a local ldapi:// socket
# from the 'private' directory in one of the non-default instance's
# chroot.
-{% if 'MX' in group_names or ('LDAP-provider' in group_names and groups.MX | difference([inventory_hostname])) %}
+{% if 'MX' in group_names or ('LDAP_provider' in group_names and groups.MX | difference([inventory_hostname])) %}
olcAccess: to dn.regex="^fvd=[^,]+,ou=virtual,dc=fripost,dc=org$"
attrs=entry,fripostMaildrop
filter=(&(objectClass=FripostVirtualAliasDomain)(!(objectClass=FripostPendingEntry)))
- {% if 'LDAP-provider' in group_names and groups.MX | difference([inventory_hostname]) -%}
+ {% if 'LDAP_provider' in group_names and groups.MX | difference([inventory_hostname]) -%}
by dn.exact="cn=mX,ou=syncRepl,dc=fripost,dc=org" tls_ssf=128 =rsd
{% endif -%}
{% if 'MX' in group_names -%}
@@ -371,7 +380,7 @@ olcAccess: to dn.regex="^fvd=[^,]+,ou=virtual,dc=fripost,dc=org$"
# using a TLS-protected connection.
# * So has Postfix, when connecting a local ldapi:// socket from the
# 'private' directory in one of the non-default instance's chroot.
-# * So has Dovecot on the MDA (for the iterate filter), when
+# * So has _dovecot-auth-proxy on the MDA (for the iterate logic), when
# SASL-binding using the EXTERNAL mechanism and connecting to a local
# ldapi:// socket.
# * So has Amavis on the MDA, when SASL-binding using the EXTERNAL
@@ -379,14 +388,21 @@ olcAccess: to dn.regex="^fvd=[^,]+,ou=virtual,dc=fripost,dc=org$"
olcAccess: to dn.regex="^fvl=[^,]+,fvd=[^,]+,ou=virtual,dc=fripost,dc=org$"
attrs=entry,objectClass,fvl
filter=(objectClass=FripostVirtualUser)
- {% if 'LDAP-provider' in group_names and groups.MX | difference([inventory_hostname]) -%}
+ {% if 'LDAP_provider' in group_names and groups.MX | difference([inventory_hostname]) -%}
by dn.exact="cn=mX,ou=syncRepl,dc=fripost,dc=org" tls_ssf=128 =rsd
{% endif -%}
+ {% if 'MX' in group_names -%}
by dn.exact="username=postfix,cn=peercred,cn=external,cn=auth" sockurl.regex="^ldapi://%2Fvar%2Fspool%2Fpostfix-[-[:alnum:]]+%2Fprivate%2F" =rsd
+ {% endif -%}
{% if 'MDA' in group_names -%}
- by dn.exact="username=dovecot,cn=peercred,cn=external,cn=auth" sockurl.regex="^ldapi://" =rsd
by dn.exact="username=amavis,cn=peercred,cn=external,cn=auth" sockurl.regex="^ldapi://" =rsd
{% endif -%}
+ {% if 'IMAP' in group_names -%}
+ by dn.exact="username=_dovecot-auth-proxy,cn=peercred,cn=external,cn=auth" sockurl.regex="^ldapi://" =rsd
+ {% endif -%}
+ {% if 'MSA' in group_names -%}
+ by dn.exact="username=_postfix-sender-login,cn=peercred,cn=external,cn=auth" sockurl.regex="^ldapi://" =rsd
+ {% endif -%}
by users =0 break
#
# * The SyncRepl MX replicates can check whether a virtual user is
@@ -394,11 +410,11 @@ olcAccess: to dn.regex="^fvl=[^,]+,fvd=[^,]+,ou=virtual,dc=fripost,dc=org$"
# * So can Postfix on the MX:es, when connecting a local ldapi:// socket
# from the 'private' directory in one of the non-default instance's
# chroot.
-{% if 'MX' in group_names or ('LDAP-provider' in group_names and groups.MX | difference([inventory_hostname])) %}
+{% if 'MX' in group_names or ('LDAP_provider' in group_names and groups.MX | difference([inventory_hostname])) %}
olcAccess: to dn.regex="^fvl=[^,]+,fvd=[^,]+,ou=virtual,dc=fripost,dc=org$"
attrs=fripostIsStatusActive,fripostUseContentFilter
filter=(objectClass=FripostVirtualUser)
- {% if 'LDAP-provider' in group_names and groups.MX | difference([inventory_hostname]) -%}
+ {% if 'LDAP_provider' in group_names and groups.MX | difference([inventory_hostname]) -%}
by dn.exact="cn=mX,ou=syncRepl,dc=fripost,dc=org" tls_ssf=128 =rsd
{% endif -%}
{% if 'MX' in group_names -%}
@@ -437,11 +453,11 @@ olcAccess: to dn.regex="^fvl=[^,]+,fvd=[^,]+,ou=virtual,dc=fripost,dc=org$"
# * So can Postfix on the MX:es, when connecting a local ldapi:// socket
# from the 'private' directory in one of the non-default instance's
# chroot.
-{% if 'MX' in group_names or ('LDAP-provider' in group_names and groups.MX | difference([inventory_hostname])) %}
+{% if 'MX' in group_names or ('LDAP_provider' in group_names and groups.MX | difference([inventory_hostname])) %}
olcAccess: to dn.regex="^fvl=[^,]+,fvd=[^,]+,ou=virtual,dc=fripost,dc=org$"
attrs=entry,objectClass,fvl,fripostMaildrop,fripostIsStatusActive
filter=(objectClass=FripostVirtualAlias)
- {% if 'LDAP-provider' in group_names and groups.MX | difference([inventory_hostname]) -%}
+ {% if 'LDAP_provider' in group_names and groups.MX | difference([inventory_hostname]) -%}
by dn.exact="cn=mX,ou=syncRepl,dc=fripost,dc=org" tls_ssf=128 =rsd
{% endif -%}
{% if 'MX' in group_names -%}
@@ -457,11 +473,11 @@ olcAccess: to dn.regex="^fvl=[^,]+,fvd=[^,]+,ou=virtual,dc=fripost,dc=org$"
# using a TLS-protected connection.
# * So can Postfix on the MX:es, when connecting a local ldapi:// socket
# from the 'private' directory in one of the non-default instance's chroot.
-{% if 'MX' in group_names or ('LDAP-provider' in group_names and groups.MX | difference([inventory_hostname])) %}
+{% if 'MX' in group_names or ('LDAP_provider' in group_names and groups.MX | difference([inventory_hostname])) %}
olcAccess: to dn.regex="^fvl=[^,]+,fvd=[^,]+,ou=virtual,dc=fripost,dc=org$"
attrs=entry,objectClass,fvl,fripostListManager
filter=(&(objectClass=FripostVirtualList)(!(objectClass=FripostPendingEntry)))
- {% if 'LDAP-provider' in group_names and groups.MX | difference([inventory_hostname]) -%}
+ {% if 'LDAP_provider' in group_names and groups.MX | difference([inventory_hostname]) -%}
by dn.exact="cn=mX,ou=syncRepl,dc=fripost,dc=org" tls_ssf=128 =rsd
{% endif -%}
{% if 'MX' in group_names -%}
@@ -475,11 +491,11 @@ olcAccess: to dn.regex="^fvl=[^,]+,fvd=[^,]+,ou=virtual,dc=fripost,dc=org$"
# * So can Postfix on the MX:es, when connecting a local ldapi:// socket
# from the 'private' directory in one of the non-default instance's
# chroot.
-{% if 'MX' in group_names or ('LDAP-provider' in group_names and groups.MX | difference([inventory_hostname])) %}
+{% if 'MX' in group_names or ('LDAP_provider' in group_names and groups.MX | difference([inventory_hostname])) %}
olcAccess: to dn.regex="^fvl=[^,]+,fvd=[^,]+,ou=virtual,dc=fripost,dc=org$"
attrs=fripostIsStatusActive
filter=(&(objectClass=FripostVirtualList)(!(objectClass=FripostPendingEntry)))
- {% if 'LDAP-provider' in group_names and groups.MX | difference([inventory_hostname]) -%}
+ {% if 'LDAP_provider' in group_names and groups.MX | difference([inventory_hostname]) -%}
by dn.exact="cn=mX,ou=syncRepl,dc=fripost,dc=org" tls_ssf=128 =rsd
{% endif -%}
{% if 'MX' in group_names -%}
@@ -488,21 +504,21 @@ olcAccess: to dn.regex="^fvl=[^,]+,fvd=[^,]+,ou=virtual,dc=fripost,dc=org$"
by users =0 break
{% endif %}
#
-# * The MSA's postfix user can read entry ownership to dermine the SASL
-# login name(s) owning a given sender address
+# * The MSA's _postfix-sender-login user can read entry ownership to
+# dermine the SASL login name(s) owning a given sender address
{% if 'MSA' in group_names %}
olcAccess: to dn.regex="^fvd=[^,]+,ou=virtual,dc=fripost,dc=org$"
attrs=fripostOwner,fripostPostmaster
filter=(|(objectClass=FripostVirtualAliasDomain)(objectClass=FripostVirtualDomain))
- by dn.exact="username=postfix,cn=peercred,cn=external,cn=auth" sockurl.regex="^ldapi://%2Fvar%2Fspool%2Fpostfix-[-[:alnum:]]+%2Fprivate%2F" =rsd
- by users =0 break
+ by dn.exact="username=_postfix-sender-login,cn=peercred,cn=external,cn=auth" sockurl.regex="^ldapi://" =rsd
+ by users =0 break
olcAccess: to dn.regex="^fvl=[^,]+,fvd=[^,]+,ou=virtual,dc=fripost,dc=org$"
attrs=entry,objectClass,fvl,fripostOwner
filter=(|(objectClass=FripostVirtualAlias)(objectClass=FripostVirtualList)(objectClass=FripostVirtualUser))
- by dn.exact="username=postfix,cn=peercred,cn=external,cn=auth" sockurl.regex="^ldapi://%2Fvar%2Fspool%2Fpostfix-[-[:alnum:]]+%2Fprivate%2F" =rsd
- by users =0 break
+ by dn.exact="username=_postfix-sender-login,cn=peercred,cn=external,cn=auth" sockurl.regex="^ldapi://" =rsd
+ by users =0 break
{% endif %}
-{% if 'LDAP-provider' in group_names %}
+{% if 'LDAP_provider' in group_names %}
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
@@ -522,6 +538,11 @@ olcAccess: to dn.exact="ou=groups,dc=fripost,dc=org"
by dn.exact="cn=nextcloud,ou=services,dc=fripost,dc=org" tls_ssf=128 =rsd
by users =0 break
olcAccess: to dn.exact="cn=medlemmar,ou=groups,dc=fripost,dc=org"
+ attrs=entry,entryDN,entryUUID,objectClass,cn,description,member
+ by dn.exact="cn=nextcloud,ou=services,dc=fripost,dc=org" tls_ssf=128 =rsd
+ by users =0 break
+olcAccess: to dn.exact="cn=styrelse,ou=groups,dc=fripost,dc=org"
+ attrs=entry,entryDN,entryUUID,objectClass,cn,description,member
by dn.exact="cn=nextcloud,ou=services,dc=fripost,dc=org" tls_ssf=128 =rsd
by users =0 break
#
diff --git a/roles/common-SQL/files/etc/mysql/mariadb.conf.d/99-user.cnf b/roles/common-SQL/files/etc/mysql/mariadb.conf.d/99-user.cnf
new file mode 100644
index 0000000..f3323f9
--- /dev/null
+++ b/roles/common-SQL/files/etc/mysql/mariadb.conf.d/99-user.cnf
@@ -0,0 +1,4 @@
+[mysqld]
+skip-networking
+innodb_file_per_table
+innodb_flush_method = O_DIRECT
diff --git a/roles/common-SQL/files/etc/mysql/my.cnf b/roles/common-SQL/files/etc/mysql/my.cnf
deleted file mode 100644
index e1dff58..0000000
--- a/roles/common-SQL/files/etc/mysql/my.cnf
+++ /dev/null
@@ -1,131 +0,0 @@
-#
-# The MySQL database server configuration file.
-#
-# You can copy this to one of:
-# - "/etc/mysql/my.cnf" to set global options,
-# - "~/.my.cnf" to set user-specific options.
-#
-# One can use all long options that the program supports.
-# Run program with --help to get a list of available options and with
-# --print-defaults to see which it would actually understand and use.
-#
-# For explanations see
-# http://dev.mysql.com/doc/mysql/en/server-system-variables.html
-
-# This will be passed to all mysql clients
-# It has been reported that passwords should be enclosed with ticks/quotes
-# escpecially if they contain "#" chars...
-# Remember to edit /etc/mysql/debian.cnf when changing the socket location.
-[client]
-port = 3306
-socket = /var/run/mysqld/mysqld.sock
-
-# Here is entries for some specific programs
-# The following values assume you have at least 32M ram
-
-# This was formally known as [safe_mysqld]. Both versions are currently parsed.
-[mysqld_safe]
-socket = /var/run/mysqld/mysqld.sock
-nice = 0
-
-[mysqld]
-#
-# * Basic Settings
-#
-user = mysql
-pid-file = /var/run/mysqld/mysqld.pid
-socket = /var/run/mysqld/mysqld.sock
-port = 3306
-basedir = /usr
-datadir = /var/lib/mysql
-tmpdir = /tmp
-lc-messages-dir = /usr/share/mysql
-character_set_server = utf8
-collation_server = utf8_unicode_ci
-skip-external-locking
-#
-# Instead of skip-networking the default is now to listen only on
-# localhost which is more compatible and is not less secure.
-#bind-address = 127.0.0.1
-skip-networking
-#
-# * Fine Tuning
-#
-key_buffer_size = 16M
-max_allowed_packet = 16M
-thread_stack = 192K
-thread_cache_size = 8
-# This replaces the startup script and checks MyISAM tables if needed
-# the first time they are touched
-myisam-recover = BACKUP
-#max_connections = 100
-#table_cache = 64
-#thread_concurrency = 10
-#
-# * Query Cache Configuration
-#
-query_cache_limit = 1M
-query_cache_size = 16M
-#
-# * Logging and Replication
-#
-# Both location gets rotated by the cronjob.
-# Be aware that this log type is a performance killer.
-# As of 5.1 you can enable the log at runtime!
-#general_log_file = /var/log/mysql/mysql.log
-#general_log = 1
-#
-# Error logging goes to syslog due to /etc/mysql/conf.d/mysqld_safe_syslog.cnf.
-#
-# Here you can see queries with especially long duration
-#log_slow_queries = /var/log/mysql/mysql-slow.log
-#long_query_time = 2
-#log-queries-not-using-indexes
-#
-# The following can be used as easy to replay backup logs or for replication.
-# note: if you are setting up a replication slave, see README.Debian about
-# other settings you may need to change.
-#server-id = 1
-#log_bin = /var/log/mysql/mysql-bin.log
-expire_logs_days = 10
-max_binlog_size = 100M
-#binlog_do_db = include_database_name
-#binlog_ignore_db = include_database_name
-#
-# * InnoDB
-#
-# InnoDB is enabled by default with a 10MB datafile in /var/lib/mysql/.
-# Read the manual for more InnoDB related options. There are many!
-
-innodb_flush_method = O_DIRECT
-innodb_file_per_table = 1
-
-# * Security Features
-#
-# Read the manual, too, if you want chroot!
-# chroot = /var/lib/mysql/
-#
-# For generating SSL certificates I recommend the OpenSSL GUI "tinyca".
-#
-# ssl-ca=/etc/mysql/cacert.pem
-# ssl-cert=/etc/mysql/server-cert.pem
-# ssl-key=/etc/mysql/server-key.pem
-
-
-
-[mysqldump]
-quick
-quote-names
-max_allowed_packet = 16M
-
-[mysql]
-#no-auto-rehash # faster start of mysql but no tab completition
-
-[isamchk]
-key_buffer_size = 16M
-
-#
-# * IMPORTANT: Additional settings that can override those from this file!
-# The files must end with '.cnf', otherwise they'll be ignored.
-#
-!includedir /etc/mysql/conf.d/
diff --git a/roles/common-SQL/tasks/main.yml b/roles/common-SQL/tasks/main.yml
index 3df2cab..7e59f60 100644
--- a/roles/common-SQL/tasks/main.yml
+++ b/roles/common-SQL/tasks/main.yml
@@ -4,13 +4,13 @@
packages:
- mariadb-common
- mariadb-server
- - python-mysqldb
+ - python3-mysqldb
# for the 'mysql_' munin plugin
- libcache-cache-perl
- name: Copy MySQL/MariaDB configuration
- copy: src=etc/mysql/my.cnf
- dest=/etc/mysql/my.cnf
+ copy: src=etc/mysql/mariadb.conf.d/99-user.cnf
+ dest=/etc/mysql/mariadb.conf.d/99-user.cnf
owner=root group=root
mode=0644
register: r
@@ -23,12 +23,12 @@
# XXX Dirty fix for #742046
- name: Force root to use UNIX permissions
- mysql_user2: name=root password= auth_plugin=unix_socket soname=auth_socket.so
- state=present
+ mysql_user: name=root password="" plugin=unix_socket
+ state=present
- name: Disallow anonymous and TCP/IP root login
- mysql_user2: name={{ item.name|default('') }} host={{ item.host }}
- state=absent
+ mysql_user: name={{ item.name|default('') }} host={{ item.host }}
+ state=absent
with_items:
- { host: '{{ inventory_hostname_short }}' }
- { host: 'localhost' }
diff --git a/roles/common-web/files/etc/nginx/sites-available/default b/roles/common-web/files/etc/nginx/sites-available/default
index 63c7910..cae8fc0 100644
--- a/roles/common-web/files/etc/nginx/sites-available/default
+++ b/roles/common-web/files/etc/nginx/sites-available/default
@@ -1,12 +1,12 @@
server {
- listen 80 default_server;
- listen [::]:80 default_server;
+ listen 80 default_server;
+ listen [::]:80 default_server;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log info;
# serve ACME challenges on all virtual hosts
# /!\ need to be served individually for each explicit virtual host as well!
- include snippets/acme-challenge.conf;
+ include /etc/lacme/nginx.conf;
include snippets/headers.conf;
}
diff --git a/roles/common-web/files/etc/nginx/snippets/acme-challenge.conf b/roles/common-web/files/etc/nginx/snippets/acme-challenge.conf
deleted file mode 100644
index b2a856a..0000000
--- a/roles/common-web/files/etc/nginx/snippets/acme-challenge.conf
+++ /dev/null
@@ -1,4 +0,0 @@
-location /.well-known/acme-challenge/ {
- alias /var/www/acme-challenge/;
- default_type application/jose+json;
-}
diff --git a/roles/common-web/files/etc/nginx/snippets/fastcgi-php.conf b/roles/common-web/files/etc/nginx/snippets/fastcgi-php.conf
index 9668bb8..f82bc5d 100644
--- a/roles/common-web/files/etc/nginx/snippets/fastcgi-php.conf
+++ b/roles/common-web/files/etc/nginx/snippets/fastcgi-php.conf
@@ -1,10 +1,13 @@
-# cf. http://wiki.nginx.org/Pitfalls#Passing_Uncontrolled_Requests_to_PHP
+# regex to split $uri to $fastcgi_script_name and $fastcgi_path
+fastcgi_split_path_info ^(.+?\.php)(/.*)$;
+
+# Check that the PHP script exists before passing it
try_files $fastcgi_script_name =404;
-include snippets/fastcgi.conf;
-# required if PHP was built with --enable-force-cgi-redirect
-fastcgi_param REDIRECT_STATUS 200;
+# Bypass the fact that try_files resets $fastcgi_path_info
+# see: http://trac.nginx.org/nginx/ticket/321
+set $path_info $fastcgi_path_info;
+fastcgi_param PATH_INFO $path_info;
-fastcgi_intercept_errors on;
-fastcgi_read_timeout 14400;
-fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
+fastcgi_index index.php;
+include snippets/fastcgi.conf;
diff --git a/roles/common-web/files/etc/nginx/snippets/fastcgi.conf b/roles/common-web/files/etc/nginx/snippets/fastcgi.conf
index ee058da..9a0a029 100644
--- a/roles/common-web/files/etc/nginx/snippets/fastcgi.conf
+++ b/roles/common-web/files/etc/nginx/snippets/fastcgi.conf
@@ -1,16 +1,16 @@
+fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
-fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
-fastcgi_param PATH_INFO $fastcgi_path_info;
-fastcgi_param REQUEST_SCHEME $scheme;
fastcgi_param REQUEST_URI $request_uri;
fastcgi_param DOCUMENT_URI $document_uri;
fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_param SERVER_PROTOCOL $server_protocol;
+fastcgi_param REQUEST_SCHEME $scheme;
+fastcgi_param HTTPS $https if_not_empty;
fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SERVER_SOFTWARE nginx/$nginx_version;
@@ -21,4 +21,5 @@ fastcgi_param SERVER_ADDR $server_addr;
fastcgi_param SERVER_PORT $server_port;
fastcgi_param SERVER_NAME $server_name;
-fastcgi_param HTTPS $https if_not_empty;
+# PHP only, required if PHP was built with --enable-force-cgi-redirect
+fastcgi_param REDIRECT_STATUS 200;
diff --git a/roles/common-web/files/etc/nginx/snippets/ssl.conf b/roles/common-web/files/etc/nginx/snippets/ssl.conf
index d3ccd9e..58adece 100644
--- a/roles/common-web/files/etc/nginx/snippets/ssl.conf
+++ b/roles/common-web/files/etc/nginx/snippets/ssl.conf
@@ -1,8 +1,5 @@
# https://wiki.mozilla.org/Security/Server_Side_TLS
-# https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=nginx-1.10.3&openssl=1.1.0j&hsts=yes&profile=intermediate
-
-# certs sent to the client in SERVER HELLO are concatenated in ssl_certificate
-# ~$ cat /etc/nginx/ssl/srvcert.pem /usr/share/lacme/lets-encrypt-x3-cross-signed.pem | sudo tee /etc/nginx/ssl/srvcert.chained.pem
+# https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=nginx-1.14.2&openssl=1.1.1c&hsts=yes&profile=intermediate
ssl on;
@@ -13,18 +10,9 @@ ssl_session_tickets off;
# Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits
ssl_dhparam /etc/ssl/dhparams.pem;
-# intermediate configuration. tweak to your needs.
-ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
-ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';
-ssl_prefer_server_ciphers on;
-
-# HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months)
-add_header Strict-Transport-Security 'max-age=15768000; includeSubDomains';
-
-# OCSP Stapling: fetch OCSP records from URL in ssl_certificate and cache them
-# https://github.com/jsha/ocsp-stapling-examples/blob/master/nginx.conf
-ssl_stapling on;
-ssl_stapling_verify on;
+ssl_protocols TLSv1.2 TLSv1.3;
+ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384";
+ssl_prefer_server_ciphers off;
-# verify chain of trust of OCSP response using Root CA and Intermediate certs
-ssl_trusted_certificate /usr/share/lacme/lets-encrypt-x3-cross-signed.pem;
+# HSTS (ngx_http_headers_module is required) (31557600 seconds = 1 year)
+add_header Strict-Transport-Security "max-age=31557600; includeSubDomains" always;
diff --git a/roles/common-web/tasks/main.yml b/roles/common-web/tasks/main.yml
index e2eb3ee..f059bfc 100644
--- a/roles/common-web/tasks/main.yml
+++ b/roles/common-web/tasks/main.yml
@@ -8,7 +8,7 @@
tags:
- logrotate
-- name: Copy fastcgi parameters, acme-challenge and SSL configuration snippets
+- name: Copy fastcgi parameters and SSL configuration snippets
copy: src=etc/nginx/snippets/{{ item }}
dest=/etc/nginx/snippets/{{ item }}
owner=root group=root
@@ -20,7 +20,6 @@
- fastcgi-php-ssl.conf
- ssl.conf
- headers.conf
- - acme-challenge.conf
notify:
- Restart Nginx
@@ -51,8 +50,19 @@
notify:
- Restart Nginx
+# WARN Bullseye: nginx >=1.15.1 uses font/woff and font/woff2 (cf. https://trac.nginx.org/nginx/ticket/1243)
+# however Bootstrap(?) appears to query resources with "Accept: application/font-woff" resp. application/font-woff2.
+# Unfortunately it also uses "Accept-Encoding: identity" so the resource isn't compressed...
+- name: Fix MIME type for woff
+ lineinfile: dest=/etc/nginx/mime.types
+ insertafter='^\s*\S+\s\s+woff;'
+ line=' application/font-woff2 woff2;'
+ register: r5
+ notify:
+ - Restart Nginx
+
- name: Start Nginx
service: name=nginx state=started
- when: not (r1.changed or r2.changed or r3.changed or r4.changed)
+ when: not (r1.changed or r2.changed or r3.changed or r4.changed or r5.changed)
- meta: flush_handlers
diff --git a/roles/common/files/etc/apt/apt.conf.d/50unattended-upgrades b/roles/common/files/etc/apt/apt.conf.d/50unattended-upgrades
index 86c6508..6f71ce6 100644
--- a/roles/common/files/etc/apt/apt.conf.d/50unattended-upgrades
+++ b/roles/common/files/etc/apt/apt.conf.d/50unattended-upgrades
@@ -1,7 +1,7 @@
// Unattended-Upgrade::Origins-Pattern controls which packages are
// upgraded.
//
-// Lines below have the format format is "keyword=value,...". A
+// Lines below have the format "keyword=value,...". A
// package will be upgraded only if the values in its metadata match
// all the supplied keywords in a line. (In other words, omitted
// keywords are wild cards.) The keywords originate from the Release
@@ -19,15 +19,18 @@
// Within lines unattended-upgrades allows 2 macros whose values are
// derived from /etc/debian_version:
// ${distro_id} Installed origin.
-// ${distro_codename} Installed codename (eg, "jessie")
+// ${distro_codename} Installed codename (eg, "buster")
Unattended-Upgrade::Origins-Pattern {
// Codename based matching:
// This will follow the migration of a release through different
// archives (e.g. from testing to stable and later oldstable).
-// "o=Debian,n=jessie";
-// "o=Debian,n=jessie-updates";
-// "o=Debian,n=jessie-proposed-updates";
-// "o=Debian,n=jessie,l=Debian-Security";
+ // Software will be the latest available for the named release,
+ // but the Debian release itself will not be automatically upgraded.
+// "origin=Debian,codename=${distro_codename}-updates";
+// "origin=Debian,codename=${distro_codename}-proposed-updates";
+ "origin=Debian,codename=${distro_codename},label=Debian";
+ "origin=Debian,codename=${distro_codename},label=Debian-Security";
+ "origin=Debian,codename=${distro_codename}-security,label=Debian-Security";
// Archive or Suite based matching:
// Note that this will silently match a different release after
@@ -36,53 +39,83 @@ Unattended-Upgrade::Origins-Pattern {
// "o=Debian,a=stable";
// "o=Debian,a=stable-updates";
// "o=Debian,a=proposed-updates";
- "origin=Debian,codename=${distro_codename},label=Debian-Security";
+// "o=Debian Backports,a=${distro_codename}-backports,l=Debian Backports";
};
-// List of packages to not update (regexp are supported)
+// Python regular expressions, matching packages to exclude from upgrading
Unattended-Upgrade::Package-Blacklist {
-// "vim";
-// "libc6";
-// "libc6-dev";
-// "libc6-i686";
+ // The following matches all packages starting with linux-
+// "linux-";
+
+ // Use $ to explicitely define the end of a package name. Without
+ // the $, "libc6" would match all of them.
+// "libc6$";
+// "libc6-dev$";
+// "libc6-i686$";
+
+ // Special characters need escaping
+// "libstdc\+\+6$";
+
+ // The following matches packages like xen-system-amd64, xen-utils-4.1,
+ // xenstore-utils and libxenstore3.0
+// "(lib)?xen(store)?";
+
+ // For more information about Python regular expressions, see
+ // https://docs.python.org/3/howto/regex.html
};
// This option allows you to control if on a unclean dpkg exit
// unattended-upgrades will automatically run
// dpkg --force-confold --configure -a
// The default is true, to ensure updates keep getting installed
-//Unattended-Upgrade::AutoFixInterruptedDpkg "false";
+//Unattended-Upgrade::AutoFixInterruptedDpkg "true";
// Split the upgrade into the smallest possible chunks so that
-// they can be interrupted with SIGUSR1. This makes the upgrade
+// they can be interrupted with SIGTERM. This makes the upgrade
// a bit slower but it has the benefit that shutdown while a upgrade
// is running is possible (with a small delay)
//Unattended-Upgrade::MinimalSteps "true";
-// Install all unattended-upgrades when the machine is shuting down
-// instead of doing it in the background while the machine is running
-// This will (obviously) make shutdown slower
-//Unattended-Upgrade::InstallOnShutdown "true";
+// Install all updates when the machine is shutting down
+// instead of doing it in the background while the machine is running.
+// This will (obviously) make shutdown slower.
+// Unattended-upgrades increases logind's InhibitDelayMaxSec to 30s.
+// This allows more time for unattended-upgrades to shut down gracefully
+// or even install a few packages in InstallOnShutdown mode, but is still a
+// big step back from the 30 minutes allowed for InstallOnShutdown previously.
+// Users enabling InstallOnShutdown mode are advised to increase
+// InhibitDelayMaxSec even further, possibly to 30 minutes.
+//Unattended-Upgrade::InstallOnShutdown "false";
// Send email to this address for problems or packages upgrades
// If empty or unset then no email is sent, make sure that you
// have a working mail setup on your system. A package that provides
// 'mailx' must be installed. E.g. "user@example.com"
-Unattended-Upgrade::Mail "admin@fripost.org";
+Unattended-Upgrade::Mail "root@fripost.org";
+
+// Set this value to one of:
+// "always", "only-on-error" or "on-change"
+// If this is not set, then any legacy MailOnlyOnError (boolean) value
+// is used to chose between "only-on-error" and "on-change"
+//Unattended-Upgrade::MailReport "on-change";
-// Set this value to "true" to get emails only on errors. Default
-// is to always send a mail if Unattended-Upgrade::Mail is set
-//Unattended-Upgrade::MailOnlyOnError "true";
+// Remove unused automatically installed kernel-related packages
+// (kernel images, kernel headers and kernel version locked tools).
+//Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
-// Do automatic removal of new unused dependencies after the upgrade
+// Do automatic removal of newly unused dependencies after the upgrade
+//Unattended-Upgrade::Remove-New-Unused-Dependencies "true";
+
+// Do automatic removal of unused packages after the upgrade
// (equivalent to apt-get autoremove)
//Unattended-Upgrade::Remove-Unused-Dependencies "false";
// Automatically reboot *WITHOUT CONFIRMATION* if
-// the file /var/run/reboot-required is found after the upgrade
+// the file /var/run/reboot-required is found after the upgrade
//Unattended-Upgrade::Automatic-Reboot "false";
-// Automatically reboot even if there are users currently logged in.
+// Automatically reboot even if there are users currently logged in
+// when Unattended-Upgrade::Automatic-Reboot is set to true
//Unattended-Upgrade::Automatic-Reboot-WithUsers "true";
// If automatic reboot is enabled and needed, reboot at the specific
@@ -99,3 +132,33 @@ Acquire::http::Dl-Limit "256";
// Specify syslog facility. Default is daemon
// Unattended-Upgrade::SyslogFacility "daemon";
+
+// Download and install upgrades only on AC power
+// (i.e. skip or gracefully stop updates on battery)
+// Unattended-Upgrade::OnlyOnACPower "true";
+
+// Download and install upgrades only on non-metered connection
+// (i.e. skip or gracefully stop updates on a metered connection)
+// Unattended-Upgrade::Skip-Updates-On-Metered-Connections "true";
+
+// Verbose logging
+// Unattended-Upgrade::Verbose "false";
+
+// Print debugging information both in unattended-upgrades and
+// in unattended-upgrade-shutdown
+// Unattended-Upgrade::Debug "false";
+
+// Allow package downgrade if Pin-Priority exceeds 1000
+// Unattended-Upgrade::Allow-downgrade "false";
+
+// When APT fails to mark a package to be upgraded or installed try adjusting
+// candidates of related packages to help APT's resolver in finding a solution
+// where the package can be upgraded or installed.
+// This is a workaround until APT's resolver is fixed to always find a
+// solution if it exists. (See Debian bug #711128.)
+// The fallback is enabled by default, except on Debian's sid release because
+// uninstallable packages are frequent there.
+// Disabling the fallback speeds up unattended-upgrades when there are
+// uninstallable packages at the expense of rarely keeping back packages which
+// could be upgraded or installed.
+// Unattended-Upgrade::Allow-APT-Mark-Fallback "true";
diff --git a/roles/common/files/etc/apt/listchanges.conf b/roles/common/files/etc/apt/listchanges.conf
index dc31f5e..e17e36d 100644
--- a/roles/common/files/etc/apt/listchanges.conf
+++ b/roles/common/files/etc/apt/listchanges.conf
@@ -1,6 +1,9 @@
[apt]
frontend=mail
-email_address=admin@fripost.org
+email_address=root@fripost.org
confirm=0
save_seen=/var/lib/apt/listchanges.db
which=news
+email_format=text
+headers=false
+reverse=false
diff --git a/roles/common/files/etc/default/rkhunter b/roles/common/files/etc/default/rkhunter
index 2e7fae7..49a63e8 100644
--- a/roles/common/files/etc/default/rkhunter
+++ b/roles/common/files/etc/default/rkhunter
@@ -18,7 +18,7 @@ DB_UPDATE_EMAIL="false"
# Set this to the email address where reports and run output should be sent
# (default: root)
-REPORT_EMAIL="admin@fripost.org"
+REPORT_EMAIL="root@fripost.org"
# Set this to yes to enable automatic database updates
# (default: false)
diff --git a/roles/common/files/etc/fail2ban/action.d/nftables-allports.local b/roles/common/files/etc/fail2ban/action.d/nftables-allports.local
index 3c8c030..3b9ebc8 100644
--- a/roles/common/files/etc/fail2ban/action.d/nftables-allports.local
+++ b/roles/common/files/etc/fail2ban/action.d/nftables-allports.local
@@ -9,8 +9,8 @@ actionunban =
[Init]
# With banaction = *-allports there is no need for separate rule names
-set_name = fail2ban
-blocktype = drop
+table = filter
+addr_set = fail2ban
[Init?family=inet6]
-set_name = fail2ban6
+addr_set = fail2ban6
diff --git a/roles/common/files/etc/fail2ban/fail2ban.local b/roles/common/files/etc/fail2ban/fail2ban.local
index 53cba35..5df817a 100644
--- a/roles/common/files/etc/fail2ban/fail2ban.local
+++ b/roles/common/files/etc/fail2ban/fail2ban.local
@@ -1,16 +1,5 @@
[Definition]
-# Option: logtarget
-# Notes.: Set the log target. This could be a file, SYSLOG, STDERR or STDOUT.
-# Only one log target can be specified.
-# If you change logtarget from the default value and you are
-# using logrotate -- also adjust or disable rotation in the
-# corresponding configuration file
-# (e.g. /etc/logrotate.d/fail2ban on Debian systems)
-# Values: [ STDOUT | STDERR | SYSLOG | SYSOUT | FILE ] Default: STDERR
-#
-logtarget = /var/log/fail2ban/fail2ban.log
-
# Options: dbfile
# Notes.: Set the file for the fail2ban persistent data to be stored.
# A value of ":memory:" means database is only stored in memory
@@ -18,3 +7,5 @@ logtarget = /var/log/fail2ban/fail2ban.log
# A value of "None" disables the database.
# Values: [ None :memory: FILE ] Default: /var/lib/fail2ban/fail2ban.sqlite3
dbfile = None
+
+allowipv6 = auto
diff --git a/roles/common/files/etc/fail2ban/filter.d/dovecot.conf b/roles/common/files/etc/fail2ban/filter.d/dovecot.conf
deleted file mode 100644
index 4d4ea16..0000000
--- a/roles/common/files/etc/fail2ban/filter.d/dovecot.conf
+++ /dev/null
@@ -1,34 +0,0 @@
-# Fail2Ban filter Dovecot authentication and pop3/imap server
-#
-
-[INCLUDES]
-
-before = common.conf
-
-[Definition]
-
-_daemon = (auth|dovecot(-auth)?|auth-worker)
-
-# Take the filter from Stretch and add managesieve to the list of protected services
-failregex = ^%(__prefix_line)s(?:%(__pam_auth)s(?:\(dovecot:auth\))?:)?\s+authentication failure; logname=\S* uid=\S* euid=\S* tty=dovecot ruser=\S* rhost=<HOST>(?:\s+user=\S*)?\s*$
- ^%(__prefix_line)s(?:pop3|imap|managesieve)-login: (?:Info: )?(?:Aborted login|Disconnected)(?::(?: [^ \(]+)+)? \((?:auth failed, \d+ attempts( in \d+ secs)?|tried to use (disabled|disallowed) \S+ auth)\):( user=<[^>]+>,)?( method=\S+,)? rip=<HOST>(?:, lip=\S+)?(?:, TLS(?: handshaking(?:: SSL_accept\(\) failed: error:[\dA-F]+:SSL routines:[TLS\d]+_GET_CLIENT_HELLO:unknown protocol)?)?(: Disconnected)?)?(, session=<\S+>)?\s*$
- ^%(__prefix_line)s(?:Info|dovecot: auth\(default\)|auth-worker\(\d+\)): pam\(\S+,<HOST>\): pam_authenticate\(\) failed: (User not known to the underlying authentication module: \d+ Time\(s\)|Authentication failure \(password mismatch\?\))\s*$
- ^%(__prefix_line)s(?:auth|auth-worker\(\d+\)): (?:pam|passwd-file)\(\S+,<HOST>\): unknown user\s*$
- ^%(__prefix_line)s(?:auth|auth-worker\(\d+\)): Info: ldap\(\S*,<HOST>,\S*\): invalid credentials\s*$
-
-ignoreregex =
-
-[Init]
-
-journalmatch = _SYSTEMD_UNIT=dovecot.service
-
-# DEV Notes:
-# * the first regex is essentially a copy of pam-generic.conf
-# * Probably doesn't do dovecot sql/ldap backends properly (resolved in edit 21/03/2016)
-# * Removed the 'no auth attempts' log lines from the matches because produces
-# lots of false positives on misconfigured MTAs making regexp unusable
-#
-# Author: Martin Waschbuesch
-# Daniel Black (rewrote with begin and end anchors)
-# Martin O'Neal (added LDAP authentication failure regex)
-# Sergey G. Brester aka sebres (reviewed, optimized, IPv6-compatibility)
diff --git a/roles/common/files/etc/logcheck/ignore.d.server/common-local b/roles/common/files/etc/logcheck/ignore.d.server/common-local
index e64ec44..4cc50f3 100644
--- a/roles/common/files/etc/logcheck/ignore.d.server/common-local
+++ b/roles/common/files/etc/logcheck/ignore.d.server/common-local
@@ -1,70 +1,141 @@
# Ansible Managed
# Do NOT edit this file directly!
#
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: subsystem request for sftp by user [-_.[:alnum:]]+$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: User [-_.[:alnum:]]+ not allowed because account is locked$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: fatal: Read from socket failed: (Connection reset by peer|Connection timed out) \[preauth\]$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: (error: )?Received disconnect from [:.[:xdigit:]]+: (3|11|14): .* \[preauth\]$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: Disconnecting: Change of username or service not allowed: \(\S+\) -> (\(\S+\) )?\[preauth\]$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: Disconnecting: Too many authentication failures for invalid user [-_.[:alnum:]]+ from [:.[:xdigit:]]+ port [[:digit:]]+ ssh2? \[preauth\]$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: (error: )?Received disconnect from [:.[:xdigit:]]+ port [0-9]+:(3|11|14): .* \[preauth\]$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: (Disconnected from|Connection (closed|reset) by) [[:xdigit:].:]{3,39} port [0-9]+ \[preauth\]$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: error: maximum authentication attempts exceeded for invalid user .* from [:.[:xdigit:]]+ port [0-9]+ ssh2 \[preauth\]$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: (Disconnected from|Connection (closed|reset) by)( invalid user .*)? [[:xdigit:].:]{3,39} port [0-9]+( \[preauth\])?$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: (Did not receive identification string|Invalid user .*) from [[:xdigit:].:]{3,39} port [0-9]+$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: Invalid user .* from [:.[:xdigit:]]+$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: input_userauth_request: invalid user .* \[preauth\]$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: userauth_pubkey: unsupported public key algorithm: [[:alnum:]-]+ \[preauth\]$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: fatal: Write failed: (Connection (timed out|reset by peer)|Broken pipe) \[preauth\]$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: fatal: (no hostkey alg|Unable to negotiate a key exchange method) \[preauth\]$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: (Disconnected from|Connection closed by) (invalid|authenticating) user .* \[preauth\]$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: Disconnecting (authenticating|invalid) user .* [[:xdigit:].:]{3,39} port [0-9]+: (Change of username or service not allowed: .* -> .*|Too many authentication failures) \[preauth\]$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: ssh_dispatch_run_fatal: Connection from (invalid user .* )?[[:xdigit:].:]{3,39} port [0-9]+: (message authentication code incorrect|Connection corrupted|Broken pipe) \[preauth\]$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: Disconnected from user [a-z0-9]+ [[:xdigit:].:]{3,39} port [0-9]+$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: Unable to negotiate with [:.[:xdigit:]]+ port [[:digit:]]+: no matching (host key type|key exchange method|cipher) found\. Their offer: [@.[:alnum:],-]+ \[preauth\]$
no matching cipher found: client [.@[:alnum:]-]+(,[.@[:alnum:]-]+)* server [.@[:alnum:]-]+(,[.@[:alnum:]-]+)* \[preauth\]$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: Bad packet length [0-9]+\. \[preauth\]$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: Bad protocol version identification '.*' from [:.[:xdigit:]]+ port [[:digit:]]+$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: Accepted publickey for [^[:space:]]+ from [^[:space:]]+ port [[:digit:]]+( (ssh|ssh2))?(: (DSA|RSA|ECDSA|ED25519) ([[:xdigit:]]{2}:){15}[[:xdigit:]]{2})?$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: WARNING: no suitable primes in /etc/ssh/primes$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: dispatch_protocol_error: type [0-9]+ seq [0-9]+ \[preauth\]$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: error: Bad remote protocol version identification: '.*'$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: Corrupted MAC on input\. \[preauth\]$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: Protocol major versions differ for [[:xdigit:].:]{3,39} port [0-9]+: .+ vs\. .+$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: error: Protocol major versions differ: .+ vs\. .+$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: banner exchange: Connection from [[:xdigit:].:]{3,39} port [0-9]+: could not read protocol version$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: userauth_pubkey: key type [-[:alnum:]]+ not in PubkeyAcceptedKeyTypes \[preauth\]$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: userauth_pubkey: signature algorithm [-[:alnum:]]+ not in PubkeyAcceptedAlgorithms \[preauth\]$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: error: kex_exchange_identification: Connection closed by remote host$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: error: kex_exchange_identification: read: Connection reset by peer$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: error: kex_exchange_identification: client sent invalid protocol identifier "
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: error: kex_exchange_identification: banner line contains invalid characters$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: error: kex_protocol_error: type [0-9]+ seq [0-9]+ \[preauth\]$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: fatal: ssh_packet_send_debug: Broken pipe$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: error: send_error: write: Connection reset by peer$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: fatal: userauth_pubkey: parse (request failed|publickey packet): incomplete message \[preauth\]$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: banner exchange: Connection from [[:xdigit:].:]{3,39} port [0-9]+: invalid format$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: error: beginning MaxStartups throttling$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: exited MaxStartups throttling after [0-9]{2}:[0-9]{2}:[0-9]{2}, [0-9]+ connections dropped$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: drop connection #[0-9]+ from \[[[:xdigit:].:]{3,39}\]:[0-9]+ on \[[[:xdigit:].:]{3,39}\]:[0-9]+ past MaxStartups$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: User .+ from [[:xdigit:].:]{3,39} not allowed because none of user's groups are listed in AllowGroups$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: pam_env\(sshd:session\): deprecated reading of user environment enabled$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ systemd\[1\]: Start(ing|ed) Cleanup of Temporary Directories\.(\.\.)?$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ slapd\[[[:digit:]]+\]: connection_input: conn=[[:digit:]]+ deferring operation: binding$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ (slapd\[[[:digit:]]+\]|slap(acl|add|auth|cat|dn|index)|ldap(add|compare|delete|exop|modify|modrdn|passwd|search|url|whoami)): DIGEST-MD5 common mech free$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ systemd\[1\]: (Created|Removed) slice User Slice of [-[:alnum:]]+\.$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ systemd\[1\]: (Created|Removed) slice User Slice of UID [-[:alnum:]]+\.$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ systemd\[[0-9]+\]: (Listening on|Closed) .*\.$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ systemd\[1\]: Start(ing|ed) Cleanup of Temporary Directories\.(\.\.)?$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ systemd\[1\]: Starting (Cleanup of Temporary Directories|Daily man-db regeneration)\.\.\.$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ systemd\[1\]: Started (Cleanup of Temporary Directories|Daily man-db regeneration)\.$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ systemd\[1\]: Start(ing|ed) Session [0-9]+ of user [-[:alnum:]]+\.$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ systemd\[[0-9]+\]: Startup finished in \S+\.$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ systemd: pam_unix\(systemd-user:session\): session (opened|closed) for user [-[:alnum:]]+( by \(uid=0\))?$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ systemd\[[0-9]+\]: [-[:alnum:]\\_@]+\.(mount|scope|service|socket): Succeeded\.$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ systemd(-[a-z]+)?\[[0-9]+\]: \[/[^]]+:[0-9]+\] Line references path below legacy directory /var/run/, updating /var/run/
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ systemd\[1\]: /lib/systemd/system/[-[:alnum:]\\_@]+\.service:[0-9]+: PIDFile= references path below legacy directory /var/run/, updating /var/run/
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ runuser: pam_unix\(runuser:session\): session (opened|closed) for user [-[:alnum:]]+( by \(uid=0\))?$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ CRON\[[0-9]+\]: pam_unix\(cron:session\): session (opened|closed) for user _?[-[:alnum:]]+(\(uid=[0-9]+\))?( by \(uid=0\))?$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ systemd\[1\]: Start(ing|ed) Session [0-9]+ of user [-[:alnum:]]+\.$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ systemd\[[0-9]+\]: Received SIGRTMIN\+24 from PID [0-9]+ \(kill\)\.$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ systemd-logind\[[0-9]+\]: New session c?[0-9]+ of user [-[:alnum:]]+\.$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ systemd-logind\[[0-9]+\]: Removed session c?[0-9]+\.$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ systemd-logind\[[0-9]+\]: Session [0-9]+ logged out\. Waiting for processes to exit\.$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ systemd\[1\]: apt-daily(-upgrade)?\.timer: Adding .* random time\.$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sudo:[[:space:]]+[_[:alnum:].-]+ : TTY=(unknown|(pts/|tty|vc/)[[:digit:]]+) ; PWD=[^;]+ ; USER=[._[:alnum:]-]+ (; ENV=([_a-zA-Z]+=\S* )+)?; COMMAND=(/(usr|etc|bin|sbin)/|sudoedit )
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ freshclam\[[[:digit:]]+\]: \w{3} \w{3} [ :[:digit:]]{16} -> (bytecode|main|daily)\.(cld|cvd) (is up to date|updated) \(version: [[:digit:]]+, sigs: [[:digit:]]+, f-level: [[:digit:]]+, builder: [._[:alnum:]-]+\)$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ systemd\[1\]: Starting Daily apt-listbugs preferences cleanup\.\.\.$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ systemd\[1\]: Finished (Daily apt-listbugs preferences cleanup|Cleanup of Temporary Directories|Autocommit of changes in /etc directory|Clean php session files|Launch apticron to notify of packages pending an update|Online ext4 Metadata Check for All Filesystems|Autocommit of changes in /etc directory)\.$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ systemd\[1\]: [[:alnum:]@-]+\.(service|scope): Consumed ([0-9]+min )?[0-9.]+s CPU time\.$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ systemd\[1\]: rsyslog\.service: Sent signal SIGHUP to main process [0-9]+ \(rsyslogd\) on client request\.$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sudo:[[:space:]]+[_[:alnum:].-]+ : (TTY=(unknown|(pts/|tty|vc/)[[:digit:]]+) ; )?PWD=[^;]+ ; USER=[._[:alnum:]-]+ (; ENV=([_a-zA-Z]+=\S* )+)?; COMMAND=(/(usr|etc|bin|sbin)/|sudoedit )
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ freshclam\[[[:digit:]]+\]: \w{3} \w{3} [ :[:digit:]]{16} -> daily database available for update \(local version: [[:digit:]]+, remote version: [[:digit:]]+\)$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ freshclam\[[[:digit:]]+\]: \w{3} \w{3} [ :[:digit:]]{16} -> (bytecode|main|daily)\.(cld|cvd) (database )?(is up to date|is up-to-date|updated) \(version: [[:digit:]]+, sigs: [[:digit:]]+, f-level: [[:digit:]]+, builder: [._[:alnum:]-]+\)$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ freshclam\[[[:digit:]]+\]: \w{3} \w{3} [ :[:digit:]]{16} -> Testing database: '/var/lib/clamav/tmp[^/]*/clamav-.*' \.\.\.$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ freshclam\[[[:digit:]]+\]: \w{3} \w{3} [ :[:digit:]]{16} -> Database test passed\.$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ freshclam\[[[:digit:]]+\]: \w{3} \w{3} [ :[:digit:]]{16} -> Received signal: wake up$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ freshclam\[[[:digit:]]+\]: \w{3} \w{3} [ :[:digit:]]{16} -> ClamAV update process started at \w{3} \w{3} [ :[:digit:]]{16}$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ freshclam\[[[:digit:]]+\]: (\w{3} \w{3} [ :[:digit:]]{16} -> \^|WARNING: )Your ClamAV installation is OUTDATED!$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ freshclam\[[[:digit:]]+\]: (\w{3} \w{3} [ :[:digit:]]{16} -> \^|WARNING: )Local version: [[:digit:]]+(\.[[:digit:]]+)* Recommended version: [[:digit:]]+(\.[[:digit:]]+)*$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ freshclam\[[[:digit:]]+\]: (\w{3} \w{3} [ :[:digit:]]{16} -> \^|WARNING: (\w{3} \w{3} [ :[:digit:]]{16} -> )?)Your ClamAV installation is OUTDATED!$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ freshclam\[[[:digit:]]+\]: (\w{3} \w{3} [ :[:digit:]]{16} -> \^|WARNING: (\w{3} \w{3} [ :[:digit:]]{16} -> )?)Local version: [[:digit:]]+(\.[[:digit:]]+)* Recommended version: [[:digit:]]+(\.[[:digit:]]+)*$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ freshclam\[[[:digit:]]+\]: WARNING: getfile: [._[:alnum:]-]+ not found on remote server \(IP: [.[:digit:]]+\)$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ freshclam\[[[:digit:]]+\]: WARNING: Incremental update failed, trying to download daily\.cvd$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ freshclam\[[[:digit:]]+\]: (WARNING|ERROR): (getpatch: )?Can't download [._[:alnum:]-]+ from [.[:alnum:]-]+$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ freshclam\[[[:digit:]]+\]: \w{3} \w{3} [ :[:digit:]]{16} -> \*Can't query [._[:alnum:]-]+$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ freshclam\[[[:digit:]]+\]: \w{3} \w{3} [ :[:digit:]]{16} -> Downloading [._[:alnum:]-]+ \[[[:digit:]]+%\]$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ freshclam\[[[:digit:]]+\]: \w{3} \w{3} [ :[:digit:]]{16} -> DON'T PANIC! Read https?://www\.clamav\.net/(support/faq|documents/upgrading-clamav)$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ freshclam\[[[:digit:]]+\]: \w{3} \w{3} [ :[:digit:]]{16} -> DON'T PANIC! Read https://docs\.clamav\.net/manual/Installing\.html$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ freshclam\[[0-9]+\]: \w{3} \w{3} [ :[:digit:]]{16} -> Database updated \([0-9]+ signatures\) from .* \(IP: [[:xdigit:].:]{3,39}\)$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ freshclam\[[0-9]+\]: \w{3} \w{3} [ :[:digit:]]{16} -> Clamd successfully notified about the update\.$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ freshclam\[[[:digit:]]+\]: \w{3} \w{3} [ :[:digit:]]{16} -> Received signal: re-opening log file$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ clamd\[[[:digit:]]+\]: \w{3} \w{3} [ :[:digit:]]{16} -> Reading databases from /var/lib/clamav$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ clamd\[[[:digit:]]+\]: \w{3} \w{3} [ :[:digit:]]{16} -> SelfCheck: Database status OK\.$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ clamd\[[[:digit:]]+\]: \w{3} \w{3} [ :[:digit:]]{16} -> SelfCheck: (Database status OK|Database modification detected\. Forcing reload)\.$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ clamd\[[[:digit:]]+\]: \w{3} \w{3} [ :[:digit:]]{16} -> Database correctly reloaded \([0-9]+ signatures\)$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ clamd\[[[:digit:]]+\]: \w{3} \w{3} [ :[:digit:]]{16} -> SIGHUP caught: re-opening log file\.$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ clamd\[[[:digit:]]+\]: \w{3} \w{3} [ :[:digit:]]{16} -> Activating the newly loaded database\.\.\.$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ kernel: \[ *[[:digit:]]+\.[[:digit:]]+ *\] Peer [.[:digit:]]+:[[:digit:]]+/[[:digit:]]+ unexpectedly shrunk window [[:digit:]]+:[[:digit:]]+ \(repaired\)$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ liblogging-stdlog: \[origin software="rsyslogd" swVersion="[0-9.]+" x-pid="[0-9]+" x-info="http://www\.rsyslog\.com"\] rsyslogd was HUPed$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ ansible-([_a-z0-9]+|<stdin>): Invoked with
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ rsyslogd(\[[0-9]+\]:|: ) \[origin software="rsyslogd" swVersion="[0-9.]+" x-pid="[0-9]+" x-info="https://www\.rsyslog\.com"\] rsyslogd was HUPed$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ smartd\[[0-9]+\]: Device: /dev/sd[a-z] \[SAT\], CHECK POWER STATUS spins up disk \(0x[0-9a-f]{2} -> 0xff\)$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ ansible-([_a-z0-9.]+|<stdin>): Invoked with
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ python3(\.[0-9]+)?\[[0-9]+\]: ansible-[_a-z0-9.]+ Invoked with
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ fail2ban-server\[[0-9]+\]: fail2ban\.filter\s*\[[0-9]+\]: INFO\s+\[[._[:alnum:]-]+\] (Found [[:xdigit:].:]{3,39} - |Ignore [[:xdigit:].:]{3,39} by ip$)
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ fail2ban-server\[[0-9]+\]: fail2ban\.actions\s*\[[0-9]+\]: NOTICE\s+\[[._[:alnum:]-]+\] (Ban|Unban) [[:xdigit:].:]{3,39}
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sympa_msg\[[0-9]+\]: notice Sympa::Request::Message::
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sympa_msg\[[0-9]+\]: info Sympa::Request::Handler::
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sympa_msg\[[0-9]+\]: notice Sympa::Bulk::store\(\)
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sympa_msg\[[0-9]+\]: notice Sympa::(Bulk|Spool)::store\(\)
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sympa_msg\[[0-9]+\]: info Sympa::Spool::_create\(\) Creating directory /var/spool/sympa/auth
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sympa_msg\[[0-9]+\]: (info|notice) Sympa::Spindle::Process(Incoming|Message|Template|Digest)::
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sympa_msg\[[0-9]+\]: info Sympa::Spindle::Do(Command|Message)::
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sympa_msg\[[0-9]+\]: info Sympa::Request::Handler::(subscribe|confirm|reject|signoff|distribute)::_twist\(\)
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sympa_msg\[[0-9]+\]: (info|notice) Sympa::Spindle::To(List|Moderation|Auth|Held)::
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sympa_msg\[[0-9]+\]: notice Sympa::Spindle::AuthorizeMessage::_twist\(\) Message Sympa::Message .* rejected\(\) because sender not allowed$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sympa_msg\[[0-9]+\]: err main::#[0-9]+ > Sympa::Spindle::spin#[0-9]+ >
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ task_manager\[[0-9]+\]: (info|notice) main::
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ wwsympa\[[0-9]+\]: info main::do_
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ wwsympa\[[[:digit:]]+\]: notice main:: \([.[:alnum:]-]+\) \[robot [.[:alnum:]-]+\] \[client [[:xdigit:].:]{3,39}\] Does NOT match HTTP_HOST; setting cookie_domain to [.[:alnum:]-]+$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ wwsympa\[[[:digit:]]+\]: notice Sympa::(Spindle::ProcessTemplate::_twist|Bulk::store)\(\)
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ bulk\[[[:digit:]]+\]: notice Sympa::(Spindle::ProcessOutgoing::_twist|Mailer::store)\(\)
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ task_manager\[[0-9]+\]: (info|notice) Sympa::(Spindle::ProcessTask|Spool)::
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ wwsympa\[[0-9]+\]: info main::
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ wwsympa\[[0-9]+\]: info Sympa::Ticket::load\(\) Ticket:
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ wwsympa\[[0-9]+\]: notice main:: Redirecting to\s
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ wwsympa\[[0-9]+\]: notice main::do_login\(\) Authentication failed$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ wwsympa\[[0-9]+\]: err main::#[0-9]+ > main::do_login#[0-9]+ > Sympa::WWW::Auth::check_auth#[0-9]+ > Sympa::WWW::Auth::authentication#[0-9]+ Incorrect password for user\s
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ wwsympa\[[0-9]+\]: notice Sympa::WWW::Tools::_get_css_url\(\) Template file /usr/share/sympa/default/web_tt2/css\.tt2 or configuration has changed; updating CSS file /var/lib/sympa/css/[.[:alnum:]-]+/style\.css$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ wwsympa\[[0-9]+\]: info Sympa::WWW::Session::new\(\) Ignoring unknown session cookie
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ wwsympa\[[0-9]+\]: err main::#[0-9]+ > main::get_parameters#[0-9]+ \[robot [.[:alnum:]-]+\] \[client [[:xdigit:].:]{3,39}\] Syntax error for parameter action value "(lists|search_list_request)#[^"]+" not conform to regexp:
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ wwsympa\[[0-9]+\]: err main::#[0-9]+ > main::check_action_parameters#[0-9]+ \[robot [.[:alnum:]-]+\] \[session [[:xdigit:]]+\] \[client [[:xdigit:].:]{3,39}\] \[list [.[:alnum:]-]+\] User not logged in$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ wwsympa\[[0-9]+\]: err main::#[0-9]+ > main::do_arc#[0-9]+ \[robot [.[:alnum:]-]+\] \[session [[:xdigit:]]+\] \[client [[:xdigit:].:]{3,39}\] \[list [.[:alnum:]-]+\] Empty archive Sympa::Archive <
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ wwsympa\[[0-9]+\]: notice Sympa::Spindle::Process(Request|Template)::_twist\(\) Processing Sympa::
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ wwsympa\[[0-9]+\]: info Sympa::Spindle::ToAuth::
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ wwsympa\[[0-9]+\]: notice Sympa::Bulk::store\(\) Message Sympa::Message::Template <
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ (wwsympa|sympa_msg)\[[0-9]+\]: notice Sympa::Spool::Outgoing::store\(\) Message Sympa::Message::Template <
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ wwsympa\[[0-9]+\]: notice Sympa::Spool::store\(\) Sympa::Request <
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ wwsympa\[[0-9]+\]: info Sympa::Request::Handler::(add|signoff|subscribe)::_twist\(\)
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ wwsympa\[[0-9]+\]: info Sympa::Scenario::authz\(\) Sympa::Scenario <create_list\.[.[:alnum:]-]+;ERROR>: No rule match, reject$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ wwsympa\[[0-9]+\]: err main::#[0-9]+ > main::check_param_in#[0-9]+ > Sympa::Scenario::new#[0-9]+ Unable to find scenario file "
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sympa_msg\[[0-9]+\]: notice Sympa::Spool::Outgoing::store\(\) Message Sympa::Message <[^>]+> is stored into bulk spool as <[^>]+>$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ (mysqld|mariadbd)\[[0-9]+\]: [0-9: -]{19} [0-9]+ \[Warning\] Aborted connection [0-9]+ to db: '[^']+' user: '[^']+' host: 'localhost' \(Got (timeout|an error) reading communication packets\)$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ (mysqld|mariadbd)\[[0-9]+\]: [0-9: -]{19} [0-9]+ \[Note\] InnoDB: Memory pressure event freed [0-9]+ pages$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ bulk\[[0-9]+\]: notice main:: Bulk exited normally due to signal$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ bulk\[[0-9]+\]: notice Sympa::Mailer::store\(\)
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ bulk\[[0-9]+\]: (info|notice) Sympa::Spindle::ProcessOutgoing::
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ bounced\[[0-9]+\]: notice Sympa::Tracking::store\(\) Sympa::Message <
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ bounced\[[0-9]+\]: notice Sympa::Spindle::ProcessBounce::_twist\(\)
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ bounced\[[0-9]+\]: info Sympa::Spindle::ProcessBounce::_twist\(\) No address found in message Sympa::Message <
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ archived\[[0-9]+\]: notice Sympa::Spindle::ProcessArchive::
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ archived\[[0-9]+\]: (info|notice) Sympa::Archive::
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ ikiwiki\[[[:digit:]]+\]:
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ ikiwiki: \[Fripost wiki\] (invalid page|unknown do) parameter$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ unbound: \[[0-9]+:[0-9]+\] info: generate keytag query _ta-[[:xdigit:]]+\. NULL IN$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ rrdcached\[[[:digit:]]+\]: (flushing old values|rotating journals|started new journal /\S+$|removing old journal /\S+$)
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ rrdcached\[[[:digit:]]+\]: queue_thread_main: rrd_update_r \(([^)]+)\) failed with status -1. \(opening '\1': No such file or directory\)
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ auditd\[[[:digit:]]+\]: Audit daemon rotating log files$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ stunnel(:|4\[[[:digit:]]+\]: [0-9]{4}\.[0-9]{2}\.[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}) LOG3\[[[:digit:]]+\]: SSL_accept: (Peer suddenly disconnected|[[:xdigit:]]+: error:[[:xdigit:]]+:SSL routines:SSL2?3_GET_CLIENT_HELLO:(unknown protocol|http request|no shared cipher))$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ dhclient\[[[:digit:]]+\]: DHCPREQUEST for [[:digit:].]{3,15} on [[:alnum:]]+ to [[:digit:].]{3,15} port 67$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ bacula-sd\[[[:digit:]]+\]: [._[:alnum:]-]+: askdir\.c:[0-9]+-[0-9]+ Discard: JobMedia Vol=[._[:alnum:]-]+ wrote=[0-9]+ MediaId=[0-9]+ FI=[0-9]+ LI=[0-9]+ StartAddr=[0-9]+ EndAddr=[0-9]+$
+###
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ slapd\[[[:digit:]]+\]: connection_read\([[:digit:]]+\): no connection!$
diff --git a/roles/common/files/etc/logcheck/ignore.d.server/dovecot-local b/roles/common/files/etc/logcheck/ignore.d.server/dovecot-local
index 66c8101..532a2a0 100644
--- a/roles/common/files/etc/logcheck/ignore.d.server/dovecot-local
+++ b/roles/common/files/etc/logcheck/ignore.d.server/dovecot-local
@@ -1,17 +1,23 @@
# Ansible Managed
# Do NOT edit this file directly!
#
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ dovecot: imap\([-_.@[:alnum:]]+\): (Logged out|Disconnected for inactivity) in=[[:digit:]]+ out=[[:digit:]]+$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ dovecot: imap\([-_.@[:alnum:]]+\): Connection closed( \(IDLE running for .*\))? in=[[:digit:]]+ out=[[:digit:]]+$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ dovecot: imap-hibernate\([-_.@[:alnum:]]+\): Connection closed in=[[:digit:]]+ out=[[:digit:]]+$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ dovecot: (pop3|imap|managesieve)-login: Login: user=<[^>]*>, method=[[:alnum:]-]+, rip=[.:[:xdigit:]]+, lip=[.:[:xdigit:]]+, mpid=[0-9]+, (TLS|secured), session=<[^>]+>$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ dovecot: (pop3|imap)-login: (Aborted login|Disconnected) \(auth failed, [[:digit:]]+ attempts in [[:digit:]]+ secs\): user=<[^>]*>, method=[[:alnum:]-]+, rip=[.:[:xdigit:]]+, lip=[.:[:xdigit:]]+, (TLS(: Disconnected)?|secured), session=<[^>]+>$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ dovecot: (pop3|imap)-login: (Aborted login|Disconnected(: Inactivity)?) \(no auth attempts in [[:digit:]]+ secs\): user=<>, rip=[.:[:xdigit:]]+, lip=[.:[:xdigit:]]+, TLS( handshaking|: Disconnected)?(: SSL_(accept|read)\(\) syscall failed: (Connection reset by peer|Success))?, session=<[^>]+>$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ dovecot: (pop3|imap)-login: Disconnected(: Inactivity during authentication)? \(client didn't finish SASL auth, waited [[:digit:]]+ secs\): user=<>, method=[[:alnum:]-]+, rip=[.:[:xdigit:]]+, lip=[.:[:xdigit:]]+, TLS(: SSL_read\(\) syscall failed: Connection reset by peer)?, session=<[^>]+>$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ dovecot: lmtp\([-_.@[:alnum:]]+\): [+/[:alnum:]]{22}: msgid=((\? )?<[^>]*>|unspecified): saved mail to\s
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ dovecot: lmtp\([-_.@[:alnum:]]+\): [+/[:alnum:]]{22}(:[0-9]+)?: sieve: msgid=((\? )?<[^>]*>|unspecified): (stored mail into mailbox '|(forwarded|discarded duplicate forward) to <[^[:space:]]+>$|marked message to be discarded if not explicitly delivered \(discard action\)$)
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ dovecot: lmtp\([^@]+@[^@]+\): [+/[:alnum:]]{22}:[0-9]+: sieve: Execution of script \S+ failed, but implicit keep was successful \(user logfile \S+ may reveal additional details\)$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ dovecot: (pop3|imap|managesieve)-login: Maximum number of connections from user\+IP exceeded \(mail_max_userip_connections=[[:digit:]]+\): user=<[^>]*>, method=[[:alnum:]-]+, rip=[.:[:xdigit:]]+, lip=[.:[:xdigit:]]+(, TLS, session=<[^>]+>)?$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ dovecot: lmtp\([-_.@[:alnum:]]+\): Connect from local$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ dovecot: lmtp\([0-9]+\): Disconnect from local: Successful quit$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ dovecot: imap\([-_.@[:alnum:]]+\)<[0-9]+><[+/[:alnum:]]+>: Connection closed(: read\(size=[0-9]+\) failed: Connection reset by peer)? \((((UID )?[[:alpha:]\-]* finished [0-9.]+ secs ago|IDLE running for [^\)]+, state=wait-input|No commands sent)\))?( in=[0-9]+ out=[0-9]+ deleted=[0-9]+ expunged=[0-9]+ trashed=[0-9]+ hdr_count=[0-9]+ hdr_bytes=[0-9]+ body_count=[0-9]+ body_bytes=[0-9]+)?$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ dovecot: imap\(.+\)<[0-9]+><[+/[:alnum:]]+>(: Disconnected)?(: Logged out| for inactivity( in reading our output)?|: Disconnected in [[:upper:]]+ \([0-9]+ msgs, [0-9]+ secs, [0-9]+/[0-9]+ bytes\)|: Too many invalid IMAP commands\.)?( in=[0-9]+ out=[0-9]+ deleted=[0-9]+ expunged=[0-9]+ trashed=[0-9]+ hdr_count=[0-9]+ hdr_bytes=[0-9]+ body_count=[0-9]+ body_bytes=[0-9]+)?$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ dovecot: imap: Logged out in=[0-9]+ out=[0-9]+ deleted=0 expunged=0 trashed=0 hdr_count=0 hdr_bytes=0 body_count=0 body_bytes=0$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ dovecot: imap\([-_.@[:alnum:]]+\)<[0-9]+><[+/[:alnum:]]+>: Connection closed(: (read\(size=[0-9]+\) failed: )?Connection reset by peer)?( \((LOGOUT,)?(UID )?[[:alpha:]\-]+ (running for|finished) [^\)]+\))? in=[0-9]+ out=[0-9]+ deleted=[0-9]+ expunged=[0-9]+ trashed=[0-9]+ hdr_count=[0-9]+ hdr_bytes=[0-9]+ body_count=[0-9]+ body_bytes=[0-9]+$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ dovecot: imap-hibernate\([-_.@[:alnum:]]+\)<[0-9]+><[+/[:alnum:]]+>: Connection closed in=[0-9]+ out=[0-9]+ deleted=[0-9]+ expunged=[0-9]+ trashed=[0-9]+ hdr_count=[0-9]+ hdr_bytes=[0-9]+ body_count=[0-9]+ body_bytes=[0-9]+$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ dovecot: (pop3|imap|managesieve)-login: Login: user=<[^>]*>, method=[[:alnum:]-]+, rip=[[:xdigit:].:]{3,39}, lip=[[:xdigit:].:]{3,39}, mpid=[0-9]+, (TLS|secured)(: (read\(size=[0-9]+\) failed: )?Connection (closed|reset by peer))?, session=<[^>]+>$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ dovecot: managesieve\([-_.@[:alnum:]]+\)<[0-9]+><[+/[:alnum:]]+>: Disconnected: Logged out bytes=[[:digit:]]+/[[:digit:]]+$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ dovecot: (imap|managesieve)-login: (Disconnected(: Inactivity)?|Aborted login) \(auth failed, [[:digit:]]+ attempts in [[:digit:]]+ secs\): user=<[^>]*>, method=[A-Z\-]+, rip=[[:xdigit:].:]{3,39}, lip=[[:xdigit:].:]{3,39}, (TLS|SSL|secured)[:,]
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ dovecot: (imap|managesieve)-login: Disconnected \((no auth attempts in|disconnected before auth was ready, waited) [[:digit:]]+ secs\):( user=<>,)? rip=[[:xdigit:].:]{3,39}, lip=[[:xdigit:].:]{3,39}, (TLS|SSL)( handshaking)?: (SSL_accept\(\)( syscall)? failed:|(read\(size=[0-9]+\) failed: )?Connection (closed|reset by peer), session=<[+/[:alnum:]]+>$|SSL_read failed: error:[[:xdigit:]]+:SSL routines:(ssl3_get_record:decryption failed or bad record mac|ssl3_read_bytes:unexpected record), session=<[+/[:alnum:]]+>$)
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ dovecot: (imap|managesieve)-login: (Disconnected(: (Inactivity|Too many invalid commands\.?))?|Aborted login) \(no auth attempts in [[:digit:]]+ secs\):( user=<>,)? rip=[[:xdigit:].:]{3,39}, lip=[[:xdigit:].:]{3,39}(, (TLS|SSL)( handshaking)?)?, session=<[+/[:alnum:]]+>$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ dovecot: (pop3|imap)-login: Disconnected(: Inactivity during authentication)? \(client didn't finish SASL auth, waited [[:digit:]]+ secs\): user=<>, method=[[:alnum:]-]+, rip=[[:xdigit:].:]{3,39}, lip=[[:xdigit:].:]{3,39}, TLS(: (read\(size=[0-9]+\) failed: Connection reset by peer|Disconnected|Connection closed))?, session=<[^>]+>$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ dovecot: lmtp\([-_.@[:alnum:]]+\)<[0-9]+><[+/[:alnum:]]{22}(:[0-9]+)?>: msgid=(\? )?(<[^>]*>|[^[:blank:]]*|[^,()]+@[.[:alnum:]-]+)( \(added by \S+@[.[:alnum:]-]+\))?: saved mail to\s
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ dovecot: lmtp\([-_.@[:alnum:]]+\)<[0-9]+><[+/[:alnum:]]{22}(:[0-9]+)?>: sieve: msgid=(\? )?(<[^>]*>\s*|[^[:blank:]]*|[^,()]+@[.[:alnum:]-]+)( \(added by \S+@[.[:alnum:]-]+\)| [[:alnum:]]+ action)?: (stored mail into mailbox '|(forwarded|discarded duplicate forward) to <[^[:space:]]+>$|Marked message to be discarded if not explicitly delivered \(discard action\)$)
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ dovecot: lmtp\([^@]+@[^@]+\)<[0-9]+><[+/[:alnum:]]{22}(:[0-9]+)?>: sieve: Execution of script \S+ failed, but implicit keep was successful \(user logfile \S+ may reveal additional details\)$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ dovecot: (pop3|imap|managesieve)-login: Maximum number of connections from user\+IP exceeded \(mail_max_userip_connections=[[:digit:]]+\): user=<[^>]*>, method=[[:alnum:]-]+, rip=[[:xdigit:].:]{3,39}, lip=[[:xdigit:].:]{3,39}(, TLS, session=<[^>]+>)?$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ dovecot: lmtp\([0-9]+\): Disconnect from local: (Client has quit the connection|Remote closed connection) \(state=[[:upper:]]+\)$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ dovecot: auth: Warning: auth client [0-9]+ disconnected with [0-9]+ pending requests: (Connection reset by peer|EOF)$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ dovecot: stats: Warning: UPDATE-CMD: Already expired$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ systemd\[1\]: Start(ing|ed) Dovecot authentication proxy\.(\.\.)?$
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 f539c3a..0921180 100644
--- a/roles/common/files/etc/logcheck/ignore.d.server/postfix-local
+++ b/roles/common/files/etc/logcheck/ignore.d.server/postfix-local
@@ -13,37 +13,43 @@
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix(-\w+)?/scache\[[[:digit:]]+\]: statistics: (domain|address) lookup hits=[[:digit:]]+ miss=[[:digit:]]+ success=[[:digit:]]+%$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix(-\w+)?/scache\[[[:digit:]]+\]: statistics: max simultaneous domains=[[:digit:]]+ addresses=[[:digit:]]+ connection=[[:digit:]]+$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix(-\w+)?/smtpd\[[[:digit:]]+\]: [[:xdigit:]]+: client=[._[:alnum:]-]+\[[[:xdigit:].:]{3,39}\]$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix(-\w+)?/cleanup\[[[:digit:]]+\]: [[:xdigit:]]+: (resent-)?message-id=([^[:blank:]]*|(mid:)?[[:alnum:]_/+.$@-]+)( \(added by [^[:space:]]+\))?$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix(-\w+)?/cleanup\[[[:digit:]]+\]: [[:xdigit:]]+: (resent-)?message-id=([^[:blank:]]*|(mid:)?[[:alnum:]_/+.$@-]+|[^,()]+@[.[:alnum:]-]+)( \(added by [^[:space:]]+\))?$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix(-\w+)?/cleanup\[[[:digit:]]+\]: warning: unix_trigger_event: read timeout for service public/qmgr$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix(-\w+)?/cleanup\[[[:digit:]]+\]: warning: milter unix:public/opendmarc: can't read SMFIC_BODYEOB reply packet header: Success$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix(-\w+)?/qmgr\[[[:digit:]]+\]: [[:xdigit:]]+: from=<[^>]*>, size=[[:digit:]]+, nrcpt=[[:digit:]]+ \(queue active\)$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix(-\w+)?/n?qmgr\[[[:digit:]]+\]: [[:xdigit:]]+: from=<[^>]*>, status=expired, returned to sender$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix(-\w+)?/n?qmgr\[[[:digit:]]+\]: [[:xdigit:]]+: message-id=(<[^>]*>|[[:alnum:]_/+.$@-]+)( \(added by [^[:space:]]+\))?
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix(-\w+)?/n?qmgr\[[[:digit:]]+\]: [[:xdigit:]]+: removed$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix(-\w+)?/n?qmgr\[[[:digit:]]+\]: [[:xdigit:]]+: skipped, still being delivered$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix(-\w+)?/verify\[[[:digit:]]+\]: cache [a-z]+:\S+ (partial|full) cleanup: retained=[[:digit:]]+ dropped=[[:digit:]]+ entries$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix(-\w+)?/smtpd\[[[:digit:]]+\]: disconnect from [._[:alnum:]-]+\[[[:xdigit:].:]{3,39}\]( (ehlo|helo|xforward|starttls|auth|mail|rcpt|data|noop|rset|quit|commands|unknown)=[0-9]+(/[0-9]+)?)+$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix(-\w+)?/smtpd\[[[:digit:]]+\]: disconnect from [._[:alnum:]-]+\[([[:xdigit:].:]{3,39}|unknown)\]( (ehlo|helo|xforward|starttls|auth|mail|rcpt|data|bdat|noop|rset|quit|commands|unknown)=[0-9]+(/[0-9]+)?)+$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-msa/smtpd\[[[:digit:]]+\]: warning: non-SMTP command from [-._[:alnum:]]+\[[[:xdigit:].:]{3,39}\]:\s
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-msa/pickup\[[[:digit:]]+\]: [[:xdigit:]]+: uid=[[:digit:]]+ from=<[^>]*>$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-msa/cleanup\[[[:digit:]]+\]: [[:xdigit:]]+: replace: header\s
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-msa/smtpd\[[[:digit:]]+\]: [[:xdigit:]]+: client=[^[:space:]]+, sasl_method=[-[:alnum:]]+, sasl_username=[-_.@[:alnum:]]+(, sasl_sender=[-_.@[:alnum:]]+)?$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-msa/smtpd\[[[:digit:]]+\]: warning: [-._[:alnum:]]+\[[[:xdigit:].:]{3,39}\]: SASL (PLAIN|LOGIN) authentication (failed|aborted)(:[ [:alnum:]]*)?$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-(msa|mx)/smtpd\[[[:digit:]]+\]: improper command pipelining after (EHLO|HELO|MAIL|QUIT) from [._[:alnum:]-]+\[[[:xdigit:].:]{3,39}\]:
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-msa/smtpd\[[[:digit:]]+\]: warning: [-._[:alnum:]]+\[[[:xdigit:].:]{3,39}\]: SASL [[:alpha:]]+ authentication (failed|aborted)(:|$)
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-(msa|mx)/smtpd\[[[:digit:]]+\]: improper command pipelining after (CONNECT|EHLO|HELO|AUTH|MAIL|QUIT) from [._[:alnum:]-]+\[[[:xdigit:].:]{3,39}\]:
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-(msa|mx)/smtpd\[[[:digit:]]+\]: warning: hostname [._[:alnum:]-]+ does not resolve to address [[:xdigit:].:]{3,39}(: Name or service not known)?$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-(msa|mx)/smtpd\[[[:digit:]]+\]: warning: Connection concurrency limit exceeded: [0-9]+ from [._[:alnum:]-]+\[[[:xdigit:].:]{3,39}\] for service (submissions?|smtpd)$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/smtpd\[[[:digit:]]+\]: NOQUEUE: reject: RCPT from [._[:alnum:]-]+\[[[:xdigit:].:]{3,39}\]: 5[[:digit:]]{2} 5(\.[[:digit:]]){2} <[^>]+>: Helo command rejected: need fully-qualified hostname;( from=<[^>]*> to=<[^>]+>)? proto=E?SMTP( helo=<[^>]+>)?$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/smtpd\[[[:digit:]]+\]: NOQUEUE: reject: RCPT from [._[:alnum:]-]+\[[[:xdigit:].:]{3,39}\]: 4[[:digit:]]{2} 4(\.[[:digit:]]){2} <[^>]+>: Sender address rejected: Domain not found;( from=<[^>]*> to=<[^>]+>)? proto=E?SMTP( helo=<[^>]+>)?$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/smtpd\[[[:digit:]]+\]: NOQUEUE: reject: RCPT from [._[:alnum:]-]+\[[[:xdigit:].:]{3,39}\]: 5[[:digit:]]{2} 5(\.[[:digit:]]){2} Service unavailable; (Unverified Client host|Sender address) \[\S+\] blocked using [._[:alnum:]-]+; https?://[^[:blank:];]+; from=<[^>]*> to=<[^>]+> proto=E?SMTP( helo=<[^>]+>)?$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/smtpd\[[[:digit:]]+\]: NOQUEUE: reject: RCPT from [._[:alnum:]-]+\[[[:xdigit:].:]{3,39}\]: 5[[:digit:]]{2} 5(\.[[:digit:]]+){2} <[^>]+>: Helo command rejected: need fully-qualified hostname;( from=<[^>]*> to=<[^>]+>)? proto=E?SMTP( helo=<[^>]+>)?$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/smtpd\[[[:digit:]]+\]: NOQUEUE: reject: RCPT from [._[:alnum:]-]+\[[[:xdigit:].:]{3,39}\]: 4[[:digit:]]{2} 4(\.[[:digit:]]+){2} <[^>]+>: Sender address rejected: (Domain not found|Malformed DNS server reply);( from=<[^>]*> to=<[^>]+>)? proto=E?SMTP( helo=<[^>]+>)?$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/smtpd\[[[:digit:]]+\]: NOQUEUE: reject: RCPT from [._[:alnum:]-]+\[[[:xdigit:].:]{3,39}\]: 5[[:digit:]]{2} 5(\.[[:digit:]]+){2} <[^>]+>: Sender address rejected: Domain [.[:alnum:]-]+ does not accept mail \(nullMX\);( from=<[^>]*> to=<[^>]+>)? proto=E?SMTP( helo=<[^>]+>)?$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/smtpd\[[[:digit:]]+\]: NOQUEUE: reject: RCPT from [._[:alnum:]-]+\[[[:xdigit:].:]{3,39}\]: 5[[:digit:]]{2} 5(\.[[:digit:]]+){2} Service unavailable; (Unverified Client host|Sender address) \[\S+\] blocked using [._[:alnum:]-]+(; Listed by DBL, see https?://[^[:blank:];]+)?; from=<[^>]*> to=<[^>]+> proto=E?SMTP( helo=<[^>]+>)?$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/smtpd\[[[:digit:]]+\]: NOQUEUE: reject: RCPT from [._[:alnum:]-]+\[([[:xdigit:].:]{3,39})\]: 4[[:digit:]]{2} 4(\.[[:digit:]]+){2} Client host rejected: cannot find your hostname, \[\1\]; from=<[^>]*> to=<[^>]+> proto=E?SMTP( helo=<[^>]+>)?$
^\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/smtpd\[[[:digit:]]+\]: (NOQUEUE|[[:xdigit:]]+): reject: [[:upper:]]+ from [^[:space:]]+: 450( 4\.1\.2)? <[^>]*>: Recipient address rejected: Domain not found;( from=<[^>]*> to=<[^>]+>)? 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=<[^>]+>)? proto=E?SMTP( helo=<[^[:space:]]+>)?$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-msa/smtpd\[[[:digit:]]+\]: NOQUEUE: reject: [[:upper:]]+ from [^[:space:]]+: 554( 5\.7\.1)? <>: Sender address rejected: Null sender not allowed; from=<> to=<[^>]+> proto=E?SMTP( helo=<[^[:space:]]+>)?$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-(msa|mx)/smtpd\[[[:digit:]]+\]: (NOQUEUE|[[:xdigit:]]+): reject: [[:upper:]]+ from [^[:space:]]+: 5[[:digit:]]{2} 5(\.[[:digit:]]){2} <[^>]*>: (Recipient|Sender) address rejected: need fully-qualified address;( from=<[^>]*> to=<[^>]+>)? proto=E?SMTP( helo=<[^[:space:]]+>)?$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-msa/smtpd\[[[:digit:]]+\]: NOQUEUE: reject: [[:upper:]]+ from [._[:alnum:]-]+\[[[:xdigit:].:]{3,39}\]: 550( 5\.7\.23)? <[^>]+>: Sender address rejected: Message rejected due to: (domain owner discourages use of this host|SPF fail - not authorized)\. Please see https?://www\.openspf\.net/Why\?\S+; from=<[^>]+> to=<[^>]+> proto=E?SMTP( helo=<[^[:space:]]+>)?$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ policyd-spf\[[[:digit:]]+\]: 550( 5\.7\.23)? Message rejected due to: (domain owner discourages use of this host|SPF fail - not authorized)\. Please see https?://www\.openspf\.net/Why\?\S+$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-(msa|mx)/smtpd\[[[:digit:]]+\]: (NOQUEUE|[[:xdigit:]]+): reject: [[:upper:]]+ from [^[:space:]]+: 5[[:digit:]]{2} 5(\.[[:digit:]]+){2} <[^>]*>: (Recipient|Sender) address rejected: need fully-qualified address;( from=<[^>]*> to=<[^>]+>)? 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=<[^>]+>)? proto=E?SMTP( helo=<[^[:space:]]+>)?$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mda/lmtp\[[[:digit:]]+\]: [[:xdigit:]]+: to=<[^>]+>,( orig_to=<[^>]+>,)? 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:]]+\]: [[:xdigit:]]+: to=<[^>]+>,( orig_to=<[^>]+>,)? relay=(none|[^[:space:]]+\[[[:xdigit:].:]{3,39}\]:[[:digit:]]+),( conn_use=[[:digit:]]+,)? delay=[[:digit:].]+,( delays=[[:digit:]./]+,)?( dsn=[45]\.[[:digit:]]\.[[:digit:]],)? status=(deferred|undeliverable|bounced) \((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|Network is unreachable|No route to host)|host [^[:space:]]+ refused to talk to me: [45][[:digit:]][[:digit:]].*|Host or domain name not found. Name service error for name=[^[:space:]]+ type=(MX|A|AAAA): Host (not found, try again|found but no data record of requested type)|User unknown in virtual alias table|host [^[:space:]]+\[[[:xdigit:].:]{3,39}\] said: [45][[:digit:]][[:digit:]] [45](\.[[:digit:]]+){2} <[^>]+>: (Temporarily rejected\. Try again later\.|Recipient address rejected: ((undeliverable|unverified) address:|Domain not found)) .*)\)$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-msa/smtp\[[[:digit:]]+\]: [[:xdigit:]]+: to=<[^>]+>,( orig_to=<[^>]+>,)? relay=[^[:space:]]+\[[[:xdigit:].:]{3,39}\]:[[:digit:]]+,( conn_use=[[:digit:]]+,)? delay=[[:digit:].]+,( delays=[[:digit:]./]+,)?( dsn=[45]\.[[:digit:]]\.[[:digit:]],)? status=undeliverable \(host
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-msa/smtp\[[[:digit:]]+\]: [[:xdigit:]]+: host [^[:space:]]+\[[[:xdigit:].:]{3,39}\]( said: 45[01] .* \(in reply to RCPT TO command\)| refused to talk to me: 421 )
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-out/smtp\[[[:digit:]]+\]: [[:xdigit:]]+: lost connection with [._[:alnum:]-]+\[[[:xdigit:].:]{3,39}\] while (receiving the initial server greeting|sending [[:upper:] ]+|performing the HELO handshake|sending end of data -- message may be sent more than once)$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-msa/smtp\[[[:digit:]]+\]: [[:xdigit:]]+: host [^[:space:]]+\[[[:xdigit:].:]{3,39}\]( said: 45[01][ -].* \(in reply to (MAIL FROM|RCPT TO) command\)| refused to talk to me: (421|450) )
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-(out|msa)/smtp\[[[:digit:]]+\]: [[:xdigit:]]+: lost connection with [._[:alnum:]-]+\[[[:xdigit:].:]{3,39}\] while (receiving the initial server greeting|sending [[:upper:] ]+|performing the HELO handshake|sending end of data -- message may be sent more than once)$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-out/smtp\[[[:digit:]]+\]: [[:xdigit:]]+: conversation with [._[:alnum:]-]+\[[[:xdigit:].:]{3,39}\] timed out while (sending message body|receiving the initial server greeting)$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-out/smtp\[[[:digit:]]+\]: [[:xdigit:]]+: to=<[^>]+>(, orig_to=<[^>]+>)?, relay=[._[:alnum:]-]+\[[[:xdigit:].:]{3,39}\](:[[:digit:]]{1,5})?,( conn_use=[[:digit:]]+,)? delay=[.[:digit:]]+(, delays=([.[:digit:]]+/){3}[.[:digit:]]+)?(, dsn=[45](\.[[:digit:]]+){2})?, status=(deferred|bounced|undeliverable|SOFTBOUNCE) \(host [._[:alnum:]-]+\[[[:xdigit:].:]{3,39}\] said: [45][[:digit:]][[:digit:]][- ]+.* \(in reply to (HELO|EHLO|MAIL FROM|RCPT TO|DATA|end of DATA) command\)\)$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-out/smtp\[[[:digit:]]+\]: connect to [^[:space:]]+: (read timeout|Connection (refused|timed out)|Network is unreachable|No route to host)( \(port [[:digit:]]+\))?$
@@ -52,10 +58,11 @@
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-(mda|out|lists)/smtpd\[[[:digit:]]+\]: [[:xdigit:]]+: client=[._[:alnum:]-]+\[[[:xdigit:].:]{3,39}\], orig_queue_id=[[:xdigit:]]+, orig_client=[._[:alnum:]-]+\[[[:xdigit:].:]{3,39}\]$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-out/smtp\[[[:digit:]]+\]: [A-Z[:digit:]]+: to=<[^>]+>,( orig_to=<[^>]+>,) relay=[^[:space:]]+, delay=[[:digit:]]+, status=deferred \(host [^[:space:]]+ said: [45][[:digit:]]{2} <[^[:space:]]*>: Recipient address rejected: Greylisted for [[:digit:]]+ (seconds|minutes)(\(see http://isg.ee.ethz.ch/tools/postgrey/help/[.[:alnum:]-]+.html\))? \(in reply to (HELO|EHLO|MAIL FROM|RCPT TO|DATA|end of DATA) command\)\)$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-out/smtp\[[[:digit:]]+\]: [[:xdigit:]]+: to=<.*>,( orig_to=<[^>]+>,)? relay=[^[:space:]]+\](:[[:digit:]]+)?,( conn_use=[[:digit:]]+,)? delay=[[:digit:].]+,( delays=[[:digit:]./]+,)?( dsn=4\.[[:digit:]]\.[[:digit:]],)? status=deferred \(host [^[:space:]]+\] said: .*$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-(mda|out)/smtpd?\[[[:digit:]]+\]: warning: numeric domain name in resource data of MX record for [._[:alnum:]-]+: [[:xdigit:].:]{3,39}$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-(mda|out|mx)/smtpd?\[[[:digit:]]+\]: warning: valid_hostname: numeric hostname: [0-9]+$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-(mda|out|mx)/smtpd?\[[[:digit:]]+\]: warning: (malformed|numeric) domain name in resource data of MX record for [._[:alnum:]-]+:\s
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-out/smtp\[[[:digit:]]+\]: warning: no MX host for [._[:alnum:]-]+ has a valid address record$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix(-\w+)?/smtpd\[[[:digit:]]+\]: SSL_accept error from [._[:alnum:]-]+\[[[:xdigit:].:]{3,39}\]: (lost connection|Connection reset by peer|-?[[:digit:]]+|Connection timed out)$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-(msa|mx)/smtpd\[[[:digit:]]+\]: warning: TLS library problem: error:[[:xdigit:]]+:SSL routines:SSL3_READ_BYTES:(sslv3|tlsv1) alert (unknown ca|certificate unknown):s3_pkt.c:[0-9]+:SSL alert number [[:digit:]]+:$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix(-\w+)?/smtpd\[[[:digit:]]+\]: SSL_accept error from [._[:alnum:]-]+\[([[:xdigit:].:]{3,39}|unknown)\]: (lost connection|Connection reset by peer|-?[[:digit:]]+|Connection timed out|Broken pipe)$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-(msa|mx)/smtpd\[[[:digit:]]+\]: warning: TLS library problem: error:[[:xdigit:]]+:SSL routines:SSL3_READ_BYTES:(sslv3|tlsv1) alert (unknown ca|certificate unknown):s3_pkt\.c:[0-9]+:SSL alert number [[:digit:]]+:$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-(out|mx)/bounce\[[[:digit:]]+\]: [[:xdigit:]]+: sender (delay|non-delivery|delivery status) notification: [[:xdigit:]]+$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-out/smtp\[[[:digit:]]+\]: [[:xdigit:]]+: host [^[:space:]]+ refused to talk to me: [45][[:digit:]][[:digit:]].*$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-out/smtp\[[[:digit:]]+\]: [[:xdigit:]]+: enabling PIX <CRLF>\.<CRLF> workaround for [._[:alnum:]-]+\[[[:xdigit:].:]{3,39}\](:[[:digit:]]{1,5})?$
@@ -64,20 +71,25 @@
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-out/smtp\[[[:digit:]]+\]: SSL_connect error to [._[:alnum:]-]+\[[[:xdigit:].:]{3,39}\]:[[:digit:]]+: -?[[:digit:]]+$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-out/smtp\[[[:digit:]]+\]: warning: TLS library problem: error:[[:xdigit:]]+:SSL routines:SSL2?3_CHECK_CERT_AND_ALGORITHM:dh key too small:s2?3_clnt\.c:[0-9]+:$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-out/smtp\[[[:digit:]]+\]: [[:xdigit:]]+: Cannot start TLS: handshake failure$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/tlsproxy\[[[:digit:]]+\]: TLS handshake failed for service=smtpd peer=\[[[:xdigit:].:]{3,39}\]:[0-9]+$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/tlsproxy\[[[:digit:]]+\]: warning: ciphertext read/write timeout for \[[[:xdigit:].:]{3,39}\]:[0-9]+$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-out/smtp\[[[:digit:]]+\]: Host offered STARTTLS: \[[._[:alnum:]-]+\]$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/smtpd\[[[:digit:]]+\]: [[:xdigit:]]+: reject: RCPT from [^[:space:]]+: 4[[:digit:]][[:digit:]]( 4(\.[[:digit:]]){2}) <[^[:space:]]*>: Recipient address rejected: Greylisted( for [[:digit:]]+ (second|minute)s)?, see https?://[-_.:/[:alnum:]]+\.html?; from=<[^>]*> to=<[^>]+> proto=E?SMTP helo=<[^[:space:]]+>$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/smtpd\[[[:digit:]]+\]: [[:xdigit:]]+: reject: RCPT from [^[:space:]]+: 4[[:digit:]][[:digit:]]( 4(\.[[:digit:]]+){2}) <[^[:space:]]*>: Recipient address rejected: Greylisted( for [[:digit:]]+ (second|minute)s)?, see https?://[-_.:/[:alnum:]]+\.html?; from=<[^>]*> to=<[^>]+> proto=E?SMTP helo=<[^[:space:]]+>$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-\w+/smtpd\[[[:digit:]]+\]: lost connection after [[:upper:]]+( \([[:digit:]]+ bytes\))? from [._[:alnum:]-]+\[(unknown|[[:xdigit:].:]{3,39})\]$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/smtpd\[[[:digit:]]+\]: [[:xdigit:]]+: reject: (CONNECT|RCPT) from [^[:space:]]+: [45][[:digit:]][[:digit:]]( [45](\.[[:digit:]]){2})? Service unavailable; Client host \[([[:xdigit:].:]{3,39}|[-._[:alnum:]]+)\] blocked using [._[:alnum:]-]+;( .+;)? (from=<[^>]*> to=<[^>]+> )?proto=E?SMTP( helo=<[^[:space:]]+>)?$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/smtpd\[[[:digit:]]+\]: (NOQUEUE|[[:xdigit:]]+): reject: RCPT from [^[:space:]]+: [[:digit:]]{3}( [45](\.[[:digit:]]){2})? <[^[:space:]]*>: Relay access denied; from=<[^>]*> to=<[^>]+> proto=E?SMTP helo=<[^[:space:]]+>$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/smtpd\[[[:digit:]]+\]: [[:xdigit:]]+: reject: (CONNECT|RCPT) from [^[:space:]]+: [45][[:digit:]][[:digit:]]( [45](\.[[:digit:]]+){2})? Service unavailable; Client host \[([[:xdigit:].:]{3,39}|[-._[:alnum:]]+)\] blocked using [._[:alnum:]-]+;( .+;)? (from=<[^>]*> to=<[^>]+> )?proto=E?SMTP( helo=<[^[:space:]]+>)?$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/smtpd\[[[:digit:]]+\]: (NOQUEUE|[[:xdigit:]]+): reject: RCPT from [^[:space:]]+: [[:digit:]]{3}( [45](\.[[:digit:]]+){2})? <[^[:space:]]*>: Relay access denied; from=<[^>]*> to=<[^>]+> proto=E?SMTP helo=<[^[:space:]]+>$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/smtpd\[[[:digit:]]+\]: warning: ([-._[:alnum:]]+): RBL lookup error: Host or domain name not found\. Name service error for name=\1 type=A(AAA)?: Host not found, try again$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-(mx|msa)/(smtpd|tlsproxy)\[[[:digit:]]+\]: warning: TLS library problem: error:[[:xdigit:]]+:SSL routines:SSL2?3_(GET_RECORD:(decryption failed or bad record mac|wrong version number):s3_pkt\.c:[0-9]+:|READ_BYTES:(reason\([[:digit:]]+\)|sslv3 alert (unexpected message|bad certificate)):s3_pkt\.c:[[:digit:]]+:SSL alert number (0|10|42):|GET_CLIENT_HELLO:(unsupported protocol|no shared cipher|unknown protocol|wrong version number):s2?3_srvr\.c:[0-9]+:)$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/tlsproxy\[[[:digit:]]+\]: warning: TLS library problem: error:[[:xdigit:]]+:SSL routines:tls_post_process_client_hello:no shared cipher:\.\./ssl/statem/statem_srvr\.c:[0-9]+:$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-msa/smtpd\[[[:digit:]]+\]: warning: TLS library problem: error:[[:xdigit:]]+:SSL routines:tls_process_client_hello:(no shared cipher|unknown protocol|version too low):\.\./ssl/statem/statem_srvr\.c:[0-9]+:$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/smtpd\[[[:digit:]]+\]: (NOQUEUE|[[:xdigit:]]+): reject: [[:upper:]]+ from [^[:space:]]+: 554( 5\.1\.[01])? <[^[:space:]]*>: Recipient address rejected: User unknown in virtual alias table;( from=<[^>]*> to=<[^>]+>)? proto=E?SMTP( helo=<[^[:space:]]+>)?$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/smtpd\[[[:digit:]]+\]: [[:xdigit:]]+: reject: RCPT from [^[:space:]]+: [45][[:digit:]][[:digit:]]( [45](\.[[:digit:]]){2})? <[^[:space:]]*>: Helo command rejected: .+; from=<[^>]*> to=<[^>]+> proto=E?SMTP helo=<[^[:space:]]+>$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-(mx|msa)/(smtpd|tlsproxy)\[[[:digit:]]+\]: warning: TLS library problem: error:[[:xdigit:]]+:SSL routines:ssl2?3_get_record:(decryption failed or bad record mac|wrong version number):
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-(mx|msa)/(smtpd|tlsproxy)\[[[:digit:]]+\]: warning: TLS library problem: error:[[:xdigit:]]+:SSL routines:(ssl3_get_record:(wrong version number|http request|packet length too long|bad record type)|tls_post_process_client_hello:no shared cipher):
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-(mx|msa)/(smtpd|tlsproxy)\[[[:digit:]]+\]: warning: TLS library problem: error:[[:xdigit:]]+:SSL routines:ssl3_read_bytes:(sslv3 alert bad certificate|unexpected record|tlsv1 alert user cancelled):
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-(mx|msa)/(smtpd|tlsproxy)\[[[:digit:]]+\]: warning: TLS library problem: error:[[:xdigit:]]+:SSL routines:tls_parse_ctos_key_share:bad key share:
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-(msa|mx)/(smtpd|tlsproxy)\[[[:digit:]]+\]: warning: TLS library problem: error:[[:xdigit:]]+:SSL routines:tls_((early_)?post_)?process_client_hello:(no shared cipher|unknown protocol|unsupported protocol|version too low):\.\./ssl/statem/statem_srvr\.c:[0-9]+:$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/smtpd\[[[:digit:]]+\]: (NOQUEUE|[[:xdigit:]]+): reject: [[:upper:]]+ from [^[:space:]]+: 55[0-9]( 5\.1\.[01])? <[^[:space:]]*>: Recipient address rejected: User unknown in virtual alias table;( from=<[^>]*> to=<[^>]+>)? proto=E?SMTP( helo=<[^[:space:]]+>)?$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/smtpd\[[[:digit:]]+\]: [[:xdigit:]]+: reject: RCPT from [^[:space:]]+: [45][[:digit:]][[:digit:]]( [45](\.[[:digit:]]+){2})? <[^[:space:]]*>: Helo command rejected: .+; from=<[^>]*> to=<[^>]+> proto=E?SMTP helo=<[^[:space:]]+>$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/smtpd\[[[:digit:]]+\]: too many errors after ([[:upper:]]{4}|END-OF-MESSAGE|UNKNOWN|DATA \(0 bytes\)) from [._[:alnum:]-]+\[[.[:digit:]]+\]$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-(mx|msa)/smtpd\[[[:digit:]]+\]: warning: hostname [^[:space:]]+ does not resolve to address [[:xdigit:].:]{3,39}: (No address associated with hostname|Temporary failure in name resolution)$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/smtpd\[[[:digit:]]+\]: warning: (numeric hostname: [[:xdigit:].:]{3,39}|valid_hostname: misplaced delimiter: \S)$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-(mx|msa)/smtpd\[[[:digit:]]+\]: warning: (numeric hostname: [[:xdigit:].:]{3,39}|valid_hostname: misplaced delimiter: \S)$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-(mx|lists)/pipe\[[[:digit:]]+\]: [[:xdigit:]]+: to=<[^>]+>,( orig_to=<[^>]+>,)* relay=([-_.[:alnum:]]+), delay=[.[:digit:]]+(, delays=([.[:digit:]]+/){3}[.[:digit:]]+)?(, dsn=2(\.[[:digit:]]+){2})?, status=sent \(delivered via \3 service\)$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/discard\[[[:digit:]]+\]: [[:xdigit:]]+: to=<[^>]+>,( orig_to=<[^>]+>,)* relay=none, delay=[.[:digit:]]+(, delays=([.[:digit:]]+/){3}[.[:digit:]]+)?(, dsn=2(\.[[:digit:]]+){2})?, status=sent \(discard\.fripost\.org\)$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-(mx|msa)/smtpd\[[[:digit:]]+\]: warning: Illegal address syntax from [._[:alnum:]-]+\[[[:xdigit:].:]{3,39}\] in (MAIL|RCPT) command:\s
@@ -90,10 +102,11 @@
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/postscreen\[[[:digit:]]+\]: NON-SMTP COMMAND from \[[[:xdigit:].:]{3,39}\]:[[:digit:]]+\s
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/postscreen\[[[:digit:]]+\]: COMMAND PIPELINING from \[[[:xdigit:].:]{3,39}\]:[[:digit:]]+ after\s
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/postscreen\[[[:digit:]]+\]: DNSBL rank [[:digit:]]+ for \[[[:xdigit:].:]{3,39}\]:[[:digit:]]+$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/postscreen\[[[:digit:]]+\]: NOQUEUE: reject: RCPT from (\[[[:xdigit:].:]{3,39}\]):[[:digit:]]+: [45][[:digit:]][[:digit:]]( [45](\.[[:digit:]]){2})? (Service unavailable; client \1 blocked using [._[:alnum:]-]+|Protocol error|Service currently unavailable);( .+;)? (from=<[^>]*>, to=<[^>]+>, )?proto=E?SMTP(, helo=<[^[:space:]]+>)?$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/postscreen\[[[:digit:]]+\]: [[:upper:]]+ without valid RCPT from \[[[:xdigit:].:]{3,39}\]:[[:digit:]]+$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/postscreen\[[[:digit:]]+\]: NOQUEUE: reject: RCPT from (\[[[:xdigit:].:]{3,39}\]):[[:digit:]]+: [45][[:digit:]][[:digit:]]( [45](\.[[:digit:]]+){2})? (Service unavailable; client \1 blocked using [._[:alnum:]-]+|Protocol error|Service currently unavailable);( .+;)? (from=<[^>]*>, to=<[^>]+>, )?proto=E?SMTP(, helo=<[^[:space:]]+>)?$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/postscreen\[[[:digit:]]+\]: NOQUEUE: reject: CONNECT from \[[[:xdigit:].:]{3,39}\]:[[:digit:]]+: too many connections$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/postscreen\[[[:digit:]]+\]: COMMAND (COUNT|TIME) LIMIT from \[[[:xdigit:].:]{3,39}\]:[[:digit:]]+( after [[:upper:]]+)?$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/postscreen\[[[:digit:]]+\]: cache [a-z]+:\S+ full cleanup: retained=[[:digit:]]+ dropped=[[:digit:]]+ entries$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/postscreen\[[[:digit:]]+\]: cache [a-z]+:\S+ (partial|full) cleanup: retained=[[:digit:]]+ dropped=[[:digit:]]+ entries$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/postscreen\[[[:digit:]]+\]: warning: getpeername: Transport endpoint is not connected -- dropping this connection$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/postscreen\[[[:digit:]]+\]: warning: psc_cache_update: lmdb:/var/lib/postfix-mx/postscreen_cache update average delay is [[:digit:]]+ ms$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/postscreen\[[[:digit:]]+\]: warning: dnsblog reply timeout [[:digit:]]+s for [._[:alnum:]-]+$
@@ -104,8 +117,19 @@
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ systemd\[1\]: Start(ing|ed) Postfix sender login socketmap\.(\.\.)?$
#
# Amavis
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ amavis\[[[:digit:]]+\]: \([-[:digit:]]+\) Passed (CLEAN|SPAM|UNCHECKED(-[A-Z]+)?|BAD-HEADER-[28]) {Relayed(Tagged)?(Internal|Inbound|Outbound)}, (INCOMING|OUTGOING)( LOCAL)? \[(IPv6:)?[[:xdigit:].:]{3,39}\](:[[:digit:]]+)?( \[[[:xdigit:].:]{3,39}\])? <[^>]*> -> (<[^>]*>,)+( Queue-ID: [[:xdigit:]]+,)?( Message-ID: <[^>]+>,)?( Resent-Message-ID: <[^>]+>,)? mail_id: [_-+[:alnum:]]+, Hits: -?[[:digit:].]*, size: [[:digit:]]+, queued_as: [[:xdigit:]]+(, dkim_(new|sd)?=[-_.,:[:alnum:]]+)?, [[:digit:]]+ ms$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ amavis\[[[:digit:]]+\]: \([-[:digit:]]+\) Passed (CLEAN|SPAM|UNCHECKED(-[A-Z]+)?|BAD-HEADER-[28]) {Relayed(Tagged)?(Internal|Inbound|Outbound)}, (INCOMING|OUTGOING)( LOCAL)? \[(IPv6:)?[[:xdigit:].:]{3,39}\](:[[:digit:]]+)?( \[[[:xdigit:].:]{3,39}\])? <[^>]*> -> (<[^>]*>,)+( Queue-ID: [[:xdigit:]]+,)?( Message-ID: <[^>]+>,)?( Resent-Message-ID: <[^>]+>,)? mail_id: [-_+[:alnum:]]+, Hits: -?[[:digit:].]*, size: [[:digit:]]+, queued_as: [[:xdigit:]]+(, dkim_(new|sd)?=[-_.,:[:alnum:]]+)?, [[:digit:]]+ ms$
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ amavis\[[[:digit:]]+\]: \([-[:digit:]]+\) Passed (CLEAN|SPAM|UNCHECKED(-[A-Z]+)?|BAD-HEADER-[28]) {Relayed(Tagged)?(Internal|Inbound|Outbound)}, (INCOMING|OUTGOING)( LOCAL)? \[(IPv6:)?[[:xdigit:].:]{3,39}\](:[[:digit:]]+)?( \[[[:xdigit:].:]{3,39}\])? <[^>]*> -> (<[^>]*>,)*(<[^>]*)?\.\.\.$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ amavis\[[[:digit:]]+\]: \([-[:digit:]]+\) \.\.\.([^>]*>)?(,<[^>]*>)*,( Queue-ID: [[:xdigit:]]+,)?( Message-ID: <[^>]+>,)?( Resent-Message-ID: <[^>]+>,)? mail_id: [_-+[:alnum:]]+, Hits: -?[[:digit:].]*, size: [[:digit:]]+, queued_as: [[:xdigit:]]+(, dkim_(new|sd)?=[-_.,:[:alnum:]]+)?, [[:digit:]]+ ms$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ amavis\[[[:digit:]]+\]: \([-[:digit:]]+\) \.\.\.([^>]*>)?(,<[^>]*>)*,( Queue-ID: [[:xdigit:]]+,)?( Message-ID: <[^>]+>,)?( Resent-Message-ID: <[^>]+>,)? mail_id: [-_+[:alnum:]]+, Hits: -?[[:digit:].]*, size: [[:digit:]]+, queued_as: [[:xdigit:]]+(, dkim_(new|sd)?=[-_.,:[:alnum:]]+)?, [[:digit:]]+ ms$
# SMTP client connection caching was introduced in 2.6.0; the SMTP session is held for the next task, and is terminated by Postfix if the next mail comes soon enough
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-out/smtpd\[[[:digit:]]+\]: timeout after END-OF-MESSAGE from [._[:alnum:]-]+\[(127.0.0.1|::1)\]$
+#
+# OpenDMARC
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ opendmarc\[[0-9]+\]: implicit authentication service: [-_.[:alnum:]]+\.fripost\.org$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ opendmarc\[[0-9]+\]: [[:xdigit:]]+: RFC5322 requirement error: (not exactly one Date field|multiple Message-Id fields)$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ opendmarc\[[0-9]+\]: [[:xdigit:]]+: unable to parse From header field$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ opendmarc\[[0-9]+\]: [[:xdigit:]]+:? ignoring Authentication-Results at\s
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ opendmarc\[[0-9]+\]: [[:xdigit:]]+: ignoring invalid ARC-Authentication-Results header ".*"
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ opendmarc\[[0-9]+\]: [[:xdigit:]]+: SPF\((mailfrom|helo)\): \S+ (none|tempfail|fail|pass)$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ opendmarc\[[0-9]+\]: [[:xdigit:]]+: [-_.[:alnum:]]+ (none|fail|pass)$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ opendmarc\[[0-9]+\]: [[:xdigit:]]+: opendmarc_policy_query_dmarc\([._[:alnum:]-]+\) returned status 4$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ opendmarc\[[0-9]+\]: opendmarc: opendmarc-arcares\.c:[0-9]+: opendmarc_arcares_strip_whitespace: Assertion `.*' failed\.$
diff --git a/roles/common/files/etc/logcheck/ignore.d.server/strongswan-local b/roles/common/files/etc/logcheck/ignore.d.server/strongswan-local
index cebfaba..adf47a1 100644
--- a/roles/common/files/etc/logcheck/ignore.d.server/strongswan-local
+++ b/roles/common/files/etc/logcheck/ignore.d.server/strongswan-local
@@ -1,19 +1,24 @@
# Ansible Managed
# Do NOT edit this file directly!
#
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ (charon|ipsec\[[[:digit:]]+\]): [[:digit:]]+\[KNL\] creating acquire job for policy [[:xdigit:].:]{3,39}/[[:digit:]]+(\[\w+(/[[:alnum:]-]+)?\])? === [[:xdigit:].:]{3,39}/[[:digit:]]+(\[\w+(/[[:alnum:]-]+)?\])? with reqid \{[[:digit:]]+\}$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ (charon|ipsec\[[[:digit:]]+\]): [[:digit:]]+\[KNL\] creating rekey job for CHILD_SA ESP/0x[[:xdigit:]]{8}/[[:xdigit:].:]{3,39}$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ (charon|ipsec\[[[:digit:]]+\]): [[:digit:]]+\[KNL\] creating delete job for CHILD_SA ESP/0x[[:xdigit:]]{8}/[[:xdigit:].:]{3,39}$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ (charon|ipsec\[[[:digit:]]+\]): [[:digit:]]+\[JOB\] CHILD_SA ESP/0x[[:xdigit:]]{8}/[[:xdigit:].:]{3,39} not found for delete$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ (charon|ipsec\[[[:digit:]]+\]): [[:digit:]]+\[IKE\] initiating IKE_SA [[:alnum:]._-]+\[[[:digit:]]+\] to [[:xdigit:].:]{3,39}$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ (charon|ipsec\[[[:digit:]]+\]): [[:digit:]]+\[IKE\] [[:xdigit:].:]{3,39} is initiating an IKE_SA$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ (charon|ipsec\[[[:digit:]]+\]): [[:digit:]]+\[IKE\] establishing CHILD_SA [[:alnum:]._-]+(\{[[:digit:]]+\})?$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ (charon|ipsec\[[[:digit:]]+\]): [[:digit:]]+\[IKE\] IKE_SA [[:alnum:]._-]+\[[[:digit:]]+\] established between [[:xdigit:].:]{3,39}\[[^]\"]+\]\.\.\.[[:xdigit:].:]{3,39}\[[^]]+\]$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ (charon|ipsec\[[[:digit:]]+\]): [[:digit:]]+\[IKE\] CHILD_SA [[:alnum:]._-]+\{[[:digit:]]+\} established with SPIs [[:xdigit:]]{8}_i [[:xdigit:]]{8}_o and TS [[:xdigit:].:]{3,39}/[[:digit:]]+ === [[:xdigit:].:]{3,39}/[[:digit:]]+$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ (charon|ipsec\[[[:digit:]]+\]): [[:digit:]]+\[IKE\] closing CHILD_SA [[:alnum:]._-]+\{[[:digit:]]+\} with SPIs [[:xdigit:]]{8}_i \([[:digit:]]+ bytes\) [[:xdigit:]]{8}_o \([[:digit:]]+ bytes\) and TS [[:xdigit:].:]{3,39}/[[:digit:]]+ === [[:xdigit:].:]{3,39}/[[:digit:]]+$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ (charon|ipsec\[[[:digit:]]+\]): [[:digit:]]+\[IKE\] reauthenticating IKE_SA [[:alnum:]._-]+\[[[:digit:]]+\]$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ (charon|ipsec\[[[:digit:]]+\]): [[:digit:]]+\[JOB\] deleting IKE_SA after [[:digit:]]+ seconds of CHILD_SA inactivity$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ (charon|ipsec\[[[:digit:]]+\]): [[:digit:]]+\[IKE\] deleting IKE_SA [[:alnum:]._-]+\[[[:digit:]]+\] between [[:xdigit:].:]{3,39}\[[^]\"]+\]\.\.\.[[:xdigit:].:]{3,39}\[[^]]+\]$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ (charon|ipsec\[[[:digit:]]+\]): [[:digit:]]+\[IKE\] IKE_SA deleted$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ vpn: [+-] .* [[:xdigit:].:]{3,39}/[[:digit:]]+ == [[:xdigit:].:]{3,39} -- [[:xdigit:].:]{3,39} == [[:xdigit:].:]{3,39}/[[:digit:]]+$
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ (charon|ipsec\[[[:digit:]]+\]): [[:digit:]]+\[MGR\] ignoring request with ID [[:digit:]]+, already processing$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ (charon|ipsec)(\[[[:digit:]]+\])?: [[:digit:]]+\[KNL\] creating acquire job for policy [[:xdigit:].:]{3,39}/[[:digit:]]+(\[\w+(/[[:alnum:]-]+)?\])? === [[:xdigit:].:]{3,39}/[[:digit:]]+(\[\w+(/[[:alnum:]-]+)?\])? with reqid \{[[:digit:]]+\}$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ (charon|ipsec)(\[[[:digit:]]+\])?: [[:digit:]]+\[KNL\] creating rekey job for CHILD_SA ESP/0x[[:xdigit:]]{8}/[[:xdigit:].:]{3,39}$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ (charon|ipsec)(\[[[:digit:]]+\])?: [[:digit:]]+\[KNL\] creating delete job for CHILD_SA ESP/0x[[:xdigit:]]{8}/([[:xdigit:].:]{3,39}|%any)$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ (charon|ipsec)(\[[[:digit:]]+\])?: [[:digit:]]+\[JOB\] CHILD_SA ESP/0x[[:xdigit:]]{8}/([[:xdigit:].:]{3,39}|%any) not found for delete$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ ipsec\[[[:digit:]]+\]: [[:digit:]]+\[JOB\] spawning [0-9]+ worker threads$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ (charon|ipsec)(\[[[:digit:]]+\])?: [[:digit:]]+\[IKE\] initiating IKE_SA [[:alnum:]._-]+\[[[:digit:]]+\] to [[:xdigit:].:]{3,39}$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ (charon|ipsec)(\[[[:digit:]]+\])?: [[:digit:]]+\[IKE\] [[:xdigit:].:]{3,39} is initiating an IKE_SA$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ (charon|ipsec)(\[[[:digit:]]+\])?: [[:digit:]]+\[IKE\] establishing CHILD_SA [[:alnum:]._-]+(\{[[:digit:]]+\}( reqid [0-9]+)?)?$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ (charon|ipsec)(\[[[:digit:]]+\])?: [[:digit:]]+\[IKE\] IKE_SA [[:alnum:]._-]+\[[[:digit:]]+\] established between [[:xdigit:].:]{3,39}\[[^]\"]+\]\.\.\.[[:xdigit:].:]{3,39}\[[^]]+\]$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ (charon|ipsec)(\[[[:digit:]]+\])?: [[:digit:]]+\[IKE\] ((in|out)bound )?CHILD_SA [[:alnum:]._-]+\{[[:digit:]]+\} established with SPIs [[:xdigit:]]{8}_i [[:xdigit:]]{8}_o and TS [[:xdigit:].:]{3,39}/[[:digit:]]+ === [[:xdigit:].:]{3,39}/[[:digit:]]+$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ (charon|ipsec)(\[[[:digit:]]+\])?: [[:digit:]]+\[IKE\] closing CHILD_SA [[:alnum:]._-]+\{[[:digit:]]+\} with SPIs [[:xdigit:]]{8}_i \([[:digit:]]+ bytes\) [[:xdigit:]]{8}_o \([[:digit:]]+ bytes\) and TS [[:xdigit:].:]{3,39}/[[:digit:]]+ === [[:xdigit:].:]{3,39}/[[:digit:]]+$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ (charon|ipsec)(\[[[:digit:]]+\])?: [[:digit:]]+\[IKE\] reauthenticating IKE_SA [[:alnum:]._-]+\[[[:digit:]]+\]$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ (charon|ipsec)(\[[[:digit:]]+\])?: [[:digit:]]+\[JOB\] deleting IKE_SA after [[:digit:]]+ seconds of CHILD_SA inactivity$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ (charon|ipsec)(\[[[:digit:]]+\])?: [[:digit:]]+\[IKE\] deleting IKE_SA [[:alnum:]._-]+\[[[:digit:]]+\] between [[:xdigit:].:]{3,39}\[[^]\"]+\]\.\.\.[[:xdigit:].:]{3,39}\[[^]]+\]$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ (charon|ipsec)(\[[[:digit:]]+\])?: [[:digit:]]+\[JOB\] deleting CHILD_SA after [[:digit:]]+ seconds of inactivity$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ (charon|ipsec)(\[[[:digit:]]+\])?: [[:digit:]]+\[JOB\] CHILD_SA \{[[:digit:]]+\} not found for delete$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ (charon|ipsec)(\[[[:digit:]]+\])?: [[:digit:]]+\[JOB\] deleting half open IKE_SA with [[:xdigit:].:]{3,39} after timeout$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ (charon|ipsec)(\[[[:digit:]]+\])?: [[:digit:]]+\[IKE\] IKE_SA deleted$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ (charon|ipsec)(\[[[:digit:]]+\])?: [[:digit:]]+\[MGR\] ignoring request with ID [[:digit:]]+, already processing$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ (charon|ipsec)(\[[[:digit:]]+\])?: [[:digit:]]+\[KNL\] flags changed for [[:xdigit:].:]{3,39} on e[nt][[:alnum:]]+
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ (charon|ipsec)(\[[[:digit:]]+\])?: [[:digit:]]+\[KNL\] [[:xdigit:].:]{3,39} appeared on e[nt][[:alnum:]]+$
diff --git a/roles/common/files/etc/logcheck/logcheck.conf b/roles/common/files/etc/logcheck/logcheck.conf
index 9a7e7c6..6e06450 100644
--- a/roles/common/files/etc/logcheck/logcheck.conf
+++ b/roles/common/files/etc/logcheck/logcheck.conf
@@ -25,7 +25,7 @@ REPORTLEVEL="server"
# *NOTE* the script does not set a default value for this variable!
# Should be set to an offsite "emailaddress@some.domain.tld"
-SENDMAILTO="admin@fripost.org"
+SENDMAILTO="root@fripost.org"
# Send the results as attachment or not.
# 0=not as attachment; 1=as attachment; 2=as gzip attachment
@@ -69,7 +69,18 @@ FQDN=1
# Controls [logcheck] prefix on Subject: lines
-#ADDTAG="no"
+#ADDTAG="no"
+
+# Previous versions of logcheck always sent messages in 7bit encoding,
+# even if that resulted in RFC-violating messages. For example, really
+# long syslog lines would generate too-long SMTP lines, which are
+# rejected at least by Debian's default exim configuration. The new
+# default is to let mime-construct pick an appropriate encoding, but you
+# can override it by setting the below (to any of the encodings
+# supported by mime-construct). You may need to do this if you have
+# tools handling logcheck emails that don't understand MIME encoding.
+
+#MIMEENCODING=
# Set a different location for temporary files than /tmp
# this is useful if your /tmp is small and you are getting
diff --git a/roles/common/files/etc/logcheck/violations.ignore.d/logcheck-sudo b/roles/common/files/etc/logcheck/violations.ignore.d/logcheck-sudo
index e474019..4fb0765 100644
--- a/roles/common/files/etc/logcheck/violations.ignore.d/logcheck-sudo
+++ b/roles/common/files/etc/logcheck/violations.ignore.d/logcheck-sudo
@@ -1,7 +1,5 @@
-^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sudo: pam_krb5\(sudo:auth\): user [[:alnum:]-]+ authenticated as [[:alnum:]-]+@[.A-Z]+$
-# ignore sudo with custom ENV
-#^\w{3} [ :0-9]{11} [._[:alnum:]-]+ sudo:[[:space:]]+[_[:alnum:].-]+ : TTY=(unknown|console|(pts/|tty|vc/)[[:digit:]]+) ; PWD=[^;]+ ; USER=[._[:alnum:]-]+ ; COMMAND=((/(usr|etc|bin|sbin)/|sudoedit ).*|list)$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ sudo:[[:space:]]+[_[:alnum:].-]+ : TTY=(unknown|console|(pts/|tty|vc/)[[:digit:]]+) ; PWD=[^;]+ ; USER=[._[:alnum:]-]+ (; ENV=([_a-zA-Z]+=\S* )+)?; COMMAND=((/(usr|etc|bin|sbin)/|sudoedit ).*|list)$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sudo: pam_krb5\(sudo:auth\): user [._[:alnum:]-]+ authenticated as [._[:alnum:]-]+@[.A-Z]+$
+^\w{3} [ :0-9]{11} [._[:alnum:]-]+ sudo(\[[0-9]+\])?:[[:space:]]+[_[:alnum:].-]+ : (TTY=(unknown|console|(pts/|tty|vc/)[[:digit:]]+) ; )?PWD=[^;]+ ; USER=[._[:alnum:]-]+( ; GROUP=[._[:alnum:]-]+)? ; COMMAND=((/(usr|etc|bin|sbin)/|sudoedit ).*|list)$
^\w{3} [ :0-9]{11} [._[:alnum:]-]+ sudo:[[:space:]]+[_[:alnum:].-]+ : \(command continued\).*$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ sudo: pam_[[:alnum:]]+\(sudo:session\): session opened for user [[:alnum:]-]+ by ([[:alnum:]-]+)?\(uid=[0-9]+\)$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ sudo: pam_[[:alnum:]]+\(sudo:session\): session closed for user [[:alnum:]-]+$
+^\w{3} [ :0-9]{11} [._[:alnum:]-]+ sudo(\[[0-9]+\])?: pam_[[:alnum:]]+\(sudo:session\): session opened for user [._[:alnum:]-]+\(uid=[0-9]+\) by ([[:alnum:]-]+)?\(uid=[0-9]+\)$
+^\w{3} [ :0-9]{11} [._[:alnum:]-]+ sudo(\[[0-9]+\])?: pam_[[:alnum:]]+\(sudo:session\): session closed for user [._[:alnum:]-]+$
diff --git a/roles/common/files/etc/logrotate.d/fripost-mail b/roles/common/files/etc/logrotate.d/fripost-mail
index 4fc1a85..7f7ffc2 100644
--- a/roles/common/files/etc/logrotate.d/fripost-mail
+++ b/roles/common/files/etc/logrotate.d/fripost-mail
@@ -12,7 +12,7 @@
delaycompress
sharedscripts
postrotate
- invoke-rc.d rsyslog rotate > /dev/null
+ /usr/lib/rsyslog/rsyslog-rotate
endscript
}
@@ -29,6 +29,6 @@
delaycompress
sharedscripts
postrotate
- invoke-rc.d rsyslog rotate > /dev/null
+ /usr/lib/rsyslog/rsyslog-rotate
endscript
}
diff --git a/roles/common/files/etc/rkhunter.conf b/roles/common/files/etc/rkhunter.conf
index b6a7d06..8040c88 100644
--- a/roles/common/files/etc/rkhunter.conf
+++ b/roles/common/files/etc/rkhunter.conf
@@ -14,8 +14,8 @@
# been made.
#
# Please review the documentation before posting bug reports or questions.
-# To report bugs, obtain updates, or provide patches or comments, please go
-# to: http://rkhunter.sourceforge.net
+# To report bugs, provide patches or comments, please go to:
+# http://rkhunter.sourceforge.net
#
# To ask questions about rkhunter, please use the 'rkhunter-users' mailing list.
# Note that this is a moderated list, so please subscribe before posting.
@@ -50,7 +50,8 @@
# should be configured with one entry per line as in the first example.
#
# If wildcard characters (globbing) are allowed for an option, then the
-# text describing the option will say so.
+# text describing the option will say so. Any globbing character explicitly
+# required in a pathname should be escaped.
#
# Space-separated lists may be enclosed by quotes, although they are not
# required. If they are used, then they must only appear at the start and
@@ -69,7 +70,9 @@
# If a configuration option is never set, then the program will assume a
# default value. The text describing the option will state the default value.
# If there is no default, then rkhunter will calculate a value or pathname
-# to use.
+# to use. If a value is set for a configuration option, then the default
+# value is ignored. If it is wished to keep the default value, as well as
+# any other set value, then the default must be explicitly set.
#
@@ -130,7 +133,7 @@ MIRRORS_MODE=1
#
# Also see the MAIL_CMD option.
#
-MAIL-ON-WARNING=admin@fripost.org
+MAIL-ON-WARNING=root@fripost.org
#
# This option specifies the mail command to use if MAIL-ON-WARNING is set.
@@ -259,12 +262,12 @@ LOGFILE=/var/log/rkhunter.log
#
# USE_SYSLOG=authpriv.warning
#
-# Setting the value to 'none', or just leaving the option commented out,
+# Setting the value to 'NONE', or just leaving the option commented out,
# disables the use of syslog.
#
# The default value is not to use syslog.
#
-#USE_SYSLOG=authpriv.notice
+USE_SYSLOG=authpriv.warning
#
# Set the following option to '1' if the second colour set is to be used. This
@@ -317,12 +320,12 @@ AUTO_X_DETECT=1
#
# The default value is '0'.
#
-#ALLOW_SSH_PROT_V1=0
+ALLOW_SSH_PROT_V1=2
#
# This setting tells rkhunter the directory containing the SSH configuration
-# file. This setting will be worked out by rkhunter, and so should not
-# usually need to be set.
+# file. If unset, this setting will be worked out by rkhunter, and so should
+# not usually need to be set.
#
# This option has no default value.
#
@@ -330,8 +333,8 @@ AUTO_X_DETECT=1
#
# These two options determine which tests are to be performed. The ENABLE_TESTS
-# option can use the word 'all' to refer to all of the available tests. The
-# DISABLE_TESTS option can use the word 'none' to mean that no tests are
+# option can use the word 'ALL' to refer to all of the available tests. The
+# DISABLE_TESTS option can use the word 'NONE' to mean that no tests are
# disabled. The list of disabled tests is applied to the list of enabled tests.
#
# Both options are space-separated lists of test names, and both options may
@@ -349,15 +352,8 @@ AUTO_X_DETECT=1
# either of the options below are specified, then they will override the
# program defaults.
#
-# hidden_procs test requires the unhide and/or unhide.rb commands which are
-# part of the unhide respectively unhide.rb packages in Debian.
-#
-# apps test is disabled by default as it triggers warnings about outdated
-# applications (and warns about possible security risk: we better trust
-# the Debian Security Team).
-#
-ENABLE_TESTS=all
-DISABLE_TESTS=suspscan hidden_procs deleted_files packet_cap_apps apps
+ENABLE_TESTS=ALL
+DISABLE_TESTS=suspscan hidden_ports hidden_procs deleted_files packet_cap_apps apps
#
# The HASH_CMD option can be used to specify the command to use for the file
@@ -384,11 +380,13 @@ DISABLE_TESTS=suspscan hidden_procs deleted_files packet_cap_apps apps
#
# NOTE: Whenever this option is changed 'rkhunter --propupd' must be run.
#
-# The default value is the SHA1 function, or MD5 if SHA1 cannot be found.
+# The default value is the SHA256 function, unless prelinking is used in
+# which case it defaults to the SHA1 function.
#
-# Also see the HASH_FLD_IDX option.
+# Also see the HASH_FLD_IDX option. In addition, note the comments under
+# the PKGMGR option relating to the use of HASH_CMD.
#
-HASH_CMD=sha512sum
+HASH_CMD=SHA512
#
# The HASH_FLD_IDX option specifies which field from the HASH_CMD command
@@ -407,20 +405,28 @@ HASH_CMD=sha512sum
# properties file ('rkhunter.dat'), and when running the file properties check.
# For RedHat/RPM-based systems, 'RPM' can be used to get information from the
# RPM database. For Debian-based systems 'DPKG' can be used, for *BSD systems
-# 'BSD' can be used, and for Solaris systems 'SOLARIS' can be used. No value,
-# or a value of 'NONE', indicates that no package manager is to be used.
+# 'BSD' can be used, or for *BSD systems with the 'pkg' command 'BSDng' can be
+# used, and for Solaris systems 'SOLARIS' can be used. No value, or a value of
+# 'NONE', indicates that no package manager is to be used.
#
-# The current package managers, except 'SOLARIS', store the file hash values
-# using an MD5 hash function. The Solaris package manager includes a checksum
-# value, but this is not used by default (see USE_SUNSUM below).
+# The package managers obtain each file hash value using a hash function. The
+# Solaris package manager includes a 16-bit checksum value, but this is not
+# used by default (see USE_SUNSUM below). The 'RPM' and 'BSDng' package managers
+# currently use a SHA256 hash function. Other package managers will, typically,
+# use an MD5 hash function.
#
-# The 'DPKG' and 'BSD' package managers only provide MD5 hash values.
-# The 'RPM' package manager additionally provides values for the inode,
-# file permissions, uid, gid and other values. The 'SOLARIS' also provides
-# most of the values, similar to 'RPM', but not the inode number.
+# The 'DPKG', 'BSD' and 'BSDng' package managers only provide a file hash value.
+# The 'RPM' package manager additionally provides values for the inode, file
+# permissions, uid, gid and other values. The 'SOLARIS' package manager also
+# provides most of the values, similar to 'RPM', but not the inode number.
#
# For any file not part of a package, rkhunter will revert to using the
-# HASH_CMD hash function instead.
+# HASH_CMD hash function instead. This means that if the HASH_CMD option
+# is set, and PKGMGR is set, then the HASH_CMD hash function is only used,
+# and stored, for non-packaged files. All packaged files will use, and store,
+# whatever hash function the relevant package manager uses. So, for example,
+# with the 'RPM' package manager, packaged files will be stored with their
+# SHA256 value regardless of the value of the HASH_CMD option.
#
# NOTE: Whenever this option is changed 'rkhunter --propupd' must be run.
#
@@ -499,6 +505,9 @@ HASH_CMD=sha512sum
# simple command names.
# For example, 'top*' cannot be given, but '/usr/bin/top*' is allowed.
#
+# To extend the use of wildcards to include recursive checking of directories,
+# see the GLOBSTAR configuration option.
+#
# Specific files may be excluded by using the EXCLUDE_USER_FILEPROP_FILES_DIRS
# option. Wildcards may be used with this option.
#
@@ -528,11 +537,8 @@ HASH_CMD=sha512sum
#USER_FILEPROP_FILES_DIRS=/usr/local/sbin
#USER_FILEPROP_FILES_DIRS=/etc/rkhunter.conf
#USER_FILEPROP_FILES_DIRS=/etc/rkhunter.conf.local
-#USER_FILEPROP_FILES_DIRS=/var/lib/rkhunter/db/*
-#USER_FILEPROP_FILES_DIRS=/var/lib/rkhunter/db/i18n/*
+#USER_FILEPROP_FILES_DIRS=/etc/rkhunter.d/*
#EXCLUDE_USER_FILEPROP_FILES_DIRS=/opt/ps*
-#EXCLUDE_USER_FILEPROP_FILES_DIRS=/var/lib/rkhunter/db/mirrors.dat
-#EXCLUDE_USER_FILEPROP_FILES_DIRS=/var/lib/rkhunter/db/rkhunter*
#
# This option whitelists files and directories from existing, or not existing,
@@ -549,13 +555,17 @@ HASH_CMD=sha512sum
# NOTE: The user must take into consideration how often the file will appear
# and disappear from the system in relation to how often rkhunter is run. If
# the file appears, and disappears, too often then rkhunter may not notice
-# this. All it will see is that the file has changed. The inode-number and DTM
+# this. All it will see is that the file has changed. The inode number and DTM
# will certainly be different for each new file, and rkhunter will report this.
#
# The default value is the null string.
#
#EXISTWHITELIST=""
+# work around for usr-merge, cf. https://bugs.debian.org/932594
+EXISTWHITELIST=/usr/bin/egrep
+EXISTWHITELIST=/usr/bin/fgrep
+
#
# Whitelist various attributes of the specified file. The attributes are those
# of the 'attributes' test. Specifying a file name here does not include it
@@ -586,7 +596,10 @@ HASH_CMD=sha512sum
#
SCRIPTWHITELIST=/bin/egrep
SCRIPTWHITELIST=/bin/fgrep
-SCRIPTWHITELIST=/bin/which
+SCRIPTWHITELIST=/usr/bin/egrep
+SCRIPTWHITELIST=/usr/bin/fgrep
+SCRIPTWHITELIST=/usr/bin/which
+SCRIPTWHITELIST=/usr/bin/which.debianutils
SCRIPTWHITELIST=/usr/bin/ldd
SCRIPTWHITELIST=/usr/bin/lwp-request
SCRIPTWHITELIST=/usr/sbin/adduser
@@ -612,6 +625,18 @@ SCRIPTWHITELIST=/usr/sbin/adduser
#IMMUTABLE_SET=0
#
+# If this option is set to '1', then any changed inode value is ignored in
+# the file properties check. The inode test itself still runs, but it will
+# always return that no inodes have changed.
+#
+# This option may be useful for filesystems such as Btrfs, which handle inodes
+# slightly differently than other filesystems.
+#
+# The default value is '0'.
+#
+#SKIP_INODE_CHECK=0
+
+#
# Allow the specified hidden directory to be whitelisted.
#
# This option may be specified more than once, and may use wildcard characters.
@@ -644,13 +669,21 @@ ALLOWHIDDENFILE=/etc/.etckeeper
#
# Allow the specified process to use deleted files. The process name may be
-# followed by a colon-separated list of full pathnames. The process will then
-# only be whitelisted if it is using one of the given files. For example:
+# followed by a colon-separated list of full pathnames (which have been
+# deleted). The process will then only be whitelisted if it is using one of
+# the given pathnames. For example:
#
# ALLOWPROCDELFILE=/usr/libexec/gconfd-2:/tmp/abc:/var/tmp/xyz
#
# This option may be specified more than once. It may also use wildcards, but
-# only in the file names.
+# only in the deleted file pathnames, not in the process name. The use of
+# extended pattern matching in pathname expansion (for example, '**') is not
+# supported for this option. However, the option itself extends globbing when
+# the '*' character is used by matching zero or more characters in the
+# pathname, including those in sub-directories. For example, the pathname
+# '/tmp/abc/def/xyz' would not be matched by shell globbing using '/tmp/*/xyz'
+# but is matched when used in this option. Similarly, using '/tmp/*' will
+# match any file found in the '/tmp' directory or any sub-directories.
#
# The default value is the null string.
#
@@ -707,6 +740,46 @@ ALLOWHIDDENFILE=/etc/.etckeeper
#ALLOWDEVFILE=/dev/shm/sem.ADBE_*
#
+# Allow the specified process pathnames to use shared memory segments.
+#
+# This option may be specified more than once, and may use wildcard characters.
+#
+# The default value is the null string.
+#
+#ALLOWIPCPROC=/usr/bin/firefox
+#ALLOWIPCPROC=/usr/bin/vlc
+
+#
+# Allow the specified memory segment creator PIDs to use shared memory segments.
+#
+# This is a space-separated list of PID numbers (as given by the
+# 'ipcs -p' command). This option may be specified more than once.
+#
+# The default value is the null string.
+#
+#ALLOWIPCPID=12345 6789
+
+#
+# Allow the specified account names to use shared memory segments.
+#
+# This is a space-separated list of account names. The option may be specified
+# more than once.
+#
+# The default value is the null string.
+#
+#ALLOWIPCUSER=usera userb
+
+#
+# This option can be used to set the maximum shared memory segment size
+# (in bytes) that is not considered suspicious. Any segment above this size,
+# and with 600 or 666 permissions, will be considered suspicious during the
+# shared memory check.
+#
+# The default is 1048576 (1M) bytes.
+#
+#IPC_SEG_SIZE=1048576
+
+#
# This option is used to indicate if the Phalanx2 test is to perform a basic
# check, or a more thorough check. If the option is set to '0', then a basic
# check is performed. If it is set to '1', then all the directories in the
@@ -776,9 +849,9 @@ ALLOWHIDDENFILE=/etc/.etckeeper
#
# This option tells rkhunter the local system startup file pathnames. The
-# directories will be searched for files. By default rkhunter will try and
-# determine were the startup files are located. If the option is set to 'NONE',
-# then certain tests will be skipped.
+# directories will be searched for files. If unset, then rkhunter will try
+# and determine were the startup files are located. If the option is set to
+# 'NONE' then certain tests will be skipped.
#
# This is a space-separated list of file and directory pathnames. The option
# may be specified more than once, and may use wildcard characters.
@@ -789,9 +862,9 @@ ALLOWHIDDENFILE=/etc/.etckeeper
#
# This option tells rkhunter the pathname to the file containing the user
-# account passwords. This setting will be worked out by rkhunter, and so
-# should not usually need to be set. Users of TCB shadow files should not
-# set this option.
+# account passwords. If unset, this setting will be worked out by rkhunter,
+# and so should not usually need to be set. Users of TCB shadow files should
+# not set this option.
#
# This option has no default value.
#
@@ -825,9 +898,10 @@ ALLOWHIDDENFILE=/etc/.etckeeper
#
# This option tells rkhunter the pathname to the syslog configuration file.
-# This setting will be worked out by rkhunter, and so should not usually need
-# to be set. A value of 'NONE' can be used to indicate that there is no
-# configuration file, but that the syslog daemon process may be running.
+# If unset, this setting will be worked out by rkhunter, and so should not
+# usually need to be set. A value of 'NONE' can be used to indicate that
+# there is no configuration file, but that the syslog daemon process may
+# be running.
#
# This is a space-separated list of pathnames. The option may be specified
# more than once.
@@ -896,7 +970,7 @@ ALLOWHIDDENFILE=/etc/.etckeeper
#
# The default value is '1024000'.
#
-#SUSPSCAN_MAXSIZE=10240000
+#SUSPSCAN_MAXSIZE=1024000
#
# This option specifies the 'suspscan' test score threshold. Below this value
@@ -907,6 +981,18 @@ ALLOWHIDDENFILE=/etc/.etckeeper
#SUSPSCAN_THRESH=200
#
+# This option may be used to whitelist file pathnames from the suspscan test.
+#
+# Shell globbing may be used in the pathname. Also see the GLOBSTAR configuration
+# option.
+#
+# This option may be specified more than once.
+#
+# The default value is the null string.
+#
+#SUSPSCAN_WHITELIST=""
+
+#
# The following options can be used to whitelist network ports which are known
# to have been used by malware.
#
@@ -1076,8 +1162,8 @@ ALLOWHIDDENFILE=/etc/.etckeeper
#
# This setting tells rkhunter the directory containing the available Linux
-# kernel modules. This setting will be worked out by rkhunter, and so should
-# not usually need to be set.
+# kernel modules. If unset, this setting will be worked out by rkhunter, and
+# so should not usually need to be set.
#
# This option has no default value.
#
@@ -1114,18 +1200,33 @@ WEB_CMD="/bin/false"
# The lock is set just before logging starts, and is removed when the program
# ends. It is used to prevent items such as the log file, and the file
# properties file, from becoming corrupted if rkhunter is running more than
-# once. The mechanism used is to simply create a lock file in the TMPDIR
+# once. The mechanism used is to simply create a lock file in the LOCKDIR
# directory. If the lock file already exists, because rkhunter is already
# running, then the current process simply loops around sleeping for 10 seconds
# and then retrying the lock. A value of '0' means not to use locking.
#
# The default value is '0'.
#
-# Also see the LOCK_TIMEOUT and SHOW_LOCK_MSGS options.
+# Also see the LOCKDIR, LOCK_TIMEOUT and SHOW_LOCK_MSGS options.
#
#USE_LOCKING=0
#
+# This option specifies the directory to be used when locking is enabled.
+# If the option is unset, then the directory to be used will be worked out
+# by rkhunter. In that instance the directories '/run/lock', '/var/lock',
+# '/var/run/lock', '/run' and '/var/run' will be checked in turn. If none
+# of those can be found, or are not read/writeable, then the TMPDIR directory
+# will be used.
+#
+# To avoid the lock file persisting across a server reboot, the directory
+# used should be memory-resident.
+#
+# This option has no default value.
+#
+#LOCKDIR=""
+
+#
# If locking is used, then rkhunter may have to wait to get the lock file.
# This option sets the total amount of time, in seconds, that rkhunter should
# wait. It will retry the lock every 10 seconds, until either it obtains the
@@ -1191,22 +1292,6 @@ WEB_CMD="/bin/false"
#UNHIDETCP_OPTS=""
#
-# If both the C 'unhide', and Ruby 'unhide.rb', programs exist on the system,
-# then it is possible to disable the execution of one of the programs if
-# desired. By default rkhunter will look for both programs, and execute each
-# of them as they are found. If the value of this option is '0', then both
-# programs will be executed if they are present. A value of '1' will disable
-# execution of the C 'unhide' program, and a value of '2' will disable the Ruby
-# 'unhide.rb' program. To disable both programs, then disable the
-# 'hidden_procs' test.
-#
-# The default value is '0'.
-#
-DISABLE_UNHIDE=1
-
-INSTALLDIR=/usr
-
-#
# This option can be set to either '0' or '1'. If set to '1' then the summary,
# shown after rkhunter has run, will display the actual number of warnings
# found. If it is set to '0', then the summary will simply indicate that
@@ -1249,3 +1334,25 @@ INSTALLDIR=/usr
#EMPTY_LOGFILES=""
#MISSING_LOGFILES=""
+#
+# This option can be set to either '0' or '1'. If set to '1' then the globbing
+# characters '**' can be used to allow the recursive checking of directories.
+# This can be useful, for example, with the USER_FILEPROP_FILES_DIRS option.
+# For example:
+#
+# USER_FILEPROP_FILES_DIRS=/etc/**/*.conf
+#
+# This will check all '.conf' files within the '/etc' directory, and any
+# sub-directories (at any level). If GLOBSTAR is not set, then the shell will
+# interpret '**' as '*' and only one level of sub-directories will be checked.
+#
+# NOTE: This option is only valid for those shells which support the 'globstar'
+# option. Typically this will be 'bash' (version 4 and above) via the 'shopt' command,
+# and 'ksh' via the 'set' command.
+#
+# The default value is '0'.
+#
+#GLOBSTAR=0
+
+INSTALLDIR=/usr
+
diff --git a/roles/common/files/etc/rsyslog.conf b/roles/common/files/etc/rsyslog.conf
index 70e8a77..42b01c5 100644
--- a/roles/common/files/etc/rsyslog.conf
+++ b/roles/common/files/etc/rsyslog.conf
@@ -1,7 +1,7 @@
-# /etc/rsyslog.conf Configuration file for rsyslog.
+# /etc/rsyslog.conf configuration file for rsyslog
#
-# For more information see
-# /usr/share/doc/rsyslog-doc/html/rsyslog_conf.html
+# For more information install rsyslog-doc and see
+# /usr/share/doc/rsyslog-doc/html/configuration/index.html
#################
@@ -75,7 +75,7 @@ if $programname == 'amavis' and $syslogfacility-text == 'mail' and $syslogseveri
if ($programname startswith 'postfix-' or $programname == 'dovecot') and $syslogfacility-text == 'mail' and $syslogseverity >= 6 then ~
#
-# Some standard log files. Log by facility.
+# First some standard log files. Log by facility.
#
auth,authpriv.* /var/log/auth.log
*.*;auth,authpriv.none -/var/log/syslog
@@ -90,11 +90,11 @@ user.* -/var/log/user.log
#
*.=debug;\
auth,authpriv.none;\
- news.none;mail.none -/var/log/debug
+ mail.none -/var/log/debug
*.=info;*.=notice;*.=warn;\
auth,authpriv.none;\
cron,daemon.none;\
- mail,news.none -/var/log/messages
+ mail.none -/var/log/messages
#
# Emergencies are sent to everybody logged in.
diff --git a/roles/common/files/etc/strongswan.d/charon.conf b/roles/common/files/etc/strongswan.d/charon.conf
index 5ed6452..efb241c 100644
--- a/roles/common/files/etc/strongswan.d/charon.conf
+++ b/roles/common/files/etc/strongswan.d/charon.conf
@@ -1,15 +1,20 @@
# Options for the charon IKE daemon.
charon {
+ # Deliberately violate the IKE standard's requirement and allow the use of
+ # private algorithm identifiers, even if the peer implementation is unknown.
+ # accept_private_algs = no
+
# Accept unencrypted ID and HASH payloads in IKEv1 Main Mode.
# accept_unencrypted_mainmode_messages = no
- # Maximum number of half-open IKE_SAs for a single peer IP.
+ # Maximum number of half-open IKE_SAs (including unprocessed IKE_SA_INITs)
+ # for a single peer IP.
# block_threshold = 5
- # Whether Certicate Revocation Lists (CRLs) fetched via HTTP or LDAP should
- # be saved under a unique file name derived from the public key of the
- # Certification Authority (CA) to /etc/ipsec.d/crls (stroke) or
+ # Whether Certificate Revocation Lists (CRLs) fetched via HTTP or LDAP
+ # should be saved under a unique file name derived from the public key of
+ # the Certification Authority (CA) to /etc/ipsec.d/crls (stroke) or
# /etc/swanctl/x509crl (vici), respectively.
# cache_crls = no
@@ -17,18 +22,34 @@ charon {
# memory.
# cert_cache = yes
+ # Whether to use DPD to check if the current path still works after any
+ # changes to interfaces/addresses.
+ # check_current_path = no
+
+ # Send the Cisco FlexVPN vendor ID payload (IKEv2 only).
+ # cisco_flexvpn = no
+
# Send Cisco Unity vendor ID payload (IKEv1 only).
# cisco_unity = no
# Close the IKE_SA if setup of the CHILD_SA along with IKE_AUTH failed.
# close_ike_on_child_failure = no
- # Number of half-open IKE_SAs that activate the cookie mechanism.
- # cookie_threshold = 10
+ # Number of half-open IKE_SAs (including unprocessed IKE_SA_INITs) that
+ # activate the cookie mechanism.
+ # cookie_threshold = 30
+
+ # Number of half-open IKE_SAs (including unprocessed IKE_SA_INITs) for a
+ # single peer IP that activate the cookie mechanism.
+ # cookie_threshold_ip = 3
# Delete CHILD_SAs right after they got successfully rekeyed (IKEv1 only).
# delete_rekeyed = no
+ # Delay in seconds until inbound IPsec SAs are deleted after rekeyings
+ # (IKEv2 only).
+ # delete_rekeyed_delay = 5
+
# Use ANSI X9.42 DH exponent size or optimum size matched to cryptographic
# strength.
# dh_exponent_ansi_x9_42 = yes
@@ -47,15 +68,16 @@ charon {
# checks.
# dos_protection = yes
- # Compliance with the errata for RFC 4753.
- # ecp_x_coordinate_only = yes
-
# Free objects during authentication (might conflict with plugins).
# flush_auth_cfg = no
# Whether to follow IKEv2 redirects (RFC 5685).
# follow_redirects = yes
+ # Violate RFC 5998 and use EAP-only authentication even if the peer did not
+ # send an EAP_ONLY_AUTHENTICATION notify during IKE_AUTH.
+ # force_eap_only_authentication = no
+
# Maximum size (complete IP datagram size in bytes) of a sent IKE fragment
# when using proprietary IKEv1 or standardized IKEv2 fragmentation, defaults
# to 1280 (use 0 for address family specific default values, which uses a
@@ -131,6 +153,11 @@ charon {
# NAT keep alive interval.
# keep_alive = 20s
+ # Number of seconds the keep alive interval may be exceeded before a DPD is
+ # sent instead of a NAT keep alive (0 to disable). This is only useful if a
+ # clock is used that includes time spent suspended (e.g. CLOCK_BOOTTIME).
+ # keep_alive_dpd_margin = 0s
+
# Plugins to load in the IKE daemon charon.
# load =
@@ -164,19 +191,25 @@ charon {
# will be allocated.
# port_nat_t = 4500
+ # Whether to prefer updating SAs to the path with the best route.
+ # prefer_best_path = no
+
# Prefer locally configured proposals for IKE/IPsec over supplied ones as
# responder (disabling this can avoid keying retries due to
# INVALID_KE_PAYLOAD notifies).
# prefer_configured_proposals = yes
- # By default public IPv6 addresses are preferred over temporary ones (RFC
- # 4941), to make connections more stable. Enable this option to reverse
- # this.
+ # Controls whether permanent or temporary IPv6 addresses are used as source,
+ # or announced as additional addresses if MOBIKE is used.
# prefer_temporary_addrs = no
# Process RTM_NEWROUTE and RTM_DELROUTE events.
# process_route = yes
+ # How RDNs in subject DNs of certificates are matched against configured
+ # identities (strict, reordered, or relaxed).
+ # rdn_matching = strict
+
# Delay in ms for receiving packets, to simulate larger RTT.
# receive_delay = 0
@@ -196,6 +229,14 @@ charon {
# in strongswan.conf(5).
# retransmit_base = 1.8
+ # Maximum jitter in percent to apply randomly to calculated retransmission
+ # timeout (0 to disable).
+ # retransmit_jitter = 0
+
+ # Upper limit in seconds for calculated retransmission timeout (0 to
+ # disable).
+ # retransmit_limit = 0
+
# Timeout in seconds before sending first retransmit.
# retransmit_timeout = 4.0
@@ -215,6 +256,13 @@ charon {
# Priority of the routing table.
# routing_table_prio =
+ # Whether to use RSA with PSS padding instead of PKCS#1 padding by default.
+ # rsa_pss = no
+
+ # Whether to encode an explicit trailerField value of 0x01 in the RSA-PSS
+ # algorithmIdentifier (CONTEXT3) or using the DEFAULT value by omitting it.
+ # rsa_pss_trailerfield = no
+
# Delay in ms for sending packets, to simulate larger RTT.
# send_delay = 0
@@ -236,6 +284,19 @@ charon {
# Whether to enable constraints against IKEv2 signature schemes.
# signature_authentication_constraints = yes
+ # Value mixed into the local IKE SPIs after applying spi_mask.
+ # spi_label = 0x0000000000000000
+
+ # Mask applied to local IKE SPIs before mixing in spi_label (bits set will
+ # be replaced with spi_label).
+ # spi_mask = 0x0000000000000000
+
+ # The upper limit for SPIs requested from the kernel for IPsec SAs.
+ # spi_max = 0xcfffffff
+
+ # The lower limit for SPIs requested from the kernel for IPsec SAs.
+ # spi_min = 0xc0000000
+
# Number of worker threads in charon.
# threads = 16
@@ -250,7 +311,7 @@ charon {
# Buffer size used for crypto benchmark.
# bench_size = 1024
- # Number of iterations to test each algorithm.
+ # Time in ms during which crypto algorithm performance is measured.
# bench_time = 50
# Test crypto algorithms during registration (requires test vectors
@@ -284,11 +345,12 @@ charon {
# Includes source file names and line numbers in leak detective output.
# detailed = yes
- # Threshold in bytes for leaks to be reported (0 to report all).
+ # Threshold in bytes for allocations to be included in usage reports (0
+ # to include all).
# usage_threshold = 10240
- # Threshold in number of allocations for leaks to be reported (0 to
- # report all).
+ # Threshold in number of allocations for allocations to be included in
+ # usage reports (0 to include all).
# usage_threshold_count = 0
}
@@ -320,15 +382,30 @@ charon {
# List of TLS encryption ciphers.
# cipher =
+ # List of TLS key exchange groups.
+ # ke_group =
+
# List of TLS key exchange methods.
# key_exchange =
# List of TLS MAC algorithms.
# mac =
+ # Whether to include CAs in a server's CertificateRequest message.
+ # send_certreq_authorities = yes
+
+ # List of TLS signature schemes.
+ # signature =
+
# List of TLS cipher suites.
# suites =
+ # Maximum TLS version to negotiate.
+ # version_max = 1.2
+
+ # Minimum TLS version to negotiate.
+ # version_min = 1.2
+
}
x509 {
diff --git a/roles/common/files/etc/strongswan.d/charon/socket-default.conf b/roles/common/files/etc/strongswan.d/charon/socket-default.conf
index 6d4b73d..abf4650 100644
--- a/roles/common/files/etc/strongswan.d/charon/socket-default.conf
+++ b/roles/common/files/etc/strongswan.d/charon/socket-default.conf
@@ -10,6 +10,9 @@ socket-default {
# Set source address on outbound packets, if possible.
# set_source = yes
+ # Force sending interface on outbound packets, if possible.
+ # set_sourceif = no
+
# Listen on IPv4, if possible.
# use_ipv4 = yes
diff --git a/roles/common/files/etc/systemd/system/bacula-fd.service b/roles/common/files/etc/systemd/system/bacula-fd.service
deleted file mode 100644
index 792d964..0000000
--- a/roles/common/files/etc/systemd/system/bacula-fd.service
+++ /dev/null
@@ -1,25 +0,0 @@
-[Unit]
-Description=Bacula File Daemon service
-After=network.target
-
-[Service]
-Type=simple
-StandardOutput=syslog
-ExecStart=/usr/sbin/bacula-fd -f -c /etc/bacula/bacula-fd.conf
-
-# Hardening
-NoNewPrivileges=yes
-PrivateDevices=yes
-ProtectHome=read-only
-ProtectSystem=strict
-PrivateTmp=yes
-ReadWriteDirectories=-/var/lib
-ReadWriteDirectories=-/var/run/bacula
-PrivateDevices=yes
-ProtectControlGroups=yes
-ProtectKernelModules=yes
-ProtectKernelTunables=yes
-RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
-
-[Install]
-WantedBy=multi-user.target
diff --git a/roles/common/files/etc/systemd/system/bacula-fd.service.d/override.conf b/roles/common/files/etc/systemd/system/bacula-fd.service.d/override.conf
new file mode 100644
index 0000000..537bf1e
--- /dev/null
+++ b/roles/common/files/etc/systemd/system/bacula-fd.service.d/override.conf
@@ -0,0 +1,13 @@
+[Service]
+# Hardening
+NoNewPrivileges=yes
+ProtectHome=read-only
+ProtectSystem=strict
+ReadWriteDirectories=/var/lib/bacula
+PrivateTmp=yes
+PrivateDevices=yes
+ProtectControlGroups=yes
+ProtectKernelModules=yes
+ProtectKernelTunables=yes
+RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
+CapabilityBoundingSet=CAP_DAC_READ_SEARCH
diff --git a/roles/common/files/etc/systemd/system/fail2ban.service.d/override.conf b/roles/common/files/etc/systemd/system/fail2ban.service.d/override.conf
index e3e651f..b34d130 100644
--- a/roles/common/files/etc/systemd/system/fail2ban.service.d/override.conf
+++ b/roles/common/files/etc/systemd/system/fail2ban.service.d/override.conf
@@ -2,13 +2,16 @@
After=nftables.service
[Service]
+ExecStartPre=
+ExecStart=
+ExecStart=/usr/bin/fail2ban-server -xf --logtarget=sysout start
+
# Need explicit rights to read logs as we don't grant CAP_DAC_READ_SEARCH
SupplementaryGroups=adm
# Hardening
NoNewPrivileges=yes
ProtectSystem=strict
-ReadWriteDirectories=/var/log/fail2ban
RuntimeDirectory=fail2ban
PrivateDevices=yes
ProtectControlGroups=yes
diff --git a/roles/common/files/etc/systemd/system/munin-node.service.d/override.conf b/roles/common/files/etc/systemd/system/munin-node.service.d/override.conf
new file mode 100644
index 0000000..fee16b3
--- /dev/null
+++ b/roles/common/files/etc/systemd/system/munin-node.service.d/override.conf
@@ -0,0 +1,14 @@
+[Service]
+ExecStartPre=
+
+# Hardening
+NoNewPrivileges=yes
+ProtectSystem=strict
+ReadWriteDirectories=/var/lib/munin-node/plugin-state
+ReadWriteDirectories=/var/log/munin
+RuntimeDirectory=munin
+ProtectControlGroups=yes
+ProtectKernelModules=yes
+ProtectKernelTunables=yes
+RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
+CapabilityBoundingSet=CAP_SETUID CAP_SETGID
diff --git a/roles/common/files/etc/systemd/system/stunnel4@.service b/roles/common/files/etc/systemd/system/stunnel4@.service
index 1a30599..4d69702 100644
--- a/roles/common/files/etc/systemd/system/stunnel4@.service
+++ b/roles/common/files/etc/systemd/system/stunnel4@.service
@@ -1,10 +1,15 @@
[Unit]
Description=SSL tunnel for network daemons (instance %i)
+Documentation=man:stunnel4(8)
After=network.target nss-lookup.target
PartOf=stunnel4.service
ReloadPropagatedFrom=stunnel4.service
[Service]
+DynamicUser=yes
+; force dynamic user/group allocation (stunnel4 user exists already)
+User=_stunnel4-%i
+Group=_stunnel4-%i
ExecStart=/usr/bin/stunnel4 /etc/stunnel/%i.conf
ExecReload=/bin/kill -HUP ${MAINPID}
KillSignal=SIGINT
diff --git a/roles/common/files/usr/local/bin/genkeypair.sh b/roles/common/files/usr/local/bin/genkeypair.sh
index ad65aef..aecdaaf 100755
--- a/roles/common/files/usr/local/bin/genkeypair.sh
+++ b/roles/common/files/usr/local/bin/genkeypair.sh
@@ -119,14 +119,16 @@ done
case "$type" in
# XXX: genrsa and dsaparam have been deprecated in favor of genpkey.
# genpkey can also create explicit EC parameters, but not named.
- rsa) genkey=genrsa; genkeyargs="-f4 ${bits:-2048}";;
- dsa) genkey=dsaparam; genkeyargs="-noout -genkey ${bits:-1024}";;
+ rsa) genkey=genrsa; genkeyargs="-rand /dev/urandom -f4 ${bits:-2048}";;
+ dsa) genkey=dsaparam; genkeyargs="-rand /dev/urandom -noout -genkey ${bits:-1024}";;
# See 'openssl ecparam -list_curves' for the list of supported
# curves. StrongSwan doesn't support explicit curve parameters
# (however explicit parameters might be required to make exotic
# curves work with some clients.)
ecdsa) genkey=ecparam
- genkeyargs="-noout -name ${bits:-secp224r1} -param_enc named_curve -genkey";;
+ genkeyargs="-rand /dev/urandom -noout -name ${bits:-secp224r1} -param_enc named_curve -genkey";;
+ x25519|x448|ed25519|ed448) genkey=genpkey
+ genkeyargs="-algorithm $type";;
*) echo "Unrecognized key type: $type" >&2; exit 2
esac
@@ -160,7 +162,7 @@ if [ -z "$config" -a \( "$cmd" = x509 -o "$cmd" = csr \) ]; then
commonName = ${cn:-/}
[ v3_req ]
- subjectAltName = email:admin@fripost.org${dns:+, $dns}
+ subjectAltName = email:root@fripost.org${dns:+, $dns}
basicConstraints = critical, CA:FALSE
# https://security.stackexchange.com/questions/24106/which-key-usages-are-required-by-each-key-exchange-method
keyUsage = critical, ${usage:-digitalSignature, keyEncipherment, keyCertSign}
@@ -173,7 +175,7 @@ if [ -s "$privkey" -a $force -eq 0 ]; then
exit 1
elif [ ! -s "$privkey" -o $force -ge 2 ]; then
install --mode="${mode:-0600}" ${owner:+--owner="$owner"} ${group:+--group="$group"} /dev/null "$privkey" || exit 2
- openssl $genkey -rand /dev/urandom $genkeyargs >"$privkey" || exit 2
+ openssl $genkey $genkeyargs >"$privkey" || exit 2
[ "$cmd" = dkim ] && exit
fi
diff --git a/roles/common/files/usr/local/sbin/update-firewall b/roles/common/files/usr/local/sbin/update-firewall
index 957bdc1..e11e8a9 100755
--- a/roles/common/files/usr/local/sbin/update-firewall
+++ b/roles/common/files/usr/local/sbin/update-firewall
@@ -22,13 +22,6 @@ cat <"$NFTABLES" >>"$script"
ip netns add "nft-dryrun"
netns="nft-dryrun"
-# clear sets in the old rules before diff'ing with the new ones
-nft list ruleset -sn >"$oldrules"
-ip netns exec "$netns" nft -f - <"$oldrules"
-ip netns exec "$netns" nft flush set inet filter fail2ban
-ip netns exec "$netns" nft flush set inet filter fail2ban6
-ip netns exec "$netns" nft list ruleset -sn >"$oldrules"
-
declare -a INTERFACES=()
for iface in /sys/class/net/*; do
idx="$(< "$iface/ifindex")"
@@ -42,8 +35,15 @@ for idx in "${!INTERFACES[@]}"; do
ip netns exec "$netns" ip link add "${INTERFACES[idx]}" index "$idx" type dummy
done
+# clear sets in the old rules before diff'ing with the new ones
+nft -sn list ruleset >"$oldrules"
+ip netns exec "$netns" nft -f - <"$oldrules"
+ip netns exec "$netns" nft flush set inet filter fail2ban || true
+ip netns exec "$netns" nft flush set inet filter fail2ban6 || true
+ip netns exec "$netns" nft -sn list ruleset >"$oldrules"
+
ip netns exec "$netns" nft -f - <"$script"
-ip netns exec "$netns" nft list ruleset -sn >"$newrules"
+ip netns exec "$netns" nft -sn list ruleset >"$newrules"
ip netns del "$netns"
netns=
diff --git a/roles/common/handlers/main.yml b/roles/common/handlers/main.yml
index 394c67a..18462cb 100644
--- a/roles/common/handlers/main.yml
+++ b/roles/common/handlers/main.yml
@@ -18,7 +18,7 @@
command: /usr/bin/rkhunter --propupd
- name: Update firewall
- command: /usr/local/sbin/update-firewall.sh -c
+ command: /usr/local/sbin/update-firewall -c
- name: Restart fail2ban
service: name=fail2ban state=restarted
@@ -26,15 +26,15 @@
- name: Restart IPsec
service: name=ipsec state=restarted
-- name: Reload networking
- # /etc/init.d/networking doesn't answer the status command; but since
- # it should be "up" whenever ansible has access to the machine, we use
- # pattern=init as a dummy assumption.
- service: name=networking pattern=init state=reloaded
-
- name: Restart rsyslog
service: name=rsyslog state=restarted
+- name: Restart systemd-resolved
+ service: name=systemd-resolved.service state=restarted
+
+- name: Restart systemd-timesyncd
+ service: name=systemd-timesyncd state=restarted
+
- name: Restart ntp
service: name=ntp state=restarted
diff --git a/roles/common/tasks/bacula.yml b/roles/common/tasks/bacula.yml
index 73a2fa1..308e358 100644
--- a/roles/common/tasks/bacula.yml
+++ b/roles/common/tasks/bacula.yml
@@ -10,7 +10,7 @@
- name: Delete /etc/bacula/common_default_passwords
file: path=/etc/bacula/common_default_passwords state=absent
-# Create with:
+# Populate with:
# echo $director-dir $(pwgen -sn 64 1) | sudo tee -a /etc/bacula/passwords-fd
- name: Ensure /etc/bacula/passwords-fd exists
file: path=/etc/bacula/passwords-fd
@@ -54,9 +54,15 @@
tags:
- genkey
-- name: Copy bacula-fd.service
- copy: src=etc/systemd/system/bacula-fd.service
- dest=/etc/systemd/system/bacula-fd.service
+- name: Create /etc/systemd/system/bacula-fd.service.d
+ file: path=/etc/systemd/system/bacula-fd.service.d
+ state=directory
+ owner=root group=root
+ mode=0755
+
+- name: Copy bacula-fd.service override
+ copy: src=etc/systemd/system/bacula-fd.service.d/override.conf
+ dest=/etc/systemd/system/bacula-fd.service.d/override.conf
owner=root group=root
mode=0644
notify:
diff --git a/roles/common/tasks/fail2ban.yml b/roles/common/tasks/fail2ban.yml
index 89427ea..563075f 100644
--- a/roles/common/tasks/fail2ban.yml
+++ b/roles/common/tasks/fail2ban.yml
@@ -1,22 +1,6 @@
- name: Install fail2ban
apt: pkg=fail2ban
-# Log into a dedicate directory so we can use ReadWriteDirectories in
-# the .service file
-- name: Create directory /var/log/fail2ban
- file: path=/var/log/fail2ban
- state=directory
- owner=root group=adm
- mode=0750
-
-- name: Fix fail2ban logrotate snippet
- lineinfile: dest=/etc/logrotate.d/fail2ban
- state=present
- line="/var/log/fail2ban/*.log"
- insertbefore="^[^#]*\\s{$"
- tags:
- - logrotate
-
- name: Configure fail2ban (fail2ban.local)
copy: src=etc/fail2ban/fail2ban.local
dest=/etc/fail2ban/fail2ban.local
@@ -53,11 +37,11 @@
notify:
- Restart fail2ban
-- name: Create directory /etc/systemd/system/fail2ban.service.d/override.conf
+- name: Create directory /etc/systemd/system/fail2ban.service.d
file: path=/etc/systemd/system/fail2ban.service.d
state=directory
owner=root group=root
- mode=0750
+ mode=0755
- name: Harden fail2ban.service
copy: src=etc/systemd/system/fail2ban.service.d/override.conf
diff --git a/roles/common/tasks/firewall.yml b/roles/common/tasks/firewall.yml
index fd1ad92..30f4fa9 100644
--- a/roles/common/tasks/firewall.yml
+++ b/roles/common/tasks/firewall.yml
@@ -18,7 +18,7 @@
register: rv
# A non-zero return value will make ansible stop and show stderr. This
# is what we want.
- changed_when: rv.rc
+ changed_when: rv.rc != 0
- name: Enable nftables.service
service: name=nftables enabled=yes
diff --git a/roles/common/tasks/ipsec.yml b/roles/common/tasks/ipsec.yml
index 989541b..917c687 100644
--- a/roles/common/tasks/ipsec.yml
+++ b/roles/common/tasks/ipsec.yml
@@ -3,6 +3,7 @@
vars:
packages:
- strongswan-charon
+ - strongswan-starter
# for the GCM and openssl plugins
- libstrongswan-standard-plugins
notify:
@@ -14,16 +15,12 @@
dest=/etc/network/if-up.d/ipsec
owner=root group=root
mode=0755
- notify:
- - Reload networking
- name: Auto-deactivate the dedicated virtual subnet for IPsec
file: src=../if-up.d/ipsec
dest=/etc/network/if-down.d/ipsec
owner=root group=root state=link force=yes
-- meta: flush_handlers
-
- name: Configure IPsec
template: src=etc/ipsec.conf.j2
diff --git a/roles/common/tasks/logging.yml b/roles/common/tasks/logging.yml
index b602a49..699c6e3 100644
--- a/roles/common/tasks/logging.yml
+++ b/roles/common/tasks/logging.yml
@@ -3,7 +3,6 @@
vars:
packages:
- rsyslog
- - syslog-summary
- logcheck
- logcheck-database
- logrotate
@@ -41,7 +40,7 @@
- name: Configure logcheck (1)
copy: src=etc/logcheck/{{ item }}
dest=/etc/logcheck/{{ item }}
- owner=root group=logcheck
+ owner=root group=root
mode=0644
with_items:
- logcheck.conf
@@ -60,8 +59,8 @@
line={{ item }}
state=present
create=yes
- owner=root group=logcheck
- mode=0640
+ owner=root group=root
+ mode=0644
with_items:
- /var/log/syslog
- /var/log/auth.log
diff --git a/roles/common/tasks/main.yml b/roles/common/tasks/main.yml
index 02a745c..293d22b 100644
--- a/roles/common/tasks/main.yml
+++ b/roles/common/tasks/main.yml
@@ -16,9 +16,14 @@
- import_tasks: stunnel.yml
tags: stunnel
- when: "'webmail' in group_names and 'LDAP-provider' not in group_names"
-- import_tasks: auditd.yml
- tags: auditd
+ when: "'webmail' in group_names and 'LDAP_provider' not in group_names"
+#- import_tasks: auditd.yml
+# tags: auditd
+- import_tasks: resolved.yml
+ tags:
+ - resolv
+ - resolved
+ - dns
- import_tasks: unbound.yml
tags:
- unbound
@@ -82,7 +87,7 @@
- molly-guard
- rsync
- screen
- - telnet-ssl
+ - bind9-dnsutils
- name: Disable resume device
# Cf. initramfs-tools(7) and initramfs.conf(5).
diff --git a/roles/common/tasks/munin-node.yml b/roles/common/tasks/munin-node.yml
index f43094a..2411b59 100644
--- a/roles/common/tasks/munin-node.yml
+++ b/roles/common/tasks/munin-node.yml
@@ -62,10 +62,6 @@
- load
- memory
- netstat
- - ntp_kernel_err
- - ntp_kernel_pll_freq
- - ntp_kernel_pll_off
- - ntp_offset
- open_files
- open_inodes
- processes
@@ -78,6 +74,20 @@
notify:
- Restart munin-node
+- name: Install Munin plugins
+ file: src=/usr/share/munin/plugins/{{ item }}
+ dest=/etc/munin/plugins/{{ item }}
+ owner=root group=root
+ state=link force=yes
+ with_items:
+ - ntp_kernel_err
+ - ntp_kernel_pll_freq
+ - ntp_kernel_pll_off
+ - ntp_offset
+ when: "'NTP_master' in group_names"
+ notify:
+ - Restart munin-node
+
- name: Delete unnecessary Munin plugins
file: path=/etc/munin/plugins/{{ item }}
state=absent
@@ -90,6 +100,18 @@
notify:
- Restart munin-node
+- name: Delete unnecessary Munin plugins
+ file: path=/etc/munin/plugins/{{ item }}
+ state=absent
+ with_items:
+ - ntp_kernel_err
+ - ntp_kernel_pll_freq
+ - ntp_kernel_pll_off
+ - ntp_offset
+ when: "'NTP_master' not in group_names"
+ notify:
+ - Restart munin-node
+
- name: Install 'if_' Munin wildcard plugin
file: src=/usr/share/munin/plugins/{{ item.0 }}_
dest=/etc/munin/plugins/{{ item.0 }}_{{ item.1 }}
@@ -133,8 +155,32 @@
notify:
- Restart munin-node
+- name: Create directory /etc/systemd/system/munin-node.service.d
+ file: path=/etc/systemd/system/munin-node.service.d
+ state=directory
+ owner=root group=root
+ mode=0755
+
+- name: Copy munin-node.service override
+ copy: src=etc/systemd/system/munin-node.service.d/override.conf
+ dest=/etc/systemd/system/munin-node.service.d/override.conf
+ owner=root group=root
+ mode=0644
+ register: r8
+ notify:
+ - systemctl daemon-reload
+ - Restart munin-node
+
+# We use RuntimeDirectory in our overrride unit to avoid permission
+# issues caused by the restrictive Capability Bounding Set
+- name: Mask /usr/lib/tmpfiles.d/munin-common.conf
+ file: src=/dev/null
+ dest=/etc/tmpfiles.d/munin-common.conf
+ owner=root group=root
+ state=link
+
- name: Start munin-node
service: name=munin-node state=started
- when: not (r1.changed or r2.changed or r3.changed or r4.changed or r5.changed or r6.changed or r7.changed)
+ when: not (r1.changed or r2.changed or r3.changed or r4.changed or r5.changed or r6.changed or r7.changed or r8.changed)
- meta: flush_handlers
diff --git a/roles/common/tasks/ntp.yml b/roles/common/tasks/ntp.yml
index f9a01c8..2ff9e49 100644
--- a/roles/common/tasks/ntp.yml
+++ b/roles/common/tasks/ntp.yml
@@ -1,15 +1,33 @@
-- name: Install ntp
- apt: pkg=ntp
+- name: Remove ntp package
+ apt: pkg=ntp state={{ state }} purge=yes
+ vars:
+ state: "{{ ('NTP_master' in group_names) | ternary('present', 'absent') }}"
+
+- name: Install systemd-timesyncd package
+ apt: pkg=systemd-timesyncd state=present purge=yes
+ when: "'NTP_master' not in group_names"
+
+- name: Create /etc/systemd/timesyncd.conf.d
+ file: path=/etc/systemd/timesyncd.conf.d
+ state=directory
+ owner=root group=root
+ mode=0755
+ when: "'NTP_master' not in group_names"
- name: Configure ntp
- template: src=etc/ntp.conf.j2
- dest=/etc/ntp.conf
+ template: src=etc/{{ conf }}.j2
+ dest=/etc/{{ conf }}
owner=root group=root
mode=0644
+ vars:
+ conf: "{{ ('NTP_master' in group_names) | ternary('ntp.conf', 'systemd/timesyncd.conf.d/fripost.conf') }}"
+ service: "{{ ('NTP_master' in group_names) | ternary('ntp', 'systemd-timesyncd') }}"
notify:
- - Restart ntp
+ - Restart {{ service }}
- meta: flush_handlers
-- name: Start ntp
- service: name=ntp state=started
+- name: Start and enable ntp
+ service: name={{ service }}.service state=started enabled=true
+ vars:
+ service: "{{ ('NTP_master' in group_names) | ternary('ntp', 'systemd-timesyncd') }}"
diff --git a/roles/common/tasks/resolved.yml b/roles/common/tasks/resolved.yml
new file mode 100644
index 0000000..2834eaa
--- /dev/null
+++ b/roles/common/tasks/resolved.yml
@@ -0,0 +1,36 @@
+- name: Install systemd-resolved
+ apt: pkg={{ packages }}
+ vars:
+ packages:
+ - systemd-resolved
+ - libnss-resolve
+ - libnss-myhostname
+
+- name: Create directory /etc/systemd/resolved.conf.d
+ file: path=/etc/systemd/resolved.conf.d
+ state=directory
+ owner=root group=root
+ mode=0755
+
+- name: Configure systemd-resolved
+ template: src=etc/systemd/resolved.conf.d/local.conf.j2
+ dest=/etc/systemd/resolved.conf.d/local.conf
+ owner=root group=root
+ mode=0644
+ notify:
+ - Restart systemd-resolved
+
+- name: Start systemd-resolved
+ service: name=systemd-resolved.service enabled=true state=started
+
+- meta: flush_handlers
+
+- name: Remove resolvconf
+ apt: pkg=resolvconf state=absent purge=yes
+
+- name: Configure /etc/nsswitch.conf
+ lineinfile: "dest=/etc/nsswitch.conf create=no
+ regexp='^(hosts:\\s+).*'
+ line='\\1resolve [!UNAVAIL=return] files myhostname dns'
+ backrefs=true"
+ tags: nsswitch
diff --git a/roles/common/tasks/smart.yml b/roles/common/tasks/smart.yml
index 8d35d9f..68e507f 100644
--- a/roles/common/tasks/smart.yml
+++ b/roles/common/tasks/smart.yml
@@ -1,12 +1,5 @@
- name: Install smartmontools
apt: pkg=smartmontools
-- name: Auto-enable smartmontools
- lineinfile: dest=/etc/default/smartmontools
- regexp='^(\s*#)?\s*start_smartd='
- line='start_smartd=yes'
- owner=root group=root
- mode=0644
-
- name: Start smartd
service: name=smartmontools state=started
diff --git a/roles/common/tasks/stunnel.yml b/roles/common/tasks/stunnel.yml
index 7cb8823..1522f1f 100644
--- a/roles/common/tasks/stunnel.yml
+++ b/roles/common/tasks/stunnel.yml
@@ -1,14 +1,7 @@
- name: Install stunnel4
apt: pkg=stunnel4
-- name: Set 'ENABLED=0' in /etc/default/stunnel4
- lineinfile: dest=/etc/default/stunnel4
- regexp='^(\s*#)?\s*ENABLED='
- line='ENABLED=0'
- owner=root group=root
- mode=0644
-
-- name: Copy stunnel4 service file
+- name: Copy stunnel4 service files
copy: src=etc/systemd/system/{{ item }}
dest=/etc/systemd/system/{{ item }}
owner=root group=root
@@ -18,3 +11,6 @@
with_items:
- stunnel4.service
- stunnel4@.service
+
+- name: Disable stunnel4 service
+ service: name=stunnel4.service enabled=false
diff --git a/roles/common/tasks/sysctl.yml b/roles/common/tasks/sysctl.yml
index 3bf3b4f..08a1b13 100644
--- a/roles/common/tasks/sysctl.yml
+++ b/roles/common/tasks/sysctl.yml
@@ -11,10 +11,14 @@
- { name: 'net.ipv4.conf.default.rp_filter', value: 1 }
- { name: 'net.ipv4.conf.all.rp_filter', value: 1 }
- # Enable TCP/IP SYN cookies to avoid TCP SYN flood attacks. We
- # rate-limit not only the default ICMP types 3, 4, 11 and 12
+ # Disable SYN cookies and improve SYN backlog handling, see tcp(7) and
+ # https://levelup.gitconnected.com/linux-kernel-tuning-for-high-performance-networking-high-volume-incoming-connections-196e863d458a
+ - { name: 'net.ipv4.tcp_syncookies', value: 0 }
+ - { name: 'net.ipv4.tcp_synack_retries', value: 1 }
+ - { name: 'net.ipv4.tcp_max_syn_backlog', value: 32768 }
+
+ # We rate-limit not only the default ICMP types 3, 4, 11 and 12
# (0x1818), but also types 0 and 8. See icmp(7).
- - { name: 'net.ipv4.tcp_syncookies', value: 1 }
- { name: 'net.ipv4.icmp_ratemask', value: 6425 }
- { name: 'net.ipv4.icmp_ratelimit', value: 1000 }
diff --git a/roles/common/tasks/unbound.yml b/roles/common/tasks/unbound.yml
index b4554ac..dda6769 100644
--- a/roles/common/tasks/unbound.yml
+++ b/roles/common/tasks/unbound.yml
@@ -19,14 +19,3 @@
when: not r.changed
#- meta: flush_handlers
-
-- name: Use the local DNS server
- lineinfile: dest=/etc/resolv.conf create=yes
- regexp='^nameserver\s+127\.0\.0\.1\s*$'
- line='nameserver 127.0.0.1'
- insertbefore='^\s*#*?nameserver\s'
- firstmatch=yes
- tags:
- - resolver
- notify:
- - Restart Postfix
diff --git a/roles/common/templates/etc/apt/preferences.j2 b/roles/common/templates/etc/apt/preferences.j2
index 383037f..39b610e 100644
--- a/roles/common/templates/etc/apt/preferences.j2
+++ b/roles/common/templates/etc/apt/preferences.j2
@@ -1,10 +1,10 @@
# {{ ansible_managed }}
# Do NOT edit this file directly!
-# Install updates as soon as they're available
-Package: *
-Pin: release o=Debian, n={{ ansible_lsb.codename }}-updates
-Pin-Priority: 990
+## Install updates as soon as they're available
+#Package: *
+#Pin: release o=Debian, n={{ ansible_lsb.codename }}-updates
+#Pin-Priority: 990
{% if 'backports' in group_names -%}
# Automatically packages from backports (those manually installed)
@@ -20,7 +20,7 @@ Pin: release o=Debian
Pin-Priority: 200
{% endif %}
-{% if ansible_processor[1] is search('^(Genuine)?Intel.*') and not ansible_virtualization_role == 'guest' -%}
+{% if ansible_processor[1] is search('^(Genuine)?Intel.*') and not ansible_virtualization_role == 'guest' and ansible_lsb.major_release | int < 12 -%}
# Automatically upgrade the microcode (when manually installed)
Package: intel-microcode iucode-tool
Pin: release o=Debian
diff --git a/roles/common/templates/etc/apt/sources.list.j2 b/roles/common/templates/etc/apt/sources.list.j2
index 4ae1cb5..f524f2f 100644
--- a/roles/common/templates/etc/apt/sources.list.j2
+++ b/roles/common/templates/etc/apt/sources.list.j2
@@ -2,12 +2,12 @@
# Do NOT edit this file directly!
# vim: set filetype=debsources :
-deb http://deb.debian.org/debian {{ ansible_lsb.codename }} main{% if inventory_hostname_short in non_free_packages.keys() or (ansible_processor[1] is search("^(Genuine)?Intel.*") and not ansible_virtualization_role == 'guest') %} contrib non-free{% endif %}
+deb https://deb.debian.org/debian {{ ansible_lsb.codename }} main{% if inventory_hostname_short in non_free_packages.keys() or (ansible_processor[1] is search("^(Genuine)?Intel.*") and not ansible_virtualization_role == 'guest' and ansible_lsb.major_release | int < 12) %} contrib non-free{% endif %}{% if ansible_lsb.major_release | int >= 12 %} non-free-firmware{% endif %}
-deb http://deb.debian.org/debian-security {{ ansible_lsb.codename }}/updates main{% if inventory_hostname_short in non_free_packages.keys() or (ansible_processor[1] is search("^(Genuine)?Intel.*") and not ansible_virtualization_role == 'guest') %} contrib non-free{% endif %}
+deb https://deb.debian.org/debian-security {{ ansible_lsb.codename }}{% if ansible_lsb.major_release | int < 11 %}/updates{% else %}-security{% endif %} main{% if inventory_hostname_short in non_free_packages.keys() or (ansible_processor[1] is search("^(Genuine)?Intel.*") and not ansible_virtualization_role == 'guest' and ansible_lsb.major_release | int < 12) %} contrib non-free{% endif %}{% if ansible_lsb.major_release | int >= 12 %} non-free-firmware{% endif %}
-deb http://deb.debian.org/debian {{ ansible_lsb.codename }}-updates main
+deb https://deb.debian.org/debian {{ ansible_lsb.codename }}-updates main{% if ansible_lsb.major_release | int >= 12 %} non-free-firmware{% endif %}
{% if 'backports' in group_names -%}
-deb http://deb.debian.org/debian {{ ansible_lsb.codename }}-backports main
+deb https://deb.debian.org/debian {{ ansible_lsb.codename }}-backports main
{% endif %}
diff --git a/roles/common/templates/etc/bacula/bacula-fd.conf.j2 b/roles/common/templates/etc/bacula/bacula-fd.conf.j2
index e06911f..d0af395 100644
--- a/roles/common/templates/etc/bacula/bacula-fd.conf.j2
+++ b/roles/common/templates/etc/bacula/bacula-fd.conf.j2
@@ -1,7 +1,15 @@
#
# Default Bacula File Daemon Configuration file
#
-# For Bacula release 5.2.6 (21 February 2012) -- debian jessie/sid
+# For Bacula release 9.6.7 (10 December 2020) -- debian bullseye/sid
+#
+# There is not much to change here except perhaps the
+# File daemon Name to
+#
+#
+# Copyright (C) 2000-2020 Kern Sibbald
+# License: BSD 2-Clause; see file LICENSE-FOSS
+#
#
# List Directors who are permitted to contact this File daemon
@@ -25,7 +33,7 @@ Messages {
FileDaemon { # define myself
Name = {{ inventory_hostname_short }}-fd
Working Directory = /var/lib/bacula
- Pid Directory = /var/run/bacula
+ Pid Directory = /run/bacula
Maximum Concurrent Jobs = 20
FDAddress = {{ ipsec[inventory_hostname_short] }}
FDPort = 9102
diff --git a/roles/common/templates/etc/clamav/freshclam.conf.j2 b/roles/common/templates/etc/clamav/freshclam.conf.j2
index 06cebd1..650a2b3 100644
--- a/roles/common/templates/etc/clamav/freshclam.conf.j2
+++ b/roles/common/templates/etc/clamav/freshclam.conf.j2
@@ -19,7 +19,6 @@ ReceiveTimeout 30
TestDatabases yes
ScriptedUpdates yes
CompressLocalDatabase no
-SafeBrowsing false
Bytecode true
NotifyClamd /etc/clamav/clamd.conf
# Check for new database 24 times a day
diff --git a/roles/common/templates/etc/fail2ban/jail.local.j2 b/roles/common/templates/etc/fail2ban/jail.local.j2
index 29b004c..2759611 100644
--- a/roles/common/templates/etc/fail2ban/jail.local.j2
+++ b/roles/common/templates/etc/fail2ban/jail.local.j2
@@ -5,7 +5,7 @@
# Destination email address used solely for the interpolations in
# jail.{conf,local} configuration files.
-destemail = admin@fripost.org
+destemail = root@fripost.org
# "ignoreip" can be a list of IP addresses, CIDR masks or DNS hosts. Fail2ban
# will not ban a host which matches an address in this list. Several addresses
@@ -13,7 +13,9 @@ destemail = admin@fripost.org
ignoreip = 127.0.0.0/8, ::1, {{ ipsec_subnet }}
banaction = nftables-allports
-logpath = /var/log/fail2ban/fail2ban.log
+
+# must match nftables.conf's blackholes timeouts
+bantime = 10m
#
# JAILS
@@ -33,7 +35,7 @@ enabled = {{ 'MSA' in group_names }}
[roundcube-auth]
enabled = {{ 'webmail' in group_names }}
-# XXX Bullseye: logpath = /var/log/roundcube/errors.log
+logpath = /var/log/roundcube/errors.log
[nextcloud]
enabled = {{ 'nextcloud' in group_names }}
diff --git a/roles/common/templates/etc/ipsec.conf.j2 b/roles/common/templates/etc/ipsec.conf.j2
index 6b3840f..eaa9a08 100644
--- a/roles/common/templates/etc/ipsec.conf.j2
+++ b/roles/common/templates/etc/ipsec.conf.j2
@@ -17,7 +17,7 @@ conn %default
{% endif %}
leftauth = pubkey
left = %defaultroute
- leftsubnet = {{ ipsec[inventory_hostname_short] | ipv4 }}/32
+ leftsubnet = {{ ipsec[inventory_hostname_short] | ansible.utils.ipv4 }}/32
leftid = {{ inventory_hostname }}
leftsigkey = {{ inventory_hostname_short }}.pem
leftfirewall = no
@@ -36,7 +36,8 @@ conn {{ hostvars[host].inventory_hostname_short }}
rightallowany = yes
{% endif %}
rightsigkey = {{ hostvars[host].inventory_hostname_short }}.pem
- rightsubnet = {{ ipsec[ hostvars[host].inventory_hostname_short ] | ipv4 }}/32
+ rightsubnet = {{ ipsec[ hostvars[host].inventory_hostname_short ] | ansible.utils.ipv4 }}/32
+ reqid = {{ ipsec[ hostvars[host].inventory_hostname_short ].replace(":",".").split(".")[-1] }}
{% if 'NATed' not in group_names and 'NATed' in hostvars[host].group_names %}
mobike = yes
{% endif %}
diff --git a/roles/common/templates/etc/munin/munin-node.conf.j2 b/roles/common/templates/etc/munin/munin-node.conf.j2
index 1563526..1aba053 100644
--- a/roles/common/templates/etc/munin/munin-node.conf.j2
+++ b/roles/common/templates/etc/munin/munin-node.conf.j2
@@ -4,7 +4,7 @@
log_level 4
log_file /var/log/munin/munin-node.log
-pid_file /var/run/munin/munin-node.pid
+pid_file /run/munin/munin-node.pid
background 1
setsid 1
@@ -42,7 +42,7 @@ host_name {{ inventory_hostname_short }}
# may repeat the allow line as many times as you'd like
{% for host in groups['munin_master'] %}
-allow ^{{ ipsec[ hostvars[host].inventory_hostname_short ] | ipv4 | replace(".","\.") }}$
+allow ^{{ ipsec[ hostvars[host].inventory_hostname_short ] | ansible.utils.ipv4 | replace(".","\.") }}$
{% endfor %}
# Which address to bind to;
diff --git a/roles/common/templates/etc/munin/plugin-conf.d/munin-node.j2 b/roles/common/templates/etc/munin/plugin-conf.d/munin-node.j2
index 2d434bc..ec471eb 100644
--- a/roles/common/templates/etc/munin/plugin-conf.d/munin-node.j2
+++ b/roles/common/templates/etc/munin/plugin-conf.d/munin-node.j2
@@ -73,7 +73,7 @@ user root
[mysql*]
user root
env.mysqlopts --defaults-file=/etc/mysql/debian.cnf
-env.mysqluser debian-sys-maint
+env.mysqluser root
env.mysqlconnection DBI:mysql:mysql;mysql_read_default_file=/etc/mysql/debian.cnf
[postfix_mailqueue_*]
diff --git a/roles/common/templates/etc/nftables.conf.j2 b/roles/common/templates/etc/nftables.conf.j2
index 1e1fde2..f603ed9 100755
--- a/roles/common/templates/etc/nftables.conf.j2
+++ b/roles/common/templates/etc/nftables.conf.j2
@@ -5,7 +5,7 @@ define in-tcp-ports = {
{% if 'MX' in group_names %}
, 25 # SMTP
{% endif %}
-{% if 'LDAP-provider' in group_names %}
+{% if 'LDAP_provider' in group_names %}
, 636 # ldaps
{% endif %}
{% if 'IMAP' in group_names %}
@@ -29,7 +29,7 @@ define out-tcp-ports = {
{% if 'out' in group_names or 'MSA' in group_names %}
, 25 # SMTP
{% endif %}
-{% if 'LDAP-provider' in group_names %}
+{% if 'LDAP_provider' in group_names %}
, 11371 # OpenPGP HTTP Keyserver
, 43 # whois
{% elif 'MX' in group_names or 'lists' in group_names or 'nextcloud' in group_names %}
@@ -45,8 +45,107 @@ define out-tcp-ports = {
flush ruleset
+table netdev filter {
+{% for if in ansible_interfaces %}
+{% if if != "lo" and ansible_facts[if].active %}
+{% set addr = (ansible_facts[if].ipv4 | default({'address': '0.0.0.0'})).address %}
+ chain INGRESS-{{ if }} {
+ type filter hook ingress device {{ if }} priority -499
+ policy accept
+
+ # IPsec traffic (refined later in the filter rule)
+ ip saddr {{ ipsec_subnet }} ip daddr {{ ipsec[inventory_hostname_short] }} meta secpath exists accept
+
+ # rate-limiting is done directly by the kernel (net.ipv4.icmp_{ratelimit,ratemask} runtime options)
+ icmp type { echo-reply, echo-request, destination-unreachable, time-exceeded } counter accept
+ icmpv6 type { echo-reply, echo-request, destination-unreachable,
+ packet-too-big, time-exceeded, parameter-problem } counter accept
+
+ # accept neighbour discovery for autoconfiguration, RFC 4890 sec. 4.4.1
+ ip6 hoplimit 255 icmpv6 type { 133,134,135,136,141,142 } counter accept
+
+ # accept link-local multicast receiver notification messages
+ ip6 saddr fe80::/10 ip6 daddr ff02::/16 ip6 hoplimit 1 icmpv6 type { 130,131,132,143 } counter accept
+
+ # drop all remaining ICMP/ICMPv6 traffic
+ meta l4proto { icmp, icmpv6 } counter drop
+
+ # bogon filter (cf. RFC 6890 for non-global ip addresses)
+ define bogon = {
+ 0.0.0.0/8 # this host, on this network (RFC 1122 sec. 3.2.1.3)
+{% if not addr | ansible.utils.ipaddr('10.0.0.0/8') %}
+ , 10.0.0.0/8 # private-use (RFC 1918)
+{% endif %}
+ , 100.64.0.0/10 # shared address space (RFC 6598)
+ , 127.0.0.0/8 # loopback (RFC 1122, sec. 3.2.1.3)
+ , 169.254.0.0/16 # link local (RFC 3927)
+ , 172.16.0.0/12 # private-use (RFC 1918)
+ , 192.0.0.0/24 # IETF protocol assignments (RFC 6890 sec. 2.1)
+ , 192.0.2.0/24 # documentation (RFC 5737)
+{% if not addr | ansible.utils.ipaddr('192.168.0.0/16') %}
+ , 192.168.0.0/16 # private-use (RFC 1918)
+{% endif %}
+ , 198.18.0.0/15 # benchmarking (RFC 2544)
+ , 198.51.100.0/24 # documentation (RFC 5737)
+ , 203.0.113.0/24 # documentation (RFC 5737)
+ , 224.0.0.0/3 # multicast - class D 224.0.0.0/4 + class E 240.0.0.0/4 (RFC 1112 sec. 4)
+ , 255.255.255.255/32 # limited broadcast (RFC 0919 sec. 7)
+ }
+
+ ip saddr $bogon counter drop
+ ip daddr $bogon counter drop
+
+ # See also https://www.team-cymru.org/Services/Bogons/fullbogons-ipv6.txt
+ define bogon6 = {
+ ::1/128 # loopback address (RFC 4291)
+ , ::/128 # unspecified (RFC 4291)
+ , ::ffff:0:0/96 # IPv4-mapped address (RFC 4291)
+ , 100::/64 # discard-only address block (RFC 6666)
+ , 2001::/23 # IETF protocol assignments (RFC 2928)
+ , 2001::/32 # TEREDO (RFC 4380)
+ , 2001:2::/48 # benchmarking (RFC 5180)
+ , 2001:db8::/32 # documentation (RFC 3849)
+ , 2001:10::/28 # ORCHID (RFC 4843)
+ , 2002::/16 # 6to4 (RFC 3056)
+ , fc00::/7 # unique-local (RFC 4193)
+ , fe80::/10 # linked-scoped unicast (RFC 4291)
+ }
+
+ ip6 saddr $bogon6 counter drop
+ ip6 saddr $bogon6 counter drop
+ }
+{% endif %}
+{% endfor %}
+}
+
+table inet raw {
+ chain PREROUTING-stateless {
+ # XXX can't add that to the ingress hook as that happens before IP defragmentation
+ # so we don't have the TCP header in later fragments (we don't want to drop IP
+ # fragments, see https://blog.cloudflare.com/ip-fragmentation-is-broken/ )
+ type filter hook prerouting priority -399 # > NF_IP_PRI_CONNTRACK_DEFRAG (-400)
+ policy accept
+
+ # stateless filter for bogus TCP packets
+ tcp flags & (fin|syn|rst|psh|ack|urg) == 0x0 counter drop # null packet
+ tcp flags & (fin|psh|urg) == fin|psh|urg counter drop # XMAS packet
+ tcp flags & (syn|rst) == syn|rst counter drop
+ tcp flags & (fin|rst) == fin|rst counter drop
+ tcp flags & (fin|syn) == fin|syn counter drop
+ tcp flags & (fin|psh|ack) == fin|psh counter drop
+ }
+
+ chain PREROUTING {
+ type filter hook prerouting priority -199 # > NF_IP_PRI_CONNTRACK (-200)
+ policy accept
+
+ # stateful filter
+ ct state invalid counter drop
+ }
+}
+
table inet filter {
- # blackholes
+ # blackholes (timeout must match /etc/fail2ban/jail.local)
set fail2ban { type ipv4_addr; timeout 10m; }
set fail2ban6 { type ipv6_addr; timeout 10m; }
@@ -56,26 +155,15 @@ table inet filter {
iif lo accept
- # XXX Bullseye: this is a hack for the lack of reqid matches in
- # nftables: we mark the esp packet and accept after decapsulation
- # https://serverfault.com/questions/971735/how-to-match-reqid-in-nftables
- # https://blog.fraggod.net/2016/09/25/nftables-re-injected-ipsec-matching-without-xt_policy.html
- define IPsec.mark = 0x220
- meta l4proto esp mark set mark | $IPsec.mark accept
- ip saddr 172.16.0.0/24 ip daddr 172.16.0.7 mark & $IPsec.mark == $IPsec.mark accept
-
- # rate-limiting is done directly by the kernel (net.ipv4.icmp_{ratelimit,ratemask} runtime options)
- icmp type { echo-reply, echo-request, destination-unreachable } counter accept
- icmpv6 type { echo-reply, echo-request, destination-unreachable,
- packet-too-big, time-exceeded, parameter-problem } counter accept
+ meta l4proto esp accept
+ ip daddr {{ ipsec[inventory_hostname_short] }} jump ipsec-in
- # accept neighbour discovery for autoconfiguration, RFC 4890 sec. 4.4.1
- icmpv6 type { 133,134,135,136,141,142 } ip6 hoplimit 255 counter accept
+ # incoming ICMP/ICMPv6 traffic was filtered in the ingress chain already
+ meta l4proto { icmp, icmpv6 } counter accept
- jump martian
- jump invalid
+ # NTP (ntpd uses sport 123 but systemd-timesyncd does not)
+ udp sport 123 ct state related,established accept
- udp sport 123 udp dport 123 ct state related,established accept
{% if groups.all | length > 1 %}
udp sport 500 udp dport 500 ct state new,related,established accept
{% if groups.NATed | length > 0 %}
@@ -86,11 +174,12 @@ table inet filter {
udp sport 53 ct state related,established accept
tcp sport 53 ct state related,established accept
{% if 'dhclient' in group_names %}
- udp sport 67 ct state related,established accept
+ ip version 4 udp sport 67 udp dport 68 ct state related,established accept
+ ip6 version 6 udp sport 547 udp dport 546 ct state related,established accept
{% endif %}
- meta l4proto tcp ip saddr @fail2ban counter drop
- meta l4proto tcp ip6 saddr @fail2ban6 counter drop
+ ip saddr @fail2ban counter drop
+ ip6 saddr @fail2ban6 counter drop
tcp dport $in-tcp-ports ct state related,established accept
tcp dport $in-tcp-ports ct state new counter accept
@@ -103,25 +192,26 @@ table inet filter {
oif lo accept
- # XXX Bullseye: unlike for input we can't use marks here,
- # because by the time we see a packet to 172.16.0.0/24 we don't
- # know if it'll be encapsulated
meta l4proto esp accept
- ip saddr 172.16.0.7 ip daddr 172.16.0.0/24 accept
+ ip saddr {{ ipsec[inventory_hostname_short] }} jump ipsec-out
- meta l4proto { icmp, icmpv6 } accept
+ meta l4proto { icmp, icmpv6 } counter accept
- jump martian
- jump invalid
+ # NTP (ntpd uses sport 123 but systemd-timesyncd does not)
+ udp dport 123 ct state new,related,established accept
- udp sport 123 udp dport 123 ct state new,related,established accept
+{% if groups.all | length > 1 %}
udp sport 500 udp dport 500 ct state new,related,established accept
+{% if groups.NATed | length > 0 %}
udp sport 4500 udp dport 4500 ct state new,related,established accept
+{% endif %}
+{% endif %}
udp dport 53 ct state new,related,established accept
tcp dport 53 ct state new,related,established accept
{% if 'dhclient' in group_names %}
- udp dport 67 ct state new,related,established accept
+ ip version 4 udp sport 68 udp dport 67 ct state new,related,established accept
+ ip6 version 6 udp sport 546 udp dport 547 ct state new,related,established accept
{% endif %}
tcp sport $in-tcp-ports ct state related,established accept
@@ -133,61 +223,16 @@ table inet filter {
counter reject
}
- chain martian {
- # bogon filter (cf. RFC 6890 for non-global ip addresses)
- define invalid-ip = {
- 0.0.0.0/8 # this host, on this network (RFC 1122 sec. 3.2.1.3)
-{% if not ansible_default_ipv4.address | ipaddr('10.0.0.0/8') %}
- , 10.0.0.0/8 # private-use (RFC 1918)
-{% endif %}
- , 100.64.0.0/10 # shared address space (RFC 6598)
- , 127.0.0.0/8 # loopback (RFC 1122, sec. 3.2.1.3)
- , 169.254.0.0/16 # link local (RFC 3927)
-{% if not ansible_default_ipv4.address | ipaddr('172.16.0.0/12') %}
- , 172.16.0.0/12 # private-use (RFC 1918)
-{% endif %}
- , 192.0.0.0/24 # IETF protocol assignments (RFC 6890 sec. 2.1)
- , 192.0.2.0/24 # documentation (RFC 5737)
-{% if not ansible_default_ipv4.address | ipaddr('192.168.0.0/16') %}
- , 192.168.0.0/16 # private-use (RFC 1918)
-{% endif %}
- , 198.18.0.0/15 # benchmarking (RFC 2544)
- , 198.51.100.0/24 # documentation (RFC 5737)
- , 203.0.113.0/24 # documentation (RFC 5737)
- , 240.0.0.0/4 # reserved (RFC 1112, sec. 4)
- , 255.255.255.255/32 # limited broadcast (RFC 0919, section 7)
- }
-
- define invalid-ip6 = {
- ::1/128 # loopback address (RFC 4291)
- , ::/128 # unspecified (RFC 4291)
- , ::ffff:0:0/96 # IPv4-mapped address (RFC 4291)
- , 100::/64 # discard-only address block (RFC 6666)
- , 2001::/23 # IETF protocol assignments (RFC 2928)
- , 2001::/32 # TEREDO (RFC 4380)
- , 2001:2::/48 # benchmarking (RFC 5180)
- , 2001:db8::/32 # documentation (RFC 3849)
- , 2001:10::/28 # ORCHID (RFC 4843)
- , 2002::/16 # 6to4 (RFC 3056)
- , fc00::/7 # unique-local (RFC 4193)
- , fe80::/10 # linked-scoped unicast (RFC 4291)
- }
-
- ip saddr $invalid-ip counter drop
- ip daddr $invalid-ip counter drop
-
- ip6 saddr $invalid-ip6 counter drop
- ip6 daddr $invalid-ip6 counter drop
+ chain ipsec-in {
+{% for h in ipsec.keys() | difference([inventory_hostname_short]) | sort %}
+ ip saddr {{ ipsec[h] }} ipsec in reqid {{ ipsec[h].replace(":",".").split(".")[-1] }} counter accept
+{% endfor %}
+ log prefix "ipsec-in " drop
}
-
- chain invalid {
- ct state invalid counter reject
-
- # drop bogus TCP packets
- tcp flags & (fin|syn|rst|psh|ack|urg) == 0x0 counter drop # null packets
- tcp flags != syn ct state new counter drop # SYN-flood attacks
- tcp flags & (fin|syn|rst|psh|ack|urg) == fin|psh|urg counter drop # XMAS packets
- tcp flags & (fin|syn) == fin|syn counter drop # bogus
- tcp flags & (syn|rst) == syn|rst counter drop # bogus
+ chain ipsec-out {
+{% for h in ipsec.keys() | difference([inventory_hostname_short]) | sort %}
+ ip daddr {{ ipsec[h] }} ipsec out reqid {{ ipsec[h].replace(":",".").split(".")[-1] }} counter accept
+{% endfor %}
+ log prefix "ipsec-out " drop
}
}
diff --git a/roles/common/templates/etc/ntp.conf.j2 b/roles/common/templates/etc/ntp.conf.j2
index 18c03cf..b76f0dd 100644
--- a/roles/common/templates/etc/ntp.conf.j2
+++ b/roles/common/templates/etc/ntp.conf.j2
@@ -2,6 +2,8 @@
driftfile /var/lib/ntp/ntp.drift
+# Leap seconds definition provided by tzdata
+leapfile /usr/share/zoneinfo/leap-seconds.list
# Enable this if you want statistics to be logged.
#statsdir /var/log/ntpstats/
@@ -13,7 +15,6 @@ filegen clockstats file clockstats type day enable
# You do need to talk to an NTP server or two (or three).
-{% if 'NTP_master' in group_names %}
# Use Stratum One Time Servers:
# http://support.ntp.org/bin/view/Servers/StratumOneTimeServers
server sth1.ntp.se iburst
@@ -22,17 +23,6 @@ server gbg1.ntp.se iburst
server gbg2.ntp.se iburst
server ntp1.sp.se iburst
server ntp2.sp.se iburst
-{% else %}
-# Sychronize to our (stratum 2) NTP server, to ensure our network has a
-# consistent time.
-{% for host in groups['NTP_master'] | sort %}
-server {{ ipsec[ hostvars[host].inventory_hostname_short ] }} prefer iburst
-{% endfor %}
-pool 0.{{ geoip | default('debian') }}.pool.ntp.org iburst
-pool 1.{{ geoip | default('debian') }}.pool.ntp.org iburst
-pool 2.{{ geoip | default('debian') }}.pool.ntp.org iburst
-pool 3.{{ geoip | default('debian') }}.pool.ntp.org iburst
-{% endif %}
# Access control configuration; see /usr/share/doc/ntp-doc/html/accopt.html for
diff --git a/roles/common/templates/etc/postfix/main.cf.j2 b/roles/common/templates/etc/postfix/main.cf.j2
index b369d43..5ac7920 100644
--- a/roles/common/templates/etc/postfix/main.cf.j2
+++ b/roles/common/templates/etc/postfix/main.cf.j2
@@ -31,7 +31,7 @@ virtual_alias_maps = lmdb:/etc/aliases
alias_database = $virtual_alias_maps
# Forward everything to our internal outgoing proxy
-relayhost = [{{ postfix_instance.out.addr | ipaddr }}]:{{ postfix_instance.out.port }}
+relayhost = [{{ postfix_instance.out.addr | ansible.utils.ipaddr }}]:{{ postfix_instance.out.port }}
relay_domains =
smtp_tls_security_level = none
diff --git a/roles/common/templates/etc/postfix/master.cf.j2 b/roles/common/templates/etc/postfix/master.cf.j2
index a9c73f7..3954085 100644
--- a/roles/common/templates/etc/postfix/master.cf.j2
+++ b/roles/common/templates/etc/postfix/master.cf.j2
@@ -19,10 +19,8 @@ tlsproxy unix - - y - 0 tlsproxy
dnsblog unix - - y - 0 dnsblog
{% elif inst == 'MSA' %}
submission inet n - y - - smtpd
- -o tls_high_cipherlist=EECDH+AESGCM:!MEDIUM:!LOW:!EXP:!aNULL:!eNULL
submissions inet n - y - - smtpd
-o smtpd_tls_wrappermode=yes
- -o tls_high_cipherlist=EECDH+AESGCM:!MEDIUM:!LOW:!EXP:!aNULL:!eNULL
{% if groups.webmail | difference([inventory_hostname]) | length > 0 %}
[{{ postfix_instance.MSA.addr }}]:{{ postfix_instance.MSA.port }} inet n - y - - smtpd
-o broken_sasl_auth_clients=no
@@ -59,6 +57,8 @@ smtp_verify unix - - y - - smtp
-o smtp_tls_protocols=!SSLv2,!SSLv3
-o smtp_tls_note_starttls_offer=yes
-o smtp_tls_session_cache_database=lmdb:$data_directory/smtp_tls_session_cache
+ -o smtp_tls_fingerprint_digest=sha256
+ -o smtp_tls_policy_maps=lmdb:$config_directory/smtp_tls_policy
{% endif %}
relay unix - - y - - smtp
showq unix n - y - - showq
@@ -85,7 +85,7 @@ sympa unix - n n - - pipe
{% if inst is defined and inst == 'out' %}
# Client part (lmtp) - amavis
-amavisfeed unix - - n - 5 lmtp
+amavisfeed unix - - y - 5 lmtp
-o lmtp_destination_recipient_limit=1000
-o lmtp_send_xforward_command=yes
-o lmtp_data_done_timeout=1200s
diff --git a/roles/common/templates/etc/systemd/resolved.conf.d/local.conf.j2 b/roles/common/templates/etc/systemd/resolved.conf.d/local.conf.j2
new file mode 100644
index 0000000..044170a
--- /dev/null
+++ b/roles/common/templates/etc/systemd/resolved.conf.d/local.conf.j2
@@ -0,0 +1,11 @@
+[Resolve]
+LLMNR=no
+{% if ansible_processor[1] is search('^(Genuine)?Intel.*') and not ansible_virtualization_role == 'guest' %}
+DNS=127.0.0.1
+# Quad9
+FallbackDNS=9.9.9.9#dns.quad9.net 149.112.112.112#dns.quad9.net 2620:fe::fe#dns.quad9.net 2620:fe::9#dns.quad9.net
+{% else %}
+# Quad9
+DNS=9.9.9.9#dns.quad9.net 149.112.112.112#dns.quad9.net 2620:fe::fe#dns.quad9.net 2620:fe::9#dns.quad9.net
+{% endif %}
+Domains=fripost.org
diff --git a/roles/common/templates/etc/systemd/timesyncd.conf.d/fripost.conf.j2 b/roles/common/templates/etc/systemd/timesyncd.conf.d/fripost.conf.j2
new file mode 100644
index 0000000..f578cd9
--- /dev/null
+++ b/roles/common/templates/etc/systemd/timesyncd.conf.d/fripost.conf.j2
@@ -0,0 +1,9 @@
+[Time]
+# Sychronize to our (stratum 2) NTP server, to ensure our network has a
+# consistent time.
+{%- set ntp = [] -%}
+{%- for host in groups['NTP_master'] -%}
+{%- set _ = ntp.append(ipsec[ hostvars[host].inventory_hostname_short ]) -%}
+{%- endfor %}
+
+NTP={{ ntp | join(' ') }}
diff --git a/roles/common/templates/etc/unbound/unbound.conf.j2 b/roles/common/templates/etc/unbound/unbound.conf.j2
index 64f32bf..e75e66f 100644
--- a/roles/common/templates/etc/unbound/unbound.conf.j2
+++ b/roles/common/templates/etc/unbound/unbound.conf.j2
@@ -29,4 +29,4 @@ server:
#
# The following line includes additional configuration files from the
# /etc/unbound/unbound.conf.d directory.
-include: "/etc/unbound/unbound.conf.d/*.conf"
+include-toplevel: "/etc/unbound/unbound.conf.d/*.conf"
diff --git a/roles/git/files/etc/nginx/sites-available/git b/roles/git/files/etc/nginx/sites-available/git
index 73ac1e6..9e9d16e 100644
--- a/roles/git/files/etc/nginx/sites-available/git
+++ b/roles/git/files/etc/nginx/sites-available/git
@@ -4,7 +4,7 @@ server {
server_name git.fripost.org;
- include snippets/acme-challenge.conf;
+ include /etc/lacme/nginx.conf;
access_log /var/log/nginx/git.access.log;
error_log /var/log/nginx/git.error.log info;
@@ -25,44 +25,54 @@ server {
error_log /var/log/nginx/git.error.log info;
include snippets/headers.conf;
+ add_header Content-Security-Policy
+ "default-src 'none'; img-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self'; frame-ancestors 'none'; form-action 'self'";
include snippets/ssl.conf;
ssl_certificate ssl/git.fripost.org.pem;
ssl_certificate_key ssl/git.fripost.org.key;
include snippets/git.fripost.org.hpkp-hdr;
- location ^~ /static/ {
- alias /usr/share/cgit/;
- expires 30d;
- }
+ gzip on;
+ gzip_vary on;
+ gzip_min_length 256;
+ gzip_types application/javascript application/json application/xml image/svg+xml image/x-icon text/css text/plain;
- # Bypass the CGI to return static files stored on disk. Try first repo with
- # a trailing '.git', then without.
- location ~* "^/((?U)[^/]+)(?:\.git)?/objects/(?:[0-9a-f]{2}/[0-9a-f]{38}|pack/pack-[0-9a-f]{40}\.(?:pack|idx))$" {
- root /var/lib/gitolite/repositories;
- try_files /$1.git/objects/$2 /$1/objects/$2 =404;
+ location ^~ /static/ {
expires 30d;
- gzip off;
- # TODO honor git-daemon-export-ok
+ alias /usr/share/cgit/;
}
# disallow push over HTTP/HTTPS
- location ~* "^/[^/]+/git-receive-pack$" { return 403; }
+ location ~ "^/.+/git-receive-pack$" { return 403; }
- location ~* "^/[^/]+/(?:HEAD|info/refs|objects/info/[^/]+|git-upload-pack)$" {
+ location ~ "^/.+/(?:info/refs|git-upload-pack)$" {
+ limit_except GET POST { deny all; }
+ fastcgi_buffering off;
gzip off;
- include uwsgi_params;
- uwsgi_modifier1 9;
- uwsgi_param GIT_PROJECT_ROOT /var/lib/gitolite/repositories;
- uwsgi_pass unix:/run/uwsgi/app/git-http-backend/socket;
+
+ fastcgi_param SCRIPT_FILENAME /usr/lib/git-core/git-http-backend;
+ fastcgi_param NO_BUFFERING "";
+
+ # cf. git-http-backend(1)
+ fastcgi_param GIT_PROJECT_ROOT /var/lib/gitolite/repositories;
+ fastcgi_param PATH_INFO $uri;
+ fastcgi_param CONTENT_TYPE $content_type;
+ fastcgi_param QUERY_STRING $query_string;
+ fastcgi_param REQUEST_METHOD $request_method;
+ fastcgi_pass unix:/run/git-http-backend.socket;
}
+ location = /robots.txt { root /usr/share/cgit; }
+ location = /favicon.ico { root /usr/share/cgit; }
# send all other URLs to cgit
location / {
- gzip off;
- include uwsgi_params;
- uwsgi_modifier1 9;
- uwsgi_pass unix:/run/uwsgi/app/cgit/socket;
+ fastcgi_param SCRIPT_FILENAME /usr/lib/cgit/cgit.cgi;
+ fastcgi_param PATH_INFO $uri;
+ fastcgi_param CONTENT_TYPE $content_type;
+ fastcgi_param QUERY_STRING $query_string;
+ fastcgi_param REQUEST_METHOD $request_method;
+ fastcgi_pass unix:/run/cgit.socket;
}
}
diff --git a/roles/git/files/etc/systemd/system/cgit.service b/roles/git/files/etc/systemd/system/cgit.service
new file mode 100644
index 0000000..08037ac
--- /dev/null
+++ b/roles/git/files/etc/systemd/system/cgit.service
@@ -0,0 +1,23 @@
+[Unit]
+Description=hyperfast web frontend for git repositories written in C
+Documentation=https://git.zx2c4.com/cgit/
+
+[Service]
+User=_cgit
+Group=nogroup
+SupplementaryGroups=gitolite
+ExecStart=/usr/sbin/fcgiwrap
+SyslogIdentifier=cgit
+#
+# Hardening
+NoNewPrivileges=yes
+PrivateDevices=yes
+ProtectHome=yes
+ProtectSystem=strict
+ProtectControlGroups=yes
+ProtectKernelModules=yes
+ProtectKernelTunables=yes
+ReadWriteDirectories=/var/cache/cgit
+
+[Install]
+WantedBy=multi-user.target
diff --git a/roles/git/files/etc/systemd/system/cgit.socket b/roles/git/files/etc/systemd/system/cgit.socket
new file mode 100644
index 0000000..bba4bef
--- /dev/null
+++ b/roles/git/files/etc/systemd/system/cgit.socket
@@ -0,0 +1,11 @@
+[Unit]
+Description=hyperfast web frontend for git repositories written in C
+Documentation=https://git.zx2c4.com/cgit/
+
+[Socket]
+ListenStream=%t/cgit.socket
+SocketUser=www-data
+SocketMode=0600
+
+[Install]
+WantedBy=sockets.target
diff --git a/roles/git/files/etc/systemd/system/git-http-backend.service b/roles/git/files/etc/systemd/system/git-http-backend.service
new file mode 100644
index 0000000..f973370
--- /dev/null
+++ b/roles/git/files/etc/systemd/system/git-http-backend.service
@@ -0,0 +1,21 @@
+[Unit]
+Description=Git HTTP backend
+Documentation=man:git-http-backend(1)
+
+[Service]
+DynamicUser=yes
+SupplementaryGroups=gitolite
+ExecStart=/usr/sbin/fcgiwrap
+SyslogIdentifier=git-http-backend
+#
+# Hardening
+NoNewPrivileges=yes
+PrivateDevices=yes
+ProtectHome=yes
+ProtectSystem=strict
+ProtectControlGroups=yes
+ProtectKernelModules=yes
+ProtectKernelTunables=yes
+
+[Install]
+WantedBy=multi-user.target
diff --git a/roles/git/files/etc/systemd/system/git-http-backend.socket b/roles/git/files/etc/systemd/system/git-http-backend.socket
new file mode 100644
index 0000000..c2820d4
--- /dev/null
+++ b/roles/git/files/etc/systemd/system/git-http-backend.socket
@@ -0,0 +1,11 @@
+[Unit]
+Description=Git HTTP backend
+Documentation=man:git-http-backend(1)
+
+[Socket]
+ListenStream=%t/git-http-backend.socket
+SocketUser=www-data
+SocketMode=0600
+
+[Install]
+WantedBy=sockets.target
diff --git a/roles/git/files/etc/uwsgi/apps-available/cgit.ini b/roles/git/files/etc/uwsgi/apps-available/cgit.ini
deleted file mode 100644
index 2fb5b25..0000000
--- a/roles/git/files/etc/uwsgi/apps-available/cgit.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[uwsgi]
-plugins = cgi
-procname-master = uwsgi %(deb-confname)
-cgi = /usr/lib/cgit/cgit.cgi
-uid = cgit
-gid = www-data
diff --git a/roles/git/files/etc/uwsgi/apps-available/git-http-backend.ini b/roles/git/files/etc/uwsgi/apps-available/git-http-backend.ini
deleted file mode 100644
index 326d6d6..0000000
--- a/roles/git/files/etc/uwsgi/apps-available/git-http-backend.ini
+++ /dev/null
@@ -1,8 +0,0 @@
-[uwsgi]
-plugins = cgi
-procname-master = uwsgi %(deb-confname)
-cgi = /usr/lib/git-core/git-http-backend
-
-# XXX regression in git-http-backend
-# https://www.mail-archive.com/git@vger.kernel.org/msg119603.html
-cgi-close-stdin-on-eof = true
diff --git a/roles/git/handlers/main.yml b/roles/git/handlers/main.yml
index d52c9cc..6212d91 100644
--- a/roles/git/handlers/main.yml
+++ b/roles/git/handlers/main.yml
@@ -2,8 +2,17 @@
- name: systemctl daemon-reload
command: /bin/systemctl daemon-reload
-- name: Restart uWSGI
- service: name=uwsgi state=restarted
+- name: Stop cgit
+ service: name=cgit.service state=stopped
+
+- name: Restart cgit
+ service: name=cgit.socket state=restarted
+
+- name: Stop git-http-backend
+ service: name=git-http-backend.service state=stopped
+
+- name: Restart git-http-backend
+ service: name=git-http-backend.socket state=restarted
- name: Restart Nginx
service: name=nginx state=restarted
diff --git a/roles/git/tasks/cgit.yml b/roles/git/tasks/cgit.yml
index 160ede6..120f204 100644
--- a/roles/git/tasks/cgit.yml
+++ b/roles/git/tasks/cgit.yml
@@ -4,79 +4,99 @@
packages:
- cgit
- highlight
- - uwsgi
+ - fcgiwrap
+
+- name: Stop and disable fcgiwrap socket
+ service: name=fcgiwrap.socket state=stopped enabled=false
+
+- name: Stop fcgiwrap service
+ service: name=fcgiwrap.service state=stopped
- name: Configure cgit
copy: src=etc/cgitrc
dest=/etc/cgitrc
owner=root group=root
mode=0644
- register: r1
notify:
- - Restart uWSGI
+ - Stop cgit
- name: Copy /usr/lib/cgit/filters/syntax-highlighting2.sh
copy: src=usr/lib/cgit/filters/syntax-highlighting2.sh
dest=/usr/lib/cgit/filters/syntax-highlighting2.sh
owner=root group=root
mode=0755
- register: r2
notify:
- - Restart uWSGI
+ - Stop cgit
-- name: Create a user 'cgit'
- user: name=cgit system=yes
- home=/var/www
+- name: Create '_cgit' user
+ user: name=_cgit system=yes
+ group=nogroup
+ home=/nonexistent
shell=/usr/sbin/nologin
password=!
state=present
- register: r3
notify:
- - Restart uWSGI
+ - Stop cgit
+# Make it sticky: `dpkg-statoverride --add _cgit nogroup 0700 /var/cache/cgit`
- name: Create cache directory /var/cache/cgit
file: path=/var/cache/cgit
state=directory
- owner=cgit group=cgit
+ owner=_cgit group=nogroup
mode=0700
-- name: Create /etc/uwsgi/apps-available/{cgit,git-http-backend}.ini
- copy: src=etc/uwsgi/apps-available/{{ item }}.ini
- dest=/etc/uwsgi/apps-available/{{ item }}.ini
+- name: Copy cgit service unit
+ copy: src=etc/systemd/system/cgit.service
+ dest=/etc/systemd/system/cgit.service
owner=root group=root
mode=0644
- register: r4
- with_items:
- - cgit
- - git-http-backend
notify:
- - Restart uWSGI
+ - systemctl daemon-reload
+ - Stop cgit
-- name: Create /etc/uwsgi/apps-enabled/{cgit,git-http-backend}.ini
- file: src=../apps-available/{{ item }}.ini
- dest=/etc/uwsgi/apps-enabled/{{ item }}.ini
+- name: Copy cgit socket unit
+ copy: src=etc/systemd/system/cgit.socket
+ dest=/etc/systemd/system/cgit.socket
owner=root group=root
- state=link force=yes
- register: r5
- with_items:
- - cgit
- - git-http-backend
+ mode=0644
notify:
- - Restart uWSGI
+ - systemctl daemon-reload
+ - Restart cgit
-- name: Start uWSGI
- service: name=nginx state=started
- when: not (r1.changed or r2.changed or r3.changed or r4.changed or r5.changed)
+- name: Disable cgit service
+ service: name=cgit.service enabled=false
+
+- name: Start cgit socket
+ service: name=cgit.socket state=started enabled=true
- meta: flush_handlers
-- name: Add 'cgit' & 'www-data' to the group 'gitolite'
- user: name={{ item }} groups=gitolite append=yes
- with_items:
- # for the cgit interface
- - cgit
- # for pulls over HTTP/HTTPS
- - www-data
+
+- name: Copy git-http-backend service unit
+ copy: src=etc/systemd/system/git-http-backend.service
+ dest=/etc/systemd/system/git-http-backend.service
+ owner=root group=root
+ mode=0644
+ notify:
+ - systemctl daemon-reload
+ - Stop git-http-backend
+
+- name: Copy git-http-backend socket unit
+ copy: src=etc/systemd/system/git-http-backend.socket
+ dest=/etc/systemd/system/git-http-backend.socket
+ owner=root group=root
+ mode=0644
+ notify:
+ - systemctl daemon-reload
+ - Restart git-http-backend
+
+- name: Disable git-http-backend service
+ service: name=git-http-backend.service enabled=false
+
+- name: Start git-http-backend socket
+ service: name=git-http-backend.socket state=started enabled=true
+
+- meta: flush_handlers
- name: Copy /etc/nginx/sites-available/git
diff --git a/roles/git/tasks/gitolite.yml b/roles/git/tasks/gitolite.yml
index 38000a7..e7d1fe3 100644
--- a/roles/git/tasks/gitolite.yml
+++ b/roles/git/tasks/gitolite.yml
@@ -31,6 +31,6 @@
owner=root group=root
mode=0644
with_items:
- # See /usr/share/doc/gitolite3/README.txt.gz
+ # See /usr/share/doc/gitolite3/README.markdown.gz
- { var: UMASK, value: "0027" }
- { var: GIT_CONFIG_KEYS, value: "'gitweb\\..* gc\\..* hook\\..*'" }
diff --git a/roles/lacme/files/etc/lacme/lacme.conf b/roles/lacme/files/etc/lacme/lacme.conf
index 5aa1252..28633b6 100644
--- a/roles/lacme/files/etc/lacme/lacme.conf
+++ b/roles/lacme/files/etc/lacme/lacme.conf
@@ -1,86 +1,123 @@
-# For certificate issuance (new-cert command), specify the certificate
-# configuration file to use
+# For certificate issuance (newOrder command), specify a space-separated
+# certificate configuration files or directories to use
#
-#config-certs = config/lacme-certs.conf
+#config-certs = lacme-certs.conf lacme-certs.conf.d/
+
[client]
-# The value of "socket" specifies the lacme-accountd(1) UNIX-domain
-# socket to connect to for signature requests from the ACME client.
-# lacme(1) aborts if the socket is readable or writable by other users,
-# or if its parent directory is writable by other users.
-# Default: "$XDG_RUNTIME_DIR/S.lacme" if the XDG_RUNTIME_DIR environment
-# variable is set.
+
+# The value of "socket" specifies the path to the lacme-accountd(1)
+# UNIX-domain socket to connect to for signature requests from the ACME
+# client. lacme(8) aborts if the socket is readable or writable by
+# other users, or if its parent directory is writable by other users.
+# This setting is ignored when lacme-accountd(1) is spawned by lacme(8),
+# since the two processes communicate through a socket pair. See the
+# "accountd" section below for details.
#
-#socket = /run/user/1000/S.lacme
+#socket = %t/S.lacme
# username to drop privileges to (setting both effective and real uid).
-# Preserve root privileges if the value is empty (not recommended).
-# Default: "nobody".
+# Skip privilege drop if the value is empty (not recommended).
#
-user = lacme
+#user = _lacme-client
# groupname to drop privileges to (setting both effective and real gid,
# and also setting the list of supplementary gids to that single group).
-# Preserve root privileges if the value is empty (not recommended).
+# Skip privilege drop if the value is empty (not recommended).
#
-group = nogroup
+#group = nogroup
-# Path to the ACME client executable.
-#command = /usr/lib/lacme/client
+# ACME client command.
+#
+#command = /usr/libexec/lacme/client
-# Root URI of the ACME server. NOTE: Use the staging server for testing
-# as it has relaxed ratelimit.
+# URI of the ACME server's directory. NOTE: Use the staging server
+# <https://acme-staging-v02.api.letsencrypt.org/directory> for testing
+# as it has relaxed rate-limiting.
#
-#server = https://acme-v01.api.letsencrypt.org/
-#server = https://acme-staging.api.letsencrypt.org/
+#server = https://acme-v02.api.letsencrypt.org/directory
# Timeout in seconds after which the client stops polling the ACME
# server and considers the request failed.
#
-#timeout = 10
+#timeout = 30
# Whether to verify the server certificate chain.
-SSL_verify = yes
+#
+#SSL_verify = yes
# Specify the version of the SSL protocol used to transmit data.
-SSL_version = SSLv23:!TLSv1_1:!TLSv1:!SSLv3:!SSLv2
+#
+#SSL_version = SSLv23:!TLSv1_1:!TLSv1:!SSLv3:!SSLv2
# Specify the cipher list for the connection.
-SSL_cipher_list = EECDH+AESGCM:!MEDIUM:!LOW:!EXP:!aNULL:!eNULL
+#
+#SSL_cipher_list = EECDH+AESGCM:!MEDIUM:!LOW:!EXP:!aNULL:!eNULL
[webserver]
-# Specify the local address to listen on, in the form ADDRESS[:PORT].
+# Comma- or space-separated list of addresses to listen on, for instance
+# "0.0.0.0:80 [::]:80".
#
-#listen = 0.0.0.0:80
-listen = [::]:80
+#listen = /run/lacme-www.socket
-# If a webserver is already running, specify a non-existent directory
-# under which the webserver is configured to serve GET requests for
-# challenge files under "/.well-known/acme-challenge/" (for each virtual
-# hosts requiring authorization) as static files.
+# Directory under which an external HTTP daemon is configured to serve
+# GET requests for challenge files under "/.well-known/acme-challenge/"
+# (for each virtual host requiring authorization) as static files.
+# NOTE: the directory must exist and be writable by the lacme client
+# user.
#
-challenge-directory = /var/www/acme-challenge
+#challenge-directory =
# username to drop privileges to (setting both effective and real uid).
-# Preserve root privileges if the value is empty (not recommended).
+# Skip privilege drop if the value is empty (not recommended).
#
-user = www-data
+#user = _lacme-www
# groupname to drop privileges to (setting both effective and real gid,
# and also setting the list of supplementary gids to that single group).
-# Preserve root privileges if the value is empty (not recommended).
+# Skip privilege drop if the value is empty (not recommended).
#
-user = www-data
+#group = nogroup
-# Path to the ACME webserver executable.
-#command = /usr/lib/lacme/webserver
+# ACME webserver command.
+#
+#command = /usr/libexec/lacme/webserver
# Whether to automatically install iptables(8) rules to open the
# ADDRESS[:PORT] specified with listen. Theses rules are automatically
-# removed once lacme(1) exits.
+# removed once lacme(8) exits.
+#
+#iptables = No
+
+
+[accountd]
+# lacme-accound(1) section. Comment out this section (including its
+# header), or use the --socket= CLI option, to make lacme(8) connect to
+# an existing lacme-accountd(1) process via a UNIX-domain socket.
+
+# username to drop privileges to (setting both effective and real uid).
+# Skip privilege drop if the value is empty.
+#
+#user =
+
+# groupname to drop privileges to (setting both effective and real gid,
+# and also setting the list of supplementary gids to that single group).
+# Skip privilege drop if the value is empty.
+#
+#group =
+
+# lacme-accountd(1) command.
+#
+#command = /usr/bin/lacme-accountd
+
+# Path to the lacme-accountd(1) configuration file.
+#
+#config =
+
+# Be quiet.
#
-#iptables = Yes
+#quiet = Yes
; vim:ft=dosini
diff --git a/roles/lacme/tasks/main.yml b/roles/lacme/tasks/main.yml
index 9ff88c2..b031b25 100644
--- a/roles/lacme/tasks/main.yml
+++ b/roles/lacme/tasks/main.yml
@@ -5,15 +5,6 @@
- liblwp-protocol-https-perl
- lacme
-- name: Create a user 'lacme'
- user: name=lacme system=yes
- group=nogroup
- createhome=no
- home=/nonexistent
- shell=/usr/sbin/nologin
- password=!
- state=present
-
- name: Copy lacme/lacme-certs.conf
copy: src=etc/lacme/lacme.conf
dest=/etc/lacme/lacme.conf
diff --git a/roles/lists/files/etc/nginx/sites-available/sympa b/roles/lists/files/etc/nginx/sites-available/sympa
index f5a67bf..9b6aed2 100644
--- a/roles/lists/files/etc/nginx/sites-available/sympa
+++ b/roles/lists/files/etc/nginx/sites-available/sympa
@@ -4,7 +4,7 @@ server {
server_name lists.fripost.org;
- include snippets/acme-challenge.conf;
+ include /etc/lacme/nginx.conf;
access_log /var/log/nginx/lists.access.log;
error_log /var/log/nginx/lists.error.log info;
@@ -26,13 +26,18 @@ server {
include snippets/headers.conf;
add_header Content-Security-Policy
- "default-src 'none'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self'; font-src 'self'; upgrade-insecure-requests; block-all-mixed-content; reflected-xss block; referrer no-referrer-when-downgrade; frame-ancestors 'none'; form-action 'self'; base-uri lists.fripost.org";
+ "default-src 'none'; connect-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self'; font-src 'self'; frame-ancestors 'none'; form-action 'self'; base-uri lists.fripost.org";
include snippets/ssl.conf;
ssl_certificate ssl/lists.fripost.org.pem;
ssl_certificate_key ssl/lists.fripost.org.key;
include snippets/lists.fripost.org.hpkp-hdr;
+ gzip on;
+ gzip_vary on;
+ gzip_min_length 256;
+ gzip_types application/font-woff application/font-woff2 application/javascript application/json application/xml image/x-icon text/css text/plain;
+
location = /robots.txt {
allow all;
log_not_found off;
@@ -44,36 +49,34 @@ server {
return 302 /sympa$args;
}
- location ^~ /static-sympa/ {
- alias /var/lib/sympa/static_content/;
- expires 30d;
- }
+ location ^~ /static-sympa/ { expires 30d; try_files $uri =404; alias /usr/share/sympa/static_content/; }
+ location ^~ /css-sympa/ { expires 30d; try_files $uri =404; alias /var/lib/sympa/css/; }
+ location ^~ /pictures-sympa/ { expires 30d; try_files $uri =404; alias /var/lib/sympa/pictures; }
+
+ location ~* ^/sympa(?:/|$) {
+ gzip off; # protect against BREACH
- location ^~ /sympa {
fastcgi_split_path_info ^(/sympa)(.*)$;
include snippets/fastcgi.conf;
-
+ fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_pass unix:/run/wwsympa.socket;
- gzip off;
}
location ~* ^/([^/]+)/?$ {
return 302 /$1/sympa$args;
}
- location ~* ^/([^/]+)/sympa(/.*)?$ {
- set $vhost $1;
+ location ~* ^/(?<vhost>[^/]+)/sympa(?:/|$) {
+ gzip off; # protect against BREACH
if (!-f /etc/sympa/$vhost/robot.conf) {
return 404;
}
- fastcgi_split_path_info ^(/[^/]+/sympa)(.*)$;
+ fastcgi_split_path_info ^/[^/]+(/sympa)(.*)$;
include snippets/fastcgi.conf;
-
- fastcgi_pass unix:/run/wwsympa.socket;
- gzip off;
-
+ fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param SERVER_NAME $vhost;
+ fastcgi_pass unix:/run/wwsympa.socket;
}
location / {
diff --git a/roles/lists/files/etc/sympa/sympa/sympa.conf b/roles/lists/files/etc/sympa/sympa/sympa.conf
index 0e88baf..a864a14 100644
--- a/roles/lists/files/etc/sympa/sympa/sympa.conf
+++ b/roles/lists/files/etc/sympa/sympa/sympa.conf
@@ -12,21 +12,25 @@ email sympa
listmaster listmaster@fripost.org
## URL of main Web page
-wwsympa_url http://lists.fripost.org/sympa
+wwsympa_url https://lists.fripost.org/sympa
max_wrong_password 19
## Directory for storing static contents (CSS, members pictures, documentation) directly delivered by Apache
-static_content_path /var/lib/sympa/static_content
+static_content_path /usr/share/sympa/static_content
## URL mapped with the static_content_path directory defined above
static_content_url /static-sympa
-css_url /static-sympa/css
+css_url /css-sympa
+css_path /var/lib/sympa/css
+
+pictures_path /var/lib/sympa/pictures
+pictures_url /pictures-sympa
## Secret used by Sympa to make MD5 fingerprint in web cookies secure
## Should not be changed ! May invalid all user password
-cookie `head -n1 /etc/sympa/cookie`
+cookie `/usr/bin/head -n1 /etc/sympa/cookie`
## Who is able to create lists
## This parameter is a scenario, check sympa documentation about scenarios if you want to define one
@@ -44,7 +48,7 @@ etc /etc/sympa
## Syslog facility for sympa
## Do not forget to edit syslog.conf
-syslog `cat /etc/sympa/facility`
+syslog LOCAL1
## Log verbosity
## 0: normal, 2,3,4: for debug
@@ -63,8 +67,6 @@ umask 027
sendmail /usr/sbin/sendmail
sendmail_aliases none
-distribution_mode fork
-
## Max. number of Sendmail processes (launched by Sympa) running simultaneously
## Proposed value is quite low, you can rise it up to 100, 200 or even 300 with powerfull systems.
maxsmtp 128
@@ -131,8 +133,6 @@ spool /var/spool/sympa
## Directory for incoming spool
queue /var/spool/sympa/msg
-queuedistribute /var/spool/sympa/distribute
-
## Directory for moderation spool
queuemod /var/spool/sympa/moderation
@@ -164,7 +164,7 @@ queueautomatic /var/spool/sympa/automatic
## Supported languages
## This is the set of language that will be proposed to your users for the Sympa GUI. Don't select a language if you don't have the proper locale packages installed.
-supported_lang sv,en_US
+supported_lang sv,en_US,fr
## Default language (one of supported languages)
## This is the default language used by Sympa
@@ -261,18 +261,12 @@ default_sql_fetch_timeout 300
###\\\\ S/MIME configuration ////###
-## Path to OpenSSL
-## Sympa recognizes S/MIME if OpenSSL is installed
-openssl /usr/bin/openssl
-
## Directory containing trusted CA certificates
#capath /etc/sympa/ssl.crt
## File containing bundled trusted CA certificates
#cafile /usr/local/apache/conf/ssl.crt/ca-bundle.crt
-crl_dir /var/lib/sympa/list_data/crl
-
## Directory containing user certificates
ssl_cert_dir /var/lib/sympa/list_data/X509-user-certs
@@ -291,7 +285,7 @@ dkim_signature_apply_on md5_authenticated_messages,smime_authenticated_messages,
## DMARC protection
## https://sympa-community.github.io/manual/customize/dmarc-protection.html
-dmarc_protection_mode dmarc_reject
+dmarc_protection_mode all
###\\\\ Antivirus plug-in ////###
@@ -370,7 +364,7 @@ ldap_force_canonical_email 1
## Syslog facility for wwsympa, archived and bounced
## Default is to use previously defined sympa log facility.
-log_facility `cat /etc/sympa/facility`
+log_facility LOCAL1
#log_module
@@ -399,3 +393,5 @@ use_fast_cgi 1
## Default number of lines of the array displaying the log entries in the logs
## page
viewlogs_page_size 25
+
+shared_feature on
diff --git a/roles/lists/files/etc/systemd/system/wwsympa.service b/roles/lists/files/etc/systemd/system/wwsympa.service
index 3f76aca..cff2db7 100644
--- a/roles/lists/files/etc/systemd/system/wwsympa.service
+++ b/roles/lists/files/etc/systemd/system/wwsympa.service
@@ -12,16 +12,15 @@ ExecStart=/usr/lib/cgi-bin/sympa/wwsympa.fcgi
# Hardening
NoNewPrivileges=yes
-PrivateDevices=yes
-ProtectHome=yes
-ProtectSystem=strict
-PrivateTmp=yes
ReadWriteDirectories=/etc/sympa
ReadWriteDirectories=/var/lib/sympa
-ReadWriteDirectories=-/var/run/sympa
ReadWriteDirectories=/var/spool/sympa
+ReadWriteDirectories=/run/sympa
PrivateDevices=yes
PrivateNetwork=yes
+ProtectHome=yes
+ProtectSystem=strict
+PrivateTmp=yes
ProtectControlGroups=yes
ProtectKernelModules=yes
ProtectKernelTunables=yes
diff --git a/roles/lists/tasks/mail.yml b/roles/lists/tasks/mail.yml
index 44b96e5..2821b02 100644
--- a/roles/lists/tasks/mail.yml
+++ b/roles/lists/tasks/mail.yml
@@ -3,7 +3,7 @@
vars:
packages:
- postfix
- - postfix-ldap
+ - postfix-lmdb
- name: Configure Postfix
template: src=etc/postfix/{{ item }}.j2
diff --git a/roles/lists/tasks/sympa.yml b/roles/lists/tasks/sympa.yml
index 0d5eac1..27a5823 100644
--- a/roles/lists/tasks/sympa.yml
+++ b/roles/lists/tasks/sympa.yml
@@ -10,8 +10,8 @@
- libcrypt-openssl-x509-perl
- name: Make the 'sympa' MySQL user use unix_socket
- mysql_user2: name=sympa password= auth_plugin=unix_socket
- state=present
+ mysql_user: name=sympa password= plugin=unix_socket
+ state=present
- name: Configure Sympa
copy: src=etc/sympa/{{ item }}
diff --git a/roles/lists/templates/etc/postfix/main.cf.j2 b/roles/lists/templates/etc/postfix/main.cf.j2
index 1bf02eb..2be1b41 100644
--- a/roles/lists/templates/etc/postfix/main.cf.j2
+++ b/roles/lists/templates/etc/postfix/main.cf.j2
@@ -21,7 +21,7 @@ append_dot_mydomain = no
mynetworks = 127.0.0.0/8, [::1]/128
{%- if groups.all | length > 1 -%}
{%- for mx in groups.MX | sort -%}
- , {{ ipsec[ hostvars[mx].inventory_hostname_short ] | ipaddr }}
+ , {{ ipsec[ hostvars[mx].inventory_hostname_short ] | ansible.utils.ipaddr }}
{%- endfor %}
{% endif %}
diff --git a/roles/lists/templates/etc/sympa/robot.conf.j2 b/roles/lists/templates/etc/sympa/robot.conf.j2
index 75687d8..28998e3 100644
--- a/roles/lists/templates/etc/sympa/robot.conf.j2
+++ b/roles/lists/templates/etc/sympa/robot.conf.j2
@@ -1,3 +1,2 @@
-http_host {{ item }}
+#wwsympa_url_local https://{{ item }}/sympa
wwsympa_url https://{{ item }}/sympa
-# wwsympa_url https://lists.fripost.org/{{ item }}/sympa
diff --git a/roles/munin-master/files/etc/nginx/sites-available/munin b/roles/munin-master/files/etc/nginx/sites-available/munin
index 7b0b789..2f681fb 100644
--- a/roles/munin-master/files/etc/nginx/sites-available/munin
+++ b/roles/munin-master/files/etc/nginx/sites-available/munin
@@ -23,15 +23,15 @@ server {
location /munin-cgi/munin-cgi-graph/ {
fastcgi_split_path_info ^(/munin-cgi/munin-cgi-graph)(.*);
+ fastcgi_param PATH_INFO $fastcgi_path_info;
include snippets/fastcgi.conf;
fastcgi_pass unix:/run/munin/cgi-graph.socket;
- gzip off;
}
location /munin/ {
fastcgi_split_path_info ^(/munin)(.*);
+ fastcgi_param PATH_INFO $fastcgi_path_info;
include snippets/fastcgi.conf;
fastcgi_pass unix:/run/munin/cgi-html.socket;
- gzip off;
}
}
diff --git a/roles/munin-master/tasks/main.yml b/roles/munin-master/tasks/main.yml
index 9ed3577..6dad93b 100644
--- a/roles/munin-master/tasks/main.yml
+++ b/roles/munin-master/tasks/main.yml
@@ -8,8 +8,15 @@
- name: Configure rrdcached
lineinfile: "dest=/etc/default/rrdcached
- regexp='^#?OPTS='
- line='OPTS=\"-s munin -m 660 -l unix:/var/run/rrdcached.sock -w 1800 -z 1800 -f 3600 -j /var/lib/rrdcached/journal -F -b /var/lib/munin -B\"'"
+ regexp='^#?{{ item.name }}='
+ line='{{ item.name }}=\"{{ item.value }}\"'"
+ with_items:
+ - { name: 'BASE_OPTIONS', value: '-B -F' }
+ - { name: 'BASE_PATH', value: '/var/lib/munin' }
+ - { name: 'SOCKFILE', value: '/run/rrdcached.sock' }
+ - { name: 'SOCKGROUP', value: 'munin' }
+ - { name: 'SOCKMODE', value: '0660' }
+ - { name: 'WRITE_TIMEOUT', value: '1800' }
register: r
notify:
- Restart rrdcached
diff --git a/roles/munin-master/templates/etc/munin/munin.conf.j2 b/roles/munin-master/templates/etc/munin/munin.conf.j2
index 401094a..cdf659c 100644
--- a/roles/munin-master/templates/etc/munin/munin.conf.j2
+++ b/roles/munin-master/templates/etc/munin/munin.conf.j2
@@ -8,7 +8,7 @@
#dbdir /var/lib/munin
#htmldir /var/cache/munin/www
#logdir /var/log/munin
-#rundir /var/run/munin
+#rundir /run/munin
# Where to look for the HTML templates
#
@@ -83,11 +83,11 @@ html_strategy cgi
# To reduce IO and enable the use of the rrdcached, uncomment it and set it to
# the location of the socket that rrdcached uses.
#
-rrdcached_socket /var/run/rrdcached.sock
+rrdcached_socket /run/rrdcached.sock
# Drop somejuser@fnord.comm and anotheruser@blibb.comm an email everytime
# something changes (OK -> WARNING, CRITICAL -> OK, etc)
-contact.admin.command mail -s "Munin notification" admin@fripost.org
+contact.admin.command mail -s "Munin notification" root@fripost.org
#
# For those with Nagios, the following might come in handy. In addition,
# the services must be defined in the Nagios server as well.
diff --git a/roles/nextcloud/files/etc/cron.d/nextcloud b/roles/nextcloud/files/etc/cron.d/nextcloud
index 8bd7d86..3c4aac0 100644
--- a/roles/nextcloud/files/etc/cron.d/nextcloud
+++ b/roles/nextcloud/files/etc/cron.d/nextcloud
@@ -1,2 +1,2 @@
MAILTO=root
-*/15 * * * * www-data php -f /var/www/nextcloud/cron.php
+*/5 * * * * _nextcloud php -f /usr/local/share/nextcloud/cron.php
diff --git a/roles/nextcloud/files/etc/ldap/ldap.conf b/roles/nextcloud/files/etc/ldap/ldap.conf
index 5f388f1..b4ebe34 100644
--- a/roles/nextcloud/files/etc/ldap/ldap.conf
+++ b/roles/nextcloud/files/etc/ldap/ldap.conf
@@ -6,5 +6,5 @@
# This file should be world readable but not world writable.
# TLS certificates (needed for GnuTLS)
-TLS_CACERT /etc/ldap/ssl/ldap.fripost.org.pem
-TLS_REQCERT hard
+TLS_CACERT /etc/ldap/ssl/ldap.fripost.org.pem
+TLS_REQCERT hard
diff --git a/roles/nextcloud/files/etc/logrotate.d/nextcloud b/roles/nextcloud/files/etc/logrotate.d/nextcloud
new file mode 100644
index 0000000..b8dd232
--- /dev/null
+++ b/roles/nextcloud/files/etc/logrotate.d/nextcloud
@@ -0,0 +1,9 @@
+/var/log/nextcloud/*.log {
+ daily
+ missingok
+ rotate 7
+ compress
+ delaycompress
+ notifempty
+ create 0640 _nextcloud adm
+}
diff --git a/roles/nextcloud/files/etc/nginx/sites-available/nextcloud b/roles/nextcloud/files/etc/nginx/sites-available/nextcloud
index 9e5e9b0..f1f4dcc 100644
--- a/roles/nextcloud/files/etc/nginx/sites-available/nextcloud
+++ b/roles/nextcloud/files/etc/nginx/sites-available/nextcloud
@@ -4,10 +4,10 @@ server {
server_name cloud.fripost.org;
- include snippets/acme-challenge.conf;
+ include /etc/lacme/nginx.conf;
- access_log /var/log/nginx/cloud.access.log;
- error_log /var/log/nginx/cloud.error.log info;
+ access_log /var/log/nginx/cloud.access.log;
+ error_log /var/log/nginx/cloud.error.log info;
location / {
return 301 https://$host$request_uri;
@@ -20,10 +20,10 @@ server {
server_name cloud.fripost.org;
- root /var/www/nextcloud/;
+ root /usr/local/share/nextcloud;
include snippets/headers.conf;
- add_header X-Robots-Tag none;
+ add_header X-Robots-Tag "noindex, nofollow";
add_header X-Download-Options noopen;
add_header X-Permitted-Cross-Domain-Policies none;
@@ -32,17 +32,26 @@ server {
ssl_certificate_key ssl/cloud.fripost.org.key;
include snippets/cloud.fripost.org.hpkp-hdr;
+ include mime.types;
+ types {
+ text/javascript js mjs;
+ application/wasm wasm;
+ }
+
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
- access_log /var/log/nginx/cloud.access.log;
- error_log /var/log/nginx/cloud.error.log info;
+ access_log /var/log/nginx/cloud.access.log;
+ error_log /var/log/nginx/cloud.error.log info;
- location = /.well-known/carddav { return 301 $scheme://$host/remote.php/dav; }
- location = /.well-known/caldav { return 301 $scheme://$host/remote.php/dav; }
+ index index.php index.html /index.php$request_uri;
+
+ location = /.well-known/carddav { return 301 /remote.php/dav; }
+ location = /.well-known/caldav { return 301 /remote.php/dav; }
+ location ^~ /.well-known/ { return 301 /index.php$request_uri; }
# set max upload size
client_max_body_size 512M;
@@ -57,39 +66,44 @@ server {
gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;
- error_page 403 /core/templates/403.php;
- error_page 404 /core/templates/404.php;
-
- location = / { return 303 $scheme://$host/apps/files/; }
- location / { rewrite ^ /index.php$uri last; }
+ location = / { return 303 /apps/files/; }
location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)/ { internal; }
location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) { internal; }
- location ~ ^/(?:index|remote|public|cron|core/ajax/update|status|ocs/v[12]|updater/.+|ocs-provider/.+|core/templates/40[34])\.php(?:$|/) {
- fastcgi_split_path_info ^(.+\.php)(/.*)$;
+ location ~ \.php(?:$|/) {
+ # Required for legacy support
+ rewrite ^/(?!index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|ocs-provider\/.+|.+\/richdocumentscode(_arm64)?\/proxy) /index.php$request_uri;
+
include snippets/fastcgi-php.conf;
fastcgi_param modHeadersAvailable true;
fastcgi_param front_controller_active true;
+ fastcgi_intercept_errors on;
fastcgi_request_buffering off;
- fastcgi_param PHP_VALUE "upload_max_filesize=512M
- post_max_size=512M
- memory_limit=512M";
- fastcgi_param PHP_ADMIN_VALUE "open_basedir=$document_root:/mnt/nextcloud-data:/etc/nextcloud:/usr/share/php:/tmp:/dev";
+ fastcgi_pass unix:/run/php/php8.2-fpm@nextcloud.sock;
}
- location ~ ^/(?:updater|ocs-provider)(?:$|/) {
- try_files $uri/ =404;
- index index.php;
+ location ~ \.(?:css|js|mjs|svg|gif|png|jpg|ico|wasm|tflite|map|ogg|flac)$ {
+ try_files $uri /index.php$uri$is_args$args;
}
-
- location ~* \.(?:css|js|woff|svg|gif)$ {
+ location ~ \.woff2?$ {
+ try_files $uri /index.php$request_uri;
+ expires 7d;
+ }
+ location ~ \.(?:png|html|ttf|ico|jpg|jpeg|bcmap)$ {
try_files $uri /index.php$uri$is_args$args;
- expires 30d;
}
- location ~* \.(?:png|html|ttf|ico|jpg|jpeg)$ {
- try_files $uri /index.php$uri$is_args$args;
+ location /remote {
+ return 301 /remote.php$request_uri;
+ }
+
+ location / {
+ try_files $uri $uri/ /index.php$request_uri;
+ }
+
+ location = /core/img/favicon.ico {
+ alias /var/www/nextcloud/fripost.ico;
}
}
@@ -101,10 +115,10 @@ server {
server_name www.cloud.fripost.org;
- include snippets/acme-challenge.conf;
+ include /etc/lacme/nginx.conf;
- access_log /var/log/nginx/cloud.access.log;
- error_log /var/log/nginx/cloud.error.log info;
+ access_log /var/log/nginx/cloud.access.log;
+ error_log /var/log/nginx/cloud.error.log info;
location / {
return 301 https://cloud.fripost.org$request_uri;
diff --git a/roles/nextcloud/files/etc/php/fpm/pool.d/nextcloud.conf b/roles/nextcloud/files/etc/php/fpm/pool.d/nextcloud.conf
new file mode 100644
index 0000000..898ce60
--- /dev/null
+++ b/roles/nextcloud/files/etc/php/fpm/pool.d/nextcloud.conf
@@ -0,0 +1,24 @@
+[nextcloud]
+user = _nextcloud
+group = nogroup
+listen = /run/php/php8.2-fpm@nextcloud.sock
+listen.owner = www-data
+listen.group = www-data
+listen.mode = 0600
+pm = dynamic
+pm.max_children = 5
+pm.start_servers = 2
+pm.min_spare_servers = 1
+pm.max_spare_servers = 3
+
+php_value[upload_max_filesize] = 512M
+php_value[post_max_size] = 512M
+php_value[memory_limit] = 512M
+
+php_admin_value[open_basedir] = /usr/local/share/nextcloud:/var/www/nextcloud:/mnt/nextcloud-data:/etc/nextcloud:/var/cache/nextcloud:/var/log/nextcloud:/usr/share/php:/tmp:/dev
+
+env[HOSTNAME] = $HOSTNAME
+env[PATH] = /usr/bin:/bin
+env[TMP] = /tmp
+env[TMPDIR] = /tmp
+env[TEMP] = /tmp
diff --git a/roles/nextcloud/handlers/main.yml b/roles/nextcloud/handlers/main.yml
index 6552940..a14d6e1 100644
--- a/roles/nextcloud/handlers/main.yml
+++ b/roles/nextcloud/handlers/main.yml
@@ -1,6 +1,9 @@
---
-- name: Restart php7.0-fpm
- service: name=php7.0-fpm state=restarted
+- name: Restart php8.2-fpm
+ service: name=php8.2-fpm state=restarted
+
+- name: Restart Redis
+ service: name=redis-server state=restarted
- name: Restart Nginx
service: name=nginx state=restarted
diff --git a/roles/nextcloud/tasks/main.yml b/roles/nextcloud/tasks/main.yml
index 09554e0..14bc02c 100644
--- a/roles/nextcloud/tasks/main.yml
+++ b/roles/nextcloud/tasks/main.yml
@@ -3,12 +3,13 @@
vars:
packages:
- php-cli
+ - php-bcmath
- php-fpm
- php-apcu
- php-gd
+ - php-gmp
- php-imagick
- php-mbstring
- - php-mcrypt
- php-xml
- php-curl
- php-intl
@@ -16,41 +17,54 @@
- php-mysql
- php-zip
- php-json
+ - php-gmp
-- name: Configure PHP 7.0 Zend opcache
- lineinfile: dest=/etc/php/7.0/fpm/php.ini
+- name: Configure PHP 8.2 Zend opcache
+ lineinfile: dest=/etc/php/8.2/fpm/php.ini
regexp='^;?{{ item.var }}\\s*='
line="{{ item.var }} = {{ item.value }}"
owner=root group=root
mode=0644
with_items:
- - { var: opcache.enable, value: 1 }
- - { var: opcache.enable_cli, value: 1 }
- - { var: opcache.memory_consumption, value: 128 }
- - { var: opcache.interned_strings_buffer, value: 8 }
- - { var: opcache.max_accelerated_files, value: 10000 }
- - { var: opcache.revalidate_freq, value: 1 }
- - { var: opcache.fast_shutdown, value: 1 }
+ - { var: opcache.memory_consumption, value: 512 }
+ - { var: opcache.revalidate_freq, value: 180 }
+ - { var: opcache.interned_strings_buffer, value: 12 }
notify:
- - Restart php7.0-fpm
+ - Restart php8.2-fpm
-- name: Configure PHP 7.0 pool environment
- lineinfile: dest=/etc/php/7.0/fpm/pool.d/www.conf
- regexp='^;?env\[{{ item.var }}\]\\s*='
- line="env[{{ item.var }}] = {{ item.value }}"
+- name: Configure PHP 8.2 CLI
+ lineinfile: dest=/etc/php/8.2/cli/php.ini
+ regexp='^;?{{ item.var }}\\s*='
+ line="{{ item.var }} = {{ item.value }}"
owner=root group=root
mode=0644
with_items:
- - { var: HOSTNAME, value: "$HOSTNAME" }
- - { var: PATH, value: "/usr/bin:/bin" }
- - { var: TMP, value: "/tmp" }
- - { var: TMPDIR, value: "/tmp" }
- - { var: TEMP, value: "/tmp" }
+ - { var: apc.enable_cli, value: 1 }
+
+- name: Create '_nextcloud' user
+ user: name=_nextcloud system=yes
+ group=nogroup
+ createhome=no
+ home=/nonexistent
+ shell=/usr/sbin/nologin
+ password=!
+ state=present
+
+- name: Delete PHP 8.2 FPM's www pool
+ file: path=/etc/php/8.2/fpm/pool.d/www.conf state=absent
+ notify:
+ - Restart php8.2-fpm
+
+- name: Configure PHP 8.2 FPM's nextcloud pool
+ copy: src=etc/php/fpm/pool.d/nextcloud.conf
+ dest=/etc/php/8.2/fpm/pool.d/nextcloud.conf
+ owner=root group=root
+ mode=0644
notify:
- - Restart php7.0-fpm
+ - Restart php8.2-fpm
-- name: Start php7.0-fpm
- service: name=php7.0-fpm state=started
+- name: Start php8.2-fpm
+ service: name=php8.2-fpm state=started
- name: Copy /etc/cron.d/nextcloud
copy: src=etc/cron.d/nextcloud
@@ -103,6 +117,84 @@
- genkey
- import_tasks: ldap.yml
- when: "'LDAP-provider' not in group_names"
+ when: "'LDAP_provider' not in group_names"
tags:
- ldap
+
+# Note: intentionally don't set an owner/group as we don't want to set
+# ownership unless the path is a mountpoint. The service will fail
+# unless the data directory is mounted and accessible, and that's what
+# we want.
+- name: Create directory /mnt/nextcloud-data
+ file: path=/mnt/nextcloud-data
+ state=directory
+ mode=0700
+
+- name: Create directory /var/www/nextcloud
+ file: path=/var/www/nextcloud
+ state=directory
+ owner=root group=root
+ mode=0755
+
+# Note: Nextcloud doesn't like symlinked apps
+# * https://github.com/nextcloud/server/issues/10437
+# * https://github.com/nextcloud/server/issues/13556
+- name: Create directory /var/www/nextcloud/apps
+ file: path=/var/www/nextcloud/apps
+ state=directory
+ owner=_nextcloud group=nogroup
+ mode=0755
+
+- name: Create directory /var/log/nextcloud
+ file: path=/var/log/nextcloud
+ state=directory
+ owner=_nextcloud group=adm
+ mode=0750
+
+- name: Create directory /var/cache/nextcloud
+ file: path=/var/cache/nextcloud
+ state=directory
+ owner=_nextcloud group=nogroup
+ mode=0700
+
+- name: Copy Nextcloud logrotate snippet
+ copy: src=etc/logrotate.d/nextcloud
+ dest=/etc/logrotate.d/nextcloud
+ owner=root group=root
+ mode=0644
+ tags:
+ - logrotate
+
+- name: Install redis-server
+ apt: pkg={{ packages }}
+ vars:
+ packages:
+ - php-redis
+ - redis-server
+
+- name: Configure Redis
+ lineinfile: dest=/etc/redis/redis.conf
+ regexp='^#?\\s*{{ item.var }}\\s+'
+ line="{{ item.var }} {{ item.value }}"
+ owner=redis group=redis
+ mode=0640
+ with_items:
+ - { var: port, value: 0 }
+ - { var: unixsocket, value: /run/redis/redis-server.sock }
+ - { var: unixsocketperm, value: 660 }
+ notify:
+ - Restart Redis
+
+- name: Start redis-server
+ service: name=redis-server state=started
+
+- name: Add '_nextcloud' user to 'redis' group
+ user: name=_nextcloud groups=redis append=yes
+ notify:
+ - Restart php8.2-fpm
+
+- name: Install other Nextcloud dependencies
+ apt: pkg={{ packages }}
+ vars:
+ packages:
+ - libmagickcore-6.q16-6-extra
diff --git a/roles/out/tasks/main.yml b/roles/out/tasks/main.yml
index 0e64443..7a297f1 100644
--- a/roles/out/tasks/main.yml
+++ b/roles/out/tasks/main.yml
@@ -1,5 +1,9 @@
- name: Install Postfix
- apt: pkg=postfix
+ apt: pkg={{ packages }}
+ vars:
+ packages:
+ - postfix
+ - postfix-lmdb
- name: Configure Postfix
template: src=etc/postfix/{{ item }}.j2
@@ -24,6 +28,19 @@
owner=root group=root
mode=0644
+- name: Copy the SMTP TLS policy maps
+ template: src=etc/postfix/smtp_tls_policy.j2
+ dest=/etc/postfix-{{ postfix_instance[inst].name }}/smtp_tls_policy
+ owner=root group=root
+ mode=0644
+
+- name: Compile the SMTP TLS policy maps
+ postmap: cmd=postmap src=/etc/postfix-{{ postfix_instance[inst].name }}/smtp_tls_policy db=lmdb
+ owner=root group=root
+ mode=0644
+ notify:
+ - Reload Postfix
+
- meta: flush_handlers
- name: Start Postfix
diff --git a/roles/out/templates/etc/postfix/canonical.j2 b/roles/out/templates/etc/postfix/canonical.j2
index ed8bb4d..14ef6e7 100644
--- a/roles/out/templates/etc/postfix/canonical.j2
+++ b/roles/out/templates/etc/postfix/canonical.j2
@@ -6,5 +6,5 @@
# address verification, so we use the admin team's address in the
# envelope.
{% for host in groups.all | sort %}
-@{{ hostvars[host].inventory_hostname }} admin@fripost.org
+@{{ hostvars[host].inventory_hostname }} root@fripost.org
{% endfor %}
diff --git a/roles/out/templates/etc/postfix/main.cf.j2 b/roles/out/templates/etc/postfix/main.cf.j2
index c05d9a5..f8aa55a 100644
--- a/roles/out/templates/etc/postfix/main.cf.j2
+++ b/roles/out/templates/etc/postfix/main.cf.j2
@@ -56,7 +56,10 @@ smtp_tls_protocols = !SSLv2, !SSLv3
smtp_tls_note_starttls_offer = yes
smtp_tls_session_cache_database = lmdb:$data_directory/smtp_tls_session_cache
-smtpd_tls_security_level = none
+smtp_tls_fingerprint_digest = sha256
+smtp_tls_policy_maps = lmdb:$config_directory/smtp_tls_policy
+
+smtpd_tls_security_level = none
strict_rfc821_envelopes = yes
smtpd_delay_reject = yes
diff --git a/roles/out/templates/etc/postfix/smtp_tls_policy.j2 b/roles/out/templates/etc/postfix/smtp_tls_policy.j2
new file mode 100644
index 0000000..7722dc8
--- /dev/null
+++ b/roles/out/templates/etc/postfix/smtp_tls_policy.j2
@@ -0,0 +1,12 @@
+# Lookup table matching next-hop destinations to TLS security policies;
+# this allows pining the key material for chosen recipient domains.
+#
+# {{ ansible_managed }}
+# Do NOT edit this file directly!
+{% for nexthop in ['fripost.org','.fripost.org'] %}
+
+{{ nexthop }} fingerprint ciphers=high protocols=!SSLv2:!SSLv3:!TLSv1:!TLSv1.1
+{% for h in groups.MX | sort %}
+ match={{ lookup('pipe', 'openssl pkey -pubin -outform DER <"certs/public/mx'+(hostvars[h].mxno | default('') | string)+'.fripost.org.pub" | openssl dgst -sha256 -c | sed "s/[^=]*=\s*//"') }}
+{% endfor %}
+{% endfor %}
diff --git a/roles/webmail/files/etc/cron.d/roundcube-core b/roles/webmail/files/etc/cron.d/roundcube-core
new file mode 100644
index 0000000..6d9e7af
--- /dev/null
+++ b/roles/webmail/files/etc/cron.d/roundcube-core
@@ -0,0 +1,7 @@
+#
+# Roundcube database cleaning: finally removes all records that are
+# marked as deleted.
+MAILTO=root
+
+# m h dom mon dow user command
+0 5 * * * _roundcube /usr/share/roundcube/bin/cleandb.sh >/dev/null
diff --git a/roles/webmail/files/etc/nginx/sites-available/roundcube b/roles/webmail/files/etc/nginx/sites-available/roundcube
index ae73562..602668f 100644
--- a/roles/webmail/files/etc/nginx/sites-available/roundcube
+++ b/roles/webmail/files/etc/nginx/sites-available/roundcube
@@ -6,10 +6,10 @@ server {
server_name mail.fripost.org;
server_name webmail.fripost.org;
- include snippets/acme-challenge.conf;
+ include /etc/lacme/nginx.conf;
- access_log /var/log/nginx/roundcube.access.log;
- error_log /var/log/nginx/roundcube.error.log info;
+ access_log /var/log/nginx/roundcube.access.log;
+ error_log /var/log/nginx/roundcube.error.log info;
location / {
return 301 https://$host$request_uri;
@@ -24,22 +24,27 @@ server {
server_name mail.fripost.org;
server_name webmail.fripost.org;
- root /var/lib/roundcube;
+ root /var/lib/roundcube/public_html;
include snippets/headers.conf;
add_header Content-Security-Policy
- "default-src 'none'; child-src 'self'; frame-src 'self'; connect-src 'self'; object-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src * data:; font-src 'self'; reflected-xss block; referrer no-referrer-when-downgrade; frame-ancestors 'self'; form-action 'self'; base-uri mail.fripost.org webmail.fripost.org";
+ "default-src 'none'; frame-src 'self'; connect-src 'self'; object-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'; frame-ancestors 'self'; form-action 'self'; base-uri mail.fripost.org webmail.fripost.org";
include snippets/ssl.conf;
ssl_certificate ssl/mail.fripost.org.pem;
ssl_certificate_key ssl/mail.fripost.org.key;
include snippets/mail.fripost.org.hpkp-hdr;
+ gzip on;
+ gzip_static on;
+ gzip_vary on;
+ gzip_min_length 256;
+ gzip_types application/font-woff application/font-woff2 application/javascript application/json application/xml image/svg+xml image/x-icon text/css text/plain text/vcard;
+
location = /favicon.ico {
- root /usr/share/roundcube/skins/default/images;
+ root /usr/share/roundcube/skins/elastic/images;
log_not_found off;
access_log off;
- expires max;
}
location = /robots.txt {
@@ -48,28 +53,24 @@ server {
access_log off;
}
- access_log /var/log/nginx/roundcube.access.log;
- error_log /var/log/nginx/roundcube.error.log info;
+ access_log /var/log/nginx/roundcube.access.log;
+ error_log /var/log/nginx/roundcube.error.log info;
client_max_body_size 64m;
location = / { index index.php; }
location = /index.php {
+ # TODO enable gzip for Roundcube >=1.5: it's immune to BREACH attacks once
+ # $config['session_samesite'] is set to 'Strict', see
+ # https://github.com/roundcube/roundcubemail/pull/6772
+ # https://www.sjoerdlangkemper.nl/2016/11/07/current-state-of-breach-attack/#same-site-cookies
+ gzip off;
include snippets/fastcgi-php-ssl.conf;
-
- # From /var/lib/roundcube/.htaccess
- fastcgi_param PHP_VALUE "upload_max_filesize=25M
- post_max_size=30M
- memory_limit=64M
- session.gc_maxlifetime=21600
- session.gc_divisor=500
- session.gc_probability=1";
- fastcgi_param PHP_ADMIN_VALUE "open_basedir=$document_root:/usr/share/roundcube:/etc/roundcube:/var/log/roundcube:/usr/share/php:/usr/share/javascript:/usr/share/tinymce:/usr/share/misc/magic:/dev
- upload_tmp_dir=$document_root/temp";
+ fastcgi_pass unix:/var/run/php/php7.4-fpm@roundcube.sock;
}
- location ~ "^/(?:plugins|program/js|program/resources|skins)/.*[^./]\.(?:css|eot|gif|html|ico|jpg|js|pdf|png|svg|tif|ttf|woff)$" {
- try_files $uri =404;
+ location ~ "^/(?:plugins|program/js|program/resources|skins)(?:/[[:alnum:]][[:alnum:]\-\._]*)+\.(?:css|eot|gif|html|ico|jpg|js|pdf|png|svg|tiff?|ttf|webp|woff2?)$" {
expires 30d;
+ try_files $uri =404;
}
location / { internal; }
}
diff --git a/roles/webmail/files/etc/php/fpm/pool.d/roundcube.conf b/roles/webmail/files/etc/php/fpm/pool.d/roundcube.conf
new file mode 100644
index 0000000..1a7a1d8
--- /dev/null
+++ b/roles/webmail/files/etc/php/fpm/pool.d/roundcube.conf
@@ -0,0 +1,22 @@
+[roundcube]
+user = _roundcube
+group = nogroup
+listen = /run/php/php7.4-fpm@roundcube.sock
+listen.owner = www-data
+listen.group = www-data
+listen.mode = 0600
+pm = dynamic
+pm.max_children = 5
+pm.start_servers = 2
+pm.min_spare_servers = 1
+pm.max_spare_servers = 3
+
+php_value[upload_max_filesize] = 25M
+php_value[post_max_size] = 30M
+php_value[memory_limit] = 64M
+php_value[session.gc_maxlifetime] = 21600
+php_value[session.gc_divisor] = 500
+php_value[session.gc_probability] = 1
+
+php_admin_value[upload_tmp_dir] = /var/lib/roundcube/temp
+php_admin_value[open_basedir] = /var/lib/roundcube:/usr/share/roundcube:/etc/roundcube:/var/log/roundcube:/usr/share/php:/usr/share/javascript:/usr/lib/nodejs:/usr/share/tinymce:/usr/share/misc/magic:/dev
diff --git a/roles/webmail/files/etc/roundcube/plugins/authres_status/config.inc.php b/roles/webmail/files/etc/roundcube/plugins/authres_status/config.inc.php
new file mode 100644
index 0000000..6d41d4f
--- /dev/null
+++ b/roles/webmail/files/etc/roundcube/plugins/authres_status/config.inc.php
@@ -0,0 +1,6 @@
+<?php
+
+$config['use_fallback_verifier'] = false;
+$config['trusted_mtas'] = array('mx1.fripost.org', 'mx2.fripost.org');
+
+?>
diff --git a/roles/webmail/files/etc/roundcube/plugins/html5_notifier/config.inc.php b/roles/webmail/files/etc/roundcube/plugins/html5_notifier/config.inc.php
new file mode 100644
index 0000000..1ec7922
--- /dev/null
+++ b/roles/webmail/files/etc/roundcube/plugins/html5_notifier/config.inc.php
@@ -0,0 +1,6 @@
+<?php
+
+$config['html5_notifier_duration'] = '3';
+$config['html5_notifier_smbox'] = '1';
+
+?>
diff --git a/roles/webmail/files/etc/roundcube/plugins/jqueryui/config.inc.php b/roles/webmail/files/etc/roundcube/plugins/jqueryui/config.inc.php
deleted file mode 100644
index bb9720b..0000000
--- a/roles/webmail/files/etc/roundcube/plugins/jqueryui/config.inc.php
+++ /dev/null
@@ -1,11 +0,0 @@
-<?php
-
-// if you want to load localization strings for specific sub-libraries of jquery-ui, configure them here
-$config['jquery_ui_i18n'] = array('datepicker');
-
-// map Roundcube skins with jquery-ui themes here
-$config['jquery_ui_skin_map'] = array(
- 'default' => 'smoothness',
-);
-
-?>
diff --git a/roles/webmail/files/etc/roundcube/plugins/password/config.inc.php b/roles/webmail/files/etc/roundcube/plugins/password/config.inc.php
index c32f58e..e53b753 100644
--- a/roles/webmail/files/etc/roundcube/plugins/password/config.inc.php
+++ b/roles/webmail/files/etc/roundcube/plugins/password/config.inc.php
@@ -122,7 +122,7 @@ $config['password_saslpasswd_args'] = '';
// You can provide one or several hosts in an array in which case the hosts are tried from left to right.
// Exemple: array('ldap1.exemple.com', 'ldap2.exemple.com');
// Default: 'localhost'
-$config['password_ldap_host'] = 'localhost';
+$config['password_ldap_host'] = '127.0.0.1';
// LDAP server port to connect to
// Default: '389'
diff --git a/roles/webmail/files/etc/roundcube/plugins/thunderbird_labels/config.inc.php b/roles/webmail/files/etc/roundcube/plugins/thunderbird_labels/config.inc.php
new file mode 100644
index 0000000..2abb423
--- /dev/null
+++ b/roles/webmail/files/etc/roundcube/plugins/thunderbird_labels/config.inc.php
@@ -0,0 +1,5 @@
+<?php
+
+$rcmail_config['tb_label_enable'] = true;
+
+?>
diff --git a/roles/webmail/files/etc/systemd/system/stunnel4@ldap.socket b/roles/webmail/files/etc/systemd/system/stunnel4@ldap.socket
new file mode 100644
index 0000000..72aa82c
--- /dev/null
+++ b/roles/webmail/files/etc/systemd/system/stunnel4@ldap.socket
@@ -0,0 +1,11 @@
+[Unit]
+Description=SSL tunnel for network daemons (instance %i)
+Documentation=man:stunnel4(8)
+
+[Socket]
+BindToDevice=lo
+ListenStream=127.0.0.1:389
+NoDelay=yes
+
+[Install]
+WantedBy=sockets.target
diff --git a/roles/webmail/files/usr/share/roundcube/skins/classic/images/fripost_logo.png b/roles/webmail/files/usr/share/roundcube/program/resources/fripost_logo_black.png
index 7af586a..7af586a 100644
--- a/roles/webmail/files/usr/share/roundcube/skins/classic/images/fripost_logo.png
+++ b/roles/webmail/files/usr/share/roundcube/program/resources/fripost_logo_black.png
Binary files differ
diff --git a/roles/webmail/files/usr/share/roundcube/skins/larry/images/fripost_logo.png b/roles/webmail/files/usr/share/roundcube/program/resources/fripost_logo_white.png
index c581a30..c581a30 100644
--- a/roles/webmail/files/usr/share/roundcube/skins/larry/images/fripost_logo.png
+++ b/roles/webmail/files/usr/share/roundcube/program/resources/fripost_logo_white.png
Binary files differ
diff --git a/roles/webmail/handlers/main.yml b/roles/webmail/handlers/main.yml
index 446c771..8c70168 100644
--- a/roles/webmail/handlers/main.yml
+++ b/roles/webmail/handlers/main.yml
@@ -2,8 +2,14 @@
- name: Restart stunnel@ldap
service: name=stunnel4@ldap state=restarted
-- name: Restart php7.0-fpm
- service: name=php7.0-fpm state=restarted
+- name: Restart php7.4-fpm
+ service: name=php7.4-fpm state=restarted
- name: Restart Nginx
service: name=nginx state=restarted
+
+- name: Stop stunnel4@ldap.service
+ service: name=stunnel4@ldap.service state=stopped
+
+- name: Restart stunnel4@ldap.socket
+ service: name=stunnel4@ldap.socket state=restarted
diff --git a/roles/webmail/tasks/ldap.yml b/roles/webmail/tasks/ldap.yml
index b24860c..f0b461c 100644
--- a/roles/webmail/tasks/ldap.yml
+++ b/roles/webmail/tasks/ldap.yml
@@ -1,3 +1,12 @@
+- name: Copy stunnel4@ldap.socket
+ copy: src=etc/systemd/system/stunnel4@ldap.socket
+ dest=/etc/systemd/system/stunnel4@ldap.socket
+ owner=root group=root
+ mode=0644
+ notify:
+ - systemctl daemon-reload
+ - Restart stunnel4@ldap.socket
+
- name: Create /etc/stunnel/certs
file: path=/etc/stunnel/certs
state=directory
@@ -9,24 +18,19 @@
dest=/etc/stunnel/certs/ldap.pem
owner=root group=root
mode=0644
- register: r1
notify:
- - Restart stunnel@ldap
+ - Stop stunnel4@ldap.service
- name: Configure stunnel
- copy: src=etc/stunnel/ldap.conf
- dest=/etc/stunnel/ldap.conf
- owner=root group=root
- mode=0644
- register: r2
+ template: src=etc/stunnel/ldap.conf.j2
+ dest=/etc/stunnel/ldap.conf
+ owner=root group=root
+ mode=0644
notify:
- - Restart stunnel@ldap
-
-- name: Enable stunnel@ldap
- service: name=stunnel4@ldap enabled=yes
+ - Stop stunnel4@ldap.service
-- name: Start stunnel@ldap
- service: name=stunnel4@ldap state=started
- when: not (r1.changed or r2.changed)
+- name: Disable stunnel4@ldap.service
+ service: name=stunnel4@ldap.service enabled=false
-- meta: flush_handlers
+- name: Start stunnel4@ldap.socket socket
+ service: name=stunnel4@ldap.socket state=started enabled=true
diff --git a/roles/webmail/tasks/main.yml b/roles/webmail/tasks/main.yml
index 210d277..146c36f 100644
--- a/roles/webmail/tasks/main.yml
+++ b/roles/webmail/tasks/main.yml
@@ -1,5 +1,5 @@
- import_tasks: ldap.yml
- when: "'LDAP-provider' not in group_names"
+ when: "'LDAP_provider' not in group_names"
tags:
- ldap
- stunnel
diff --git a/roles/webmail/tasks/roundcube.yml b/roles/webmail/tasks/roundcube.yml
index b7678a3..bd174bc 100644
--- a/roles/webmail/tasks/roundcube.yml
+++ b/roles/webmail/tasks/roundcube.yml
@@ -9,22 +9,57 @@
# spell-checking
- php-enchant
-- name: Configure PHP 7.0 Zend opcache
- lineinfile: dest=/etc/php/7.0/fpm/php.ini
+## TODO: run php as a dedicated system user
+- name: Configure PHP 7.4 Zend opcache
+ lineinfile: dest=/etc/php/7.4/fpm/php.ini
regexp='^;?{{ item.var }}\\s*='
line="{{ item.var }} = {{ item.value }}"
owner=root group=root
mode=0644
with_items:
- - { var: opcache.enable, value: 1 }
- - { var: opcache.enable_cli, value: 1 }
- { var: opcache.memory_consumption, value: 128 }
- - { var: opcache.interned_strings_buffer, value: 8 }
- - { var: opcache.max_accelerated_files, value: 2048 }
- { var: opcache.revalidate_freq, value: 60 }
- - { var: opcache.fast_shutdown, value: 1 }
notify:
- - Restart php7.0-fpm
+ - Restart php7.4-fpm
+
+- name: Create '_roundcube' user
+ user: name=_roundcube system=yes
+ group=nogroup
+ createhome=no
+ home=/nonexistent
+ shell=/usr/sbin/nologin
+ password=!
+ state=present
+
+- name: Delete PHP 7.4 FPM's www pool
+ file: path=/etc/php/7.4/fpm/pool.d/www.conf state=absent
+ notify:
+ - Restart php7.4-fpm
+
+- name: Configure PHP 7.4 FPM's roundcube pool
+ copy: src=etc/php/fpm/pool.d/roundcube.conf
+ dest=/etc/php/7.4/fpm/pool.d/roundcube.conf
+ owner=root group=root
+ mode=0644
+ notify:
+ - Restart php7.4-fpm
+
+- name: Start php7.4-fpm
+ service: name=php7.4-fpm state=started
+
+# Make it sticky: `dpkg-statoverride --add _roundcube nogroup 0700 /var/lib/roundcube/temp`
+- name: Create cache directory /var/lib/roundcube/temp
+ file: path=/var/lib/roundcube/temp
+ state=directory
+ owner=_roundcube group=nogroup
+ mode=0700
+
+# Make it sticky: `dpkg-statoverride --add _roundcube adm 0750 /var/log/roundcube`
+- name: Create cache directory /var/log/roundcube
+ file: path=/var/log/roundcube
+ state=directory
+ owner=_roundcube group=adm
+ mode=0750
- name: Install GNU Aspell and some dictionaries
apt: pkg={{ packages }}
@@ -46,58 +81,65 @@
- roundcube-core
- roundcube-mysql
- roundcube-plugins
+ - roundcube-plugins-extra
+
+- name: Install plugin dependencies
+ apt: pkg={{ packages }}
+ vars:
+ packages:
- php-net-sieve
- - php-net-ldap3
- name: Copy fripost's logo
- copy: src=usr/share/roundcube/skins/{{ item }}/images/fripost_logo.png
- dest=/usr/share/roundcube/skins/{{ item }}/images/fripost_logo.png
+ copy: src=usr/share/roundcube/program/resources/{{ item }}
+ dest=/usr/share/roundcube/program/resources/{{ item }}
owner=root group=root
mode=0644
with_items:
- - classic
- - larry
+ - fripost_logo_black.png
+ - fripost_logo_white.png
- name: Configure Roundcube
lineinfile: dest=/etc/roundcube/config.inc.php
regexp='^\\s*\\$config\\[\'{{ item.var }}\'\\]\\s*='
line='$config[\'{{ item.var }}\'] = {{ item.value }};'
- owner=root group=www-data
- mode=0640
+ owner=_roundcube group=nogroup
+ mode=0600
with_items:
# Logging/Debugging
- { var: smtp_log, value: "false" }
# IMAP
# WARNING: After hostname change update of mail_host column in users
# table is required to match old user data records with the new host.
- - { var: default_host, value: "'{{ imapsvr_addr | ipaddr }}'" }
- - { var: default_port, value: "143" }
- - { var: imap_auth_type, value: "'PLAIN'" }
- - { var: imap_cache, value: "null" }
- - { var: imap_timeout, value: "180" }
- - { var: imap_force_ns, value: "true" }
- - { var: messages_cache, value: "false" }
+ - { var: default_host, value: "'{{ imapsvr_addr | ansible.utils.ipaddr }}'" }
+ - { var: default_port, value: "143" }
+ - { var: imap_auth_type, value: "'PLAIN'" }
+ - { var: imap_cache, value: "null" }
+ - { var: imap_timeout, value: "180" }
+ - { var: imap_force_ns, value: "true" }
+ - { var: messages_cache, value: "false" }
# SMTP
- - { var: smtp_server, value: "'{{ postfix_instance.MSA.addr | ipaddr }}'" }
- - { var: smtp_port, value: "{{ postfix_instance.MSA.port }}" }
- - { var: smtp_auth_type, value: "'PLAIN'" }
- - { var: smtp_user, value: "'%u'" }
- - { var: smtp_pass, value: "'%p'" }
+ - { var: smtp_server, value: "'{{ postfix_instance.MSA.addr | ansible.utils.ipaddr }}'" }
+ - { var: smtp_port, value: "{{ postfix_instance.MSA.port }}" }
+ - { var: smtp_auth_type, value: "'PLAIN'" }
+ - { var: smtp_user, value: "'%u'" }
+ - { var: smtp_pass, value: "'%p'" }
+ # avoid timeout
+ - { var: max_recipients, value: "15" }
# System
- - { var: force_https, value: "true" }
- - { var: login_autocomplete, value: "2" }
- - { var: skin_logo, value: "'/images/fripost_logo.png'" }
- - { var: username_domain, value: "'fripost.org'" }
- - { var: product_name, value: "'Fripost Webmail'" }
- - { var: password_charset, value: "'UTF-8'" }
+ - { var: force_https, value: "true" }
+ - { var: login_autocomplete, value: "2" }
+ - { var: username_domain, value: "'fripost.org'" }
+ - { var: product_name, value: "'Fripost Webmail'" }
+ - { var: password_charset, value: "'UTF-8'" }
+ - { var: skin_logo, value: 'array("classic:*" => "program/resources/fripost_logo_black.png", "larry:*" => "program/resources/fripost_logo_white.png", "elastic:login[favicon]" => "", "elastic:login" => "program/resources/fripost_logo_black.png")' }
# Plugins
- - { var: plugins, value: "array('archive','additional_message_headers','managesieve','password')" }
+ - { var: plugins, value: "array('archive','additional_message_headers','attachment_reminder','authres_status','emoticons','hide_blockquote','html5_notifier','managesieve','password','thunderbird_labels','vcard_attachments')" }
# Spell Checking
- { var: enable_spellcheck, value: "'true'" }
- { var: spellcheck_engine, value: "'enchant'" }
- { var: spellcheck_languages, value: "array('da','de','en','es','fr','no','sv')" }
# User Interface
- - { var: skin, value: "'larry'" }
+ - { var: skin, value: "'elastic'" }
- { var: language, value: "'sv_SE'" }
- { var: create_default_folders, value: "true" }
- { var: support_url, value: "'https://fripost.org/kontakt/'" }
@@ -105,17 +147,22 @@
- { var: htmleditor, value: "3" }
- { var: skip_deleted, value: "true" }
- { var: check_all_folders, value: "false" }
+ - { var: hide_blockquote_limit, value: "8" }
+ - { var: attachment_reminder, value: "true" }
+ # Don't allow overriding these settings
+ - { var: dont_override, value: "array('use_fallback_verifier', 'trusted_mtas')" }
- name: Make the logo a hyperlink to the website
lineinfile: dest=/usr/share/roundcube/skins/{{ item }}/templates/login.html
- regexp='^(<roundcube:object name="logo" src="/images/roundcube_logo.png"[^>]* />)$'
- line='<a href="https://fripost.org">\1</a>'
+ regexp='^(\s*)(<roundcube:object name="logo" src="[^"]*"[^>]* />)'
+ line='\1<a href="https://fripost.org">\2</a>'
backrefs=yes
owner=root group=root
mode=0644
with_items:
- classic
- larry
+ - elastic
- name: Configure Roundcube plugins
copy: src=etc/roundcube/plugins/{{ item }}/config.inc.php
@@ -124,8 +171,10 @@
mode=0644
with_items:
- additional_message_headers
- - jqueryui
+ - authres_status
- password
+ - html5_notifier
+ - thunderbird_labels
- name: Configure Roundcube plugins (2)
template: src=etc/roundcube/plugins/{{ item }}/config.inc.php.j2
@@ -135,8 +184,22 @@
with_items:
- managesieve
-- name: Start php7.0-fpm
- service: name=php7.0-fpm state=started
+- name: Start php7.4-fpm
+ service: name=php7.4-fpm state=started
+
+- name: Copy /etc/cron.d/roundcube-core
+ copy: src=etc/cron.d/roundcube-core
+ dest=/etc/cron.d/roundcube-core
+ owner=root group=root
+ mode=0644
+
+- name: Tweak /etc/logrotate.d/roundcube-core
+ lineinfile: dest=/etc/logrotate.d/roundcube-core
+ regexp='^(\s*)create\s+[0-9]+\s+\S+\s+adm$'
+ backrefs=yes
+ line='\1create 0640 _roundcube adm'
+ owner=root group=root
+ mode=0644
- name: Copy /etc/nginx/sites-available/roundcube
copy: src=etc/nginx/sites-available/roundcube
diff --git a/roles/webmail/templates/etc/roundcube/plugins/managesieve/config.inc.php.j2 b/roles/webmail/templates/etc/roundcube/plugins/managesieve/config.inc.php.j2
index 66af466..7b424e4 100644
--- a/roles/webmail/templates/etc/roundcube/plugins/managesieve/config.inc.php.j2
+++ b/roles/webmail/templates/etc/roundcube/plugins/managesieve/config.inc.php.j2
@@ -10,7 +10,7 @@ $config['managesieve_port'] = 4190;
// %n - http hostname ($_SERVER['SERVER_NAME'])
// %d - domain (http hostname without the first part)
// For example %n = mail.domain.tld, %d = domain.tld
-$config['managesieve_host'] = '{{ imapsvr_addr | ipaddr }}';
+$config['managesieve_host'] = '{{ imapsvr_addr | ansible.utils.ipaddr }}';
// authentication method. Can be CRAM-MD5, DIGEST-MD5, PLAIN, LOGIN, EXTERNAL
// or none. Optional, defaults to best method supported by server.
@@ -60,7 +60,7 @@ $config['managesieve_replace_delimiter'] = '';
// mailbox, mboxmetadata, regex, reject, relational, servermetadata,
// spamtest, spamtestplus, subaddress, vacation, variables, virustest, etc.
// Note: not all extensions are implemented
-$config['managesieve_disabled_extensions'] = array();
+$config['managesieve_disabled_extensions'] = array('reject','ereject');
// Enables debugging of conversation with sieve server. Logs it into <log_dir>/sieve
$config['managesieve_debug'] = false;
diff --git a/roles/webmail/files/etc/stunnel/ldap.conf b/roles/webmail/templates/etc/stunnel/ldap.conf.j2
index b8c7787..6fce2bc 100644
--- a/roles/webmail/files/etc/stunnel/ldap.conf
+++ b/roles/webmail/templates/etc/stunnel/ldap.conf.j2
@@ -2,11 +2,6 @@
; * Global options *
; **************************************************************************
-; setuid()/setgid() to the specified user/group in daemon mode
-setuid = stunnel4
-setgid = stunnel4
-
-; PID is created inside the chroot jail
pid =
foreground = yes
@@ -17,41 +12,30 @@ 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/stunnel/mail.pem
-;key = /etc/stunnel/mail.pem
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
+verifyPeer = yes
; Disable support for insecure protocols
-;options = NO_SSLv2
-options = NO_SSLv3
-options = NO_TLSv1
-options = NO_TLSv1.1
-
+sslVersionMin = TLSv1.2
options = NO_COMPRESSION
-; These options provide additional security at some performance degradation
-;options = SINGLE_ECDH_USE
-;options = SINGLE_DH_USE
-
; Select permitted SSL ciphers
-ciphers = EECDH+AESGCM:!MEDIUM:!LOW:!EXP:!aNULL:!eNULL
+ciphers = EECDH+AESGCM:EECDH+CHACHA20!MEDIUM!LOW!EXP!aNULL!eNULL
; **************************************************************************
; * Service definitions (remove all services for inetd mode) *
; **************************************************************************
[ldaps]
-accept = localhost:389
-connect = ldap.fripost.org:636
-CAfile = /etc/stunnel/certs/ldap.pem
+; dummy address (socket-activated)
+accept = 127.0.0.1:0
+connect = {{ ipsec[ hostvars[groups.LDAP_provider[0]].inventory_hostname_short ] }}:636
+checkHost = ldap.fripost.org
+CAfile = /etc/stunnel/certs/ldap.pem
; vim:ft=dosini
diff --git a/roles/wiki/files/etc/nginx/sites-available/website b/roles/wiki/files/etc/nginx/sites-available/website
index ba227e5..4aeb3db 100644
--- a/roles/wiki/files/etc/nginx/sites-available/website
+++ b/roles/wiki/files/etc/nginx/sites-available/website
@@ -5,7 +5,7 @@ server {
server_name fripost.org;
server_name www.fripost.org;
- include snippets/acme-challenge.conf;
+ include /etc/lacme/nginx.conf;
access_log /var/log/nginx/www.access.log;
error_log /var/log/nginx/www.error.log info;
@@ -28,35 +28,36 @@ server {
include snippets/headers.conf;
add_header Content-Security-Policy
- "default-src 'none'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self'; font-src 'self'; upgrade-insecure-requests; block-all-mixed-content; reflected-xss block; referrer no-referrer-when-downgrade; frame-ancestors 'none'; form-action https://www.paypal.com/; base-uri fripost.org www.fripost.org";
+ "default-src 'none'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; frame-ancestors 'none'; form-action https://www.paypal.com/; base-uri fripost.org www.fripost.org";
include snippets/ssl.conf;
ssl_certificate ssl/www.fripost.org.pem;
ssl_certificate_key ssl/www.fripost.org.key;
include snippets/fripost.org.hpkp-hdr;
+ gzip on;
+ gzip_vary on;
+ gzip_min_length 256;
+ gzip_types application/font-woff application/font-woff2 application/javascript application/json application/xml image/svg+xml image/x-icon text/css text/plain;
+
location / {
try_files $uri $uri/ =404;
index index.html;
root /var/lib/ikiwiki/public_html/fripost-wiki/website;
}
+ location = /ikiwiki.cgi { internal; }
location /static/ {
- alias /var/lib/ikiwiki/public_html/fripost-wiki/static/;
expires 30d;
+ try_files $uri =404;
+ alias /var/lib/ikiwiki/public_html/fripost-wiki/static/;
}
location /material/ {
alias /var/www/fripost.org/material/;
- expires 30d;
}
location /minutes/ {
alias /var/www/fripost.org/minutes/;
- expires 30d;
}
location /.well-known/autoconfig/ {
alias /var/www/fripost.org/autoconfig/;
}
-
- location = /ikiwiki.cgi {
- return 403;
- }
}
diff --git a/roles/wiki/files/etc/nginx/sites-available/wiki b/roles/wiki/files/etc/nginx/sites-available/wiki
index 7759fa5..b201ef5 100644
--- a/roles/wiki/files/etc/nginx/sites-available/wiki
+++ b/roles/wiki/files/etc/nginx/sites-available/wiki
@@ -4,7 +4,7 @@ server {
server_name wiki.fripost.org;
- include snippets/acme-challenge.conf;
+ include /etc/lacme/nginx.conf;
access_log /var/log/nginx/wiki.access.log;
error_log /var/log/nginx/wiki.error.log info;
@@ -27,26 +27,33 @@ server {
include snippets/headers.conf;
add_header Content-Security-Policy
- "default-src 'none'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self'; font-src 'self'; upgrade-insecure-requests; block-all-mixed-content; reflected-xss block; referrer no-referrer-when-downgrade; frame-ancestors 'none'; form-action 'self'; base-uri wiki.fripost.org";
+ "default-src 'none'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; frame-ancestors 'none'; form-action 'self'; base-uri wiki.fripost.org";
include snippets/ssl.conf;
ssl_certificate ssl/www.fripost.org.pem;
ssl_certificate_key ssl/www.fripost.org.key;
include snippets/fripost.org.hpkp-hdr;
+ gzip on;
+ gzip_vary on;
+ gzip_min_length 256;
+ gzip_types application/font-woff application/font-woff2 application/javascript application/json application/xml image/svg+xml image/x-icon text/css text/plain;
+
+ root /var/lib/ikiwiki/public_html/fripost-wiki;
+
+ location /static/ { expires 30d; try_files $uri =404; }
location / {
location ~ ^/website(/.*)?$ { return 302 $scheme://fripost.org$1; }
- try_files $uri $uri/ =404;
index index.html;
- root /var/lib/ikiwiki/public_html/fripost-wiki;
+ try_files $uri $uri/ =404;
}
location = /ikiwiki.cgi {
- fastcgi_param DOCUMENT_ROOT /var/lib/ikiwiki/public_html/fripost-wiki;
+ fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_param SCRIPT_FILENAME /var/lib/ikiwiki/public_html/ikiwiki.cgi;
fastcgi_index ikiwiki.cgi;
include snippets/fastcgi.conf;
- fastcgi_pass unix:/var/run/fcgiwrap.socket;
- gzip off;
+ fastcgi_pass unix:/run/ikiwiki.socket;
+ gzip off; # protect against BREACH
}
}
diff --git a/roles/wiki/files/etc/systemd/system/ikiwiki.service b/roles/wiki/files/etc/systemd/system/ikiwiki.service
new file mode 100644
index 0000000..3ee7d66
--- /dev/null
+++ b/roles/wiki/files/etc/systemd/system/ikiwiki.service
@@ -0,0 +1,23 @@
+[Unit]
+Description=wiki compiler (CGI script)
+Documentation=https://ikiwiki.info/
+
+[Service]
+User=ikiwiki
+Group=ikiwiki
+ExecStart=/usr/sbin/fcgiwrap
+SyslogIdentifier=ikiwiki
+#
+# Hardening
+NoNewPrivileges=yes
+ReadWriteDirectories=/var/lib/ikiwiki/fripost-wiki
+ReadWriteDirectories=/var/lib/ikiwiki/public_html/fripost-wiki
+PrivateDevices=yes
+ProtectHome=yes
+ProtectSystem=strict
+ProtectControlGroups=yes
+ProtectKernelModules=yes
+ProtectKernelTunables=yes
+
+[Install]
+WantedBy=multi-user.target
diff --git a/roles/wiki/files/etc/systemd/system/ikiwiki.socket b/roles/wiki/files/etc/systemd/system/ikiwiki.socket
new file mode 100644
index 0000000..8dc1a0e
--- /dev/null
+++ b/roles/wiki/files/etc/systemd/system/ikiwiki.socket
@@ -0,0 +1,11 @@
+[Unit]
+Description=wiki compiler (CGI script)
+Documentation=https://ikiwiki.info/
+
+[Socket]
+ListenStream=%t/ikiwiki.socket
+SocketUser=www-data
+SocketMode=0600
+
+[Install]
+WantedBy=sockets.target
diff --git a/roles/wiki/files/var/lib/ikiwiki/IkiWiki/Plugin/pandoc.pm b/roles/wiki/files/var/lib/ikiwiki/IkiWiki/Plugin/pandoc.pm
index 25081ef..34bdd89 100644
--- a/roles/wiki/files/var/lib/ikiwiki/IkiWiki/Plugin/pandoc.pm
+++ b/roles/wiki/files/var/lib/ikiwiki/IkiWiki/Plugin/pandoc.pm
@@ -21,6 +21,23 @@ my %extra_formats = (
latex => { ext=>'tex', label=>'LaTeX', format=>'latex', extra=>['--standalone'], order=>7 },
);
+my @scalar_meta_keys = qw/
+ title date bibliography csl subtitle abstract summary description
+ version lang locale titlesort tag fripost_debug_inner
+ /;
+
+my @list_meta_keys = qw/
+ author
+ /;
+
+my @hash_meta_keys = qw/
+ experiment
+ /;
+
+my @list_hash_meta_keys = qw/
+ references
+ /;
+
sub import {
my $markdown_ext = $config{pandoc_markdown_ext} || "mdwn";
@@ -96,6 +113,13 @@ sub getsetup () {
safe => 1,
rebuild => 1,
},
+ pandoc_markdown_fmt => {
+ type => "string",
+ example => "markdown",
+ description => "Format string to use when processing files handled by Pandoc.",
+ safe => 1,
+ rebuild => 1,
+ },
pandoc_latex => {
type => "boolean",
example => 0,
@@ -409,10 +433,11 @@ sub htmlize ($@) {
# can be parsed out
# We must omit the 'bibliography' parameter here, otherwise the list of
# references will be doubled.
+ my $markdown_fmt = $config{pandoc_markdown_fmt} || 'markdown';
my $to_json_pid = open2(*JSON_OUT, *PANDOC_OUT, $command,
- '-f', $format,
+ '-f', $markdown_fmt,
'-t', 'json',
- @args, '--normalize');
+ @args);
error("Unable to open $command") unless $to_json_pid;
# Workaround for perl bug (#376329)
@@ -435,8 +460,8 @@ sub htmlize ($@) {
my $meta = undef;
my $decoded_json = decode_json($json_content);
# The representation of the meta block changed in pandoc version 1.18
- if (ref $decoded_json eq 'HASH' && $decoded_json->{'Meta'}) {
- $meta = $decoded_json->{'Meta'} || {}; # post-1.18 version
+ if (ref $decoded_json eq 'HASH' && $decoded_json->{'meta'}) {
+ $meta = $decoded_json->{'meta'} || {}; # post-1.18 version
} elsif (ref $decoded_json eq 'ARRAY') {
$meta = $decoded_json->[0]->{'unMeta'} || {}; # pre-1.18 version
}
@@ -450,12 +475,11 @@ sub htmlize ($@) {
# as well as some configuration options (generate_*, *_extra_options, *_template).
my @format_keys = grep { $_ ne 'pdf' } keys %extra_formats;
- my %scalar_meta = map { ($_=>undef) } qw(
- title date bibliography csl subtitle abstract summary
- description version lang locale);
+ my %scalar_meta = map { ($_=>undef) } @scalar_meta_keys;
$scalar_meta{$_.'_template'} = undef for @format_keys;
my %bool_meta = map { ("generate_$_"=>0) } keys %extra_formats;
- my %list_meta = map { ($_=>[]) } qw/author references/;
+ my %list_meta = map { ($_=>[]) } (
+ @list_meta_keys, @list_hash_meta_keys, @hash_meta_keys);
$list_meta{$_.'_extra_options'} = [] for @format_keys;
my $have_bibl = 0;
foreach my $k (keys %scalar_meta) {
@@ -484,6 +508,7 @@ sub htmlize ($@) {
$list_meta{$k} = unwrap_c($meta->{$k});
$list_meta{$k} = [$list_meta{$k}] unless ref $list_meta{$k} eq 'ARRAY';
$have_bibl = 1 if $k eq 'references';
+ $pagestate{$page}{meta}{$k} = $list_meta{$k};
$pagestate{$page}{meta}{"pandoc_$k"} = $list_meta{$k};
}
# Try to add other keys as scalars, with pandoc_ prefix only.
@@ -596,9 +621,14 @@ sub pagetemplate (@) {
my $page = $params{page};
my $template = $params{template};
foreach my $k (keys %{$pagestate{$page}{meta}}) {
- next unless $k =~ /^pandoc_/;
+ next unless
+ (grep {/^$k$/} (
+ @scalar_meta_keys, @list_meta_keys,
+ @hash_meta_keys, @list_hash_meta_keys)) ||
+ ($k =~ /^(pandoc_)/);
$template->param($k => $pagestate{$page}{meta}{$k});
}
+ return $template;
}
sub pageactions {
@@ -757,6 +787,11 @@ sub unwrap_c {
# Finds the deepest-level scalar value for 'c' in the data structure.
# Lists with one element are replaced with the scalar, lists with more
# than one element are returned as an arrayref containing scalars.
+ #
+ # Elements containing hash as keys are unwrapped. That is to
+ # support *MetaList* containing *MetaMap* with keys pointing to
+ # *MetaInlines*. Reference are examples of that structure. (hash unwrap)
+ #
my $container = shift;
if (ref $container eq 'ARRAY' && @$container > 1) {
if (ref $container->[0] eq 'HASH' && $container->[0]->{t} =~ /^(?:Str|Space)$/) {
@@ -771,6 +806,8 @@ sub unwrap_c {
return;
} elsif (ref $container eq 'HASH' && $container->{c}) {
return unwrap_c($container->{c});
+ } elsif (ref $container eq 'HASH' && keys $container->%*) { # (hash unwrap)
+ return {map { $_ => unwrap_c($container->{$_}) } keys $container->%*};
} elsif (ref $container) {
return;
} else {
diff --git a/roles/wiki/files/var/lib/ikiwiki/fripost-wiki.setup b/roles/wiki/files/var/lib/ikiwiki/fripost-wiki.setup
index 4353965..4af3d59 100644
--- a/roles/wiki/files/var/lib/ikiwiki/fripost-wiki.setup
+++ b/roles/wiki/files/var/lib/ikiwiki/fripost-wiki.setup
@@ -31,7 +31,7 @@ reverse_proxy: 0
# filename of cgi wrapper to generate
cgi_wrapper: /var/lib/ikiwiki/public_html/ikiwiki.cgi
# mode for cgi_wrapper (can safely be made suid)
-cgi_wrappermode: 06755
+cgi_wrappermode: 0755
# number of seconds to delay CGI requests when overloaded
cgi_overload_delay: ''
# message to display when overloaded (may contain html)
@@ -416,5 +416,4 @@ getsource_mimetype: text/plain; charset=utf-8
#tag_autocreate_commit: 1
# pandoc plugin
-pandoc_smart: 1
pandoc_html5: 1
diff --git a/roles/wiki/handlers/main.yml b/roles/wiki/handlers/main.yml
index 109c63d..ac9ad2b 100644
--- a/roles/wiki/handlers/main.yml
+++ b/roles/wiki/handlers/main.yml
@@ -5,3 +5,12 @@
- name: Refresh ikiwiki
become_user: ikiwiki
command: ikiwiki --setup /var/lib/ikiwiki/fripost-wiki.setup --refresh --wrappers
+
+- name: systemctl daemon-reload
+ command: /bin/systemctl daemon-reload
+
+- name: Stop ikiwiki
+ service: name=ikiwiki.service state=stopped
+
+- name: Restart ikiwiki
+ service: name=ikiwiki.socket state=restarted
diff --git a/roles/wiki/tasks/main.yml b/roles/wiki/tasks/main.yml
index 718b433..74c11f8 100644
--- a/roles/wiki/tasks/main.yml
+++ b/roles/wiki/tasks/main.yml
@@ -11,6 +11,16 @@
- libnet-dns-sec-perl
- fcgiwrap
- pandoc
+ ###
+ - fonts-font-awesome
+ - libjs-bootstrap4
+ - libjs-jquery
+
+- name: Stop and disable fcgiwrap socket
+ service: name=fcgiwrap.socket state=stopped enabled=false
+
+- name: Stop fcgiwrap service
+ service: name=fcgiwrap.service state=stopped
- name: Create a user 'ikiwiki'
user: name=ikiwiki system=yes
@@ -21,9 +31,6 @@
generate_ssh_key=yes
ssh_key_comment=ikiwiki@{{ ansible_fqdn }}
-- name: Add 'www-data' to the group 'ikiwiki'
- user: name=www-data groups=ikiwiki append=yes
-
- name: Create directory ~ikiwiki/IkiWiki/Plugin
file: path=/var/lib/ikiwiki/IkiWiki/Plugin
state=directory
@@ -70,6 +77,32 @@
- meta: flush_handlers
+- name: Copy ikiwiki service unit
+ copy: src=etc/systemd/system/ikiwiki.service
+ dest=/etc/systemd/system/ikiwiki.service
+ owner=root group=root
+ mode=0644
+ notify:
+ - systemctl daemon-reload
+ - Stop ikiwiki
+
+- name: Copy ikiwiki socket unit
+ copy: src=etc/systemd/system/ikiwiki.socket
+ dest=/etc/systemd/system/ikiwiki.socket
+ owner=root group=root
+ mode=0644
+ notify:
+ - systemctl daemon-reload
+ - Restart ikiwiki
+
+- name: Disable ikiwiki service
+ service: name=ikiwiki.service enabled=false
+
+- name: Start ikiwiki socket
+ service: name=ikiwiki.socket state=started enabled=true
+
+- meta: flush_handlers
+
- name: Copy /etc/nginx/sites-available/{wiki,website}
copy: src=etc/nginx/sites-available/{{ item }}
dest=/etc/nginx/sites-available/{{ item }}