diff options
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: @@ -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.pngBinary files differ 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 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.pngBinary files differ 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 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 }} | 
