X-Git-Url: https://iankelling.org/git/?a=blobdiff_plain;f=mail-setup;h=5166faa3a44e1a9009368ee48d9a989cfe3272d2;hb=802e885e3e7fa3857f8bc4f54c261d5ca76f2454;hp=5c5ccae88509f5b3f27badec8d96c92eefb94bad;hpb=4e735a2e1807351e4a11f2fe4cda427e18e0d550;p=distro-setup diff --git a/mail-setup b/mail-setup index 5c5ccae..5166faa 100755 --- a/mail-setup +++ b/mail-setup @@ -3,16 +3,12 @@ # Copyright (C) 2019 Ian Kelling # SPDX-License-Identifier: AGPL-3.0-or-later -# todo: sandbox / harden exim: -# 1. stop it from running as root. how? -# https://www.exim.org/exim-html-current/doc/html/spec_html/ch-security_considerations.html -# * avoid using .forward files, remove that router -# * set deliver_drop_privilege -# * set user to run as Debian-exim in systemd -# * set port to something like 2500, and forward 25 to 2500 with iptables. same for 587. -# https://superuser.com/questions/710253/allow-non-root-process-to-bind-to-port-80-and-443/1334552#1334552 -# * consider whether other routers like postmaster need modification / removal. -# 2. restrict its filesystem access from within systemd + +# todo: add a prometheus alert for dovecot. + +# todo: handle errors like this: +# Mar 02 12:44:26 kw systemd[1]: exim4.service: Found left-over process 68210 (exim4) in control group while starting unit. Ignoring. +# Mar 02 12:44:26 kw systemd[1]: This usually indicates unclean termination of a previous run, or service implementation deficiencies. # todo: harden dovecot. need to do some research. one way is for it to only listen on a wireguard vpn interface, so only clients that are on the vpn can access it. # todo: consider hardening cups listening on 0.0.0.0 @@ -26,13 +22,9 @@ # todo: emailing info@amnimal.ninja produces a bounce, user doesn't exist # instead of a simple rejection like it should. -# todo: auto restart of je on checkrestart - # todo: run mailping test after running, or otherwise # clear out terminal alert -# todo: reinstall bk with bigger filesystem - # todo: on bk, dont send email if mailvpn is not up # todo: mailtest-check should check on bk too @@ -149,7 +141,7 @@ fi [[ $EUID == 0 ]] || exec sudo -E "${BASH_SOURCE[0]}" "$@" - +# note, this is hardcoded in /etc/exim4/conf.d/main/000_local u=$(id -nu 1000) @@ -178,9 +170,10 @@ fi # background: dovecot does not yet have ocsp stapling support # reference: https://community.letsencrypt.org/t/simple-guide-using-lets-encrypt-ssl-certs-with-dovecot/2921 # -# for phone, k9mail, same thing but username alerts, pass in ivy-pass. +# for phone, k9mail, fdroid, same thing but username alerts, pass in ivy-pass. # also, bk.b8.nz for secondary alerts, username is iank. same alerts pass. -# fetching mail settings: folder poll frequency 10 minutes +# fetching mail settings: folder poll frequency 10 minutes. +# account settings, fetching mail, push folders: All. Then disable the persistent notification. ####### @@ -292,7 +285,10 @@ fi i() { # install file local tmp tmpdir dest="$1" local base="${dest##*/}" - mkdir -p ${dest%/*} + local dir="${dest%/*}" + if [[ $dir != "$base" ]]; then + mkdir -p ${dest%/*} + fi ir=false # i result tmpdir=$(mktemp -d) cat >$tmpdir/"$base" @@ -378,7 +374,7 @@ esac # * Install universal packages -# installs epanicclean +# installs epanicclean iptables-exim ip6tables-exim /a/bin/ds/install-my-scripts if [[ $(debian-codename-compat) == bionic ]]; then @@ -390,11 +386,16 @@ EOF fi # light version of exim does not have sasl auth support. -pi-nostart exim4 exim4-daemon-heavy spamassassin openvpn unbound clamav-daemon wireguard +pi-nostart exim4 exim4-daemon-heavy spamassassin unbound clamav-daemon wireguard # note: pyzor debian readme says you need to run some initialization command # but its outdated. -pi spf-tools-perl p0f postgrey pyzor razor jq moreutils certbot +pi spf-tools-perl p0f postgrey pyzor razor jq moreutils certbot fail2ban +case $HOSTNAME in + je) : ;; + # not included due to using wireguard: openvpn + *) pi wget git unzip iptables ;; +esac # bad packages that sometimes get automatically installed pu openresolv resolvconf @@ -489,14 +490,17 @@ case $HOSTNAME in i /etc/systemd/system/wg-quick@wgmail.service.d/override.conf <&2 - exit 1 - fi - ;; -esac + +# With openvpn, I didn't get around to persisting the openvpn +# cert/configs into /p/c/machine_specific/bk, so I had this case to +# manually get the cert. However, we aren't using openvpn anymore, so it +# is commented out. +# +# case $HOSTNAME in +# bk) +# if [[ ! -e /etc/openvpn/client/mail.conf ]]; then +# echo "$0: error: first, on a system with /p/c/filesystem, run mail-setup, or the vpn-mk-client-cert line above this err" 2>&2 +# exit 1 +# fi +# ;; +# esac m rsync -aiSAX --chown=root:root --chmod=g-s /a/bin/ds/mail-cert-cron /usr/local/bin @@ -829,6 +840,121 @@ if $bhost_t && [[ ! -e /etc/exim4/certs/$wghost/privkey.pem ]]; then --deploy-hook /a/bin/ds/le-exim-deploy -d $wghost fi +# * fail2ban + +# todo: test that these configs actually work, eg run +# s iptables-exim -S +# and see someone is banned. + +sed 's/^ *before *= *iptables-common.conf/before = iptables-common-exim.conf/' \ + /etc/fail2ban/action.d/iptables-multiport.conf| i /etc/fail2ban/action.d/iptables-exim.conf +i /etc/fail2ban/action.d/iptables-common-exim.conf <<'EOF' +# iank: same as iptables-common, except iptables is iptables-exim, ip6tables is ip6tables-exim + +# Fail2Ban configuration file +# +# Author: Daniel Black +# +# This is a included configuration file and includes the definitions for the iptables +# used in all iptables based actions by default. +# +# The user can override the defaults in iptables-common.local +# +# Modified: Alexander Koeppe , Serg G. Brester +# made config file IPv6 capable (see new section Init?family=inet6) + +[INCLUDES] + +after = iptables-blocktype.local + iptables-common.local +# iptables-blocktype.local is obsolete + +[Definition] + +# Option: actionflush +# Notes.: command executed once to flush IPS, by shutdown (resp. by stop of the jail or this action) +# Values: CMD +# +actionflush = -F f2b- + + +[Init] + +# Option: chain +# Notes specifies the iptables chain to which the Fail2Ban rules should be +# added +# Values: STRING Default: INPUT +chain = INPUT + +# Default name of the chain +# +name = default + +# Option: port +# Notes.: specifies port to monitor +# Values: [ NUM | STRING ] Default: +# +port = ssh + +# Option: protocol +# Notes.: internally used by config reader for interpolations. +# Values: [ tcp | udp | icmp | all ] Default: tcp +# +protocol = tcp + +# Option: blocktype +# Note: This is what the action does with rules. This can be any jump target +# as per the iptables man page (section 8). Common values are DROP +# REJECT, REJECT --reject-with icmp-port-unreachable +# Values: STRING +blocktype = REJECT --reject-with icmp-port-unreachable + +# Option: returntype +# Note: This is the default rule on "actionstart". This should be RETURN +# in all (blocking) actions, except REJECT in allowing actions. +# Values: STRING +returntype = RETURN + +# Option: lockingopt +# Notes.: Option was introduced to iptables to prevent multiple instances from +# running concurrently and causing irratic behavior. -w was introduced +# in iptables 1.4.20, so might be absent on older systems +# See https://github.com/fail2ban/fail2ban/issues/1122 +# Values: STRING +lockingopt = -w + +# Option: iptables +# Notes.: Actual command to be executed, including common to all calls options +# Values: STRING +iptables = /usr/local/bin/iptables-exim + + +[Init?family=inet6] + +# Option: blocktype (ipv6) +# Note: This is what the action does with rules. This can be any jump target +# as per the iptables man page (section 8). Common values are DROP +# REJECT, REJECT --reject-with icmp6-port-unreachable +# Values: STRING +blocktype = REJECT --reject-with icmp6-port-unreachable + +# Option: iptables (ipv6) +# Notes.: Actual command to be executed, including common to all calls options +# Values: STRING +iptables = /usr/local/bin/ip6tables-exim +EOF + +i /etc/fail2ban/jail.d/exim.local <<'EOF' +[exim] +enabled = true +port = 25,587 +filter = exim +banaction = iptables-exim +EOF +if $ir; then + m systemctl restart fail2ban +fi + # * common exim4 config @@ -897,16 +1023,24 @@ if (( ${#files[@]} )); then ${files[@]} /etc/exim4 fi -# by default, only 10 days of logs are kept. increase that. -m sed -ri 's/^(\s*rotate\s).*/\11000/' /etc/logrotate.d/exim4-base - +# By default, only 10 days of logs are kept. increase that. +# And dont compress, I look back at logs too often and +# dont need the annoyance of decompressing them all the time. +m sed -ri '/^\s*compress\s*$/d;s/^(\s*rotate\s).*/\11000/' /etc/logrotate.d/exim4-base +files=(/var/log/exim4/*.gz) +if (( ${#files[@]} )); then + gunzip ${files[@]} +fi -## https://blog.dhampir.no/content/make-exim4-on-debian-respect-forward-and-etcaliases-when-using-a-smarthost -# i only need .forwards, so just doing that one. -cd /etc/exim4/conf.d/router -b=userforward_higher_priority -# replace the router name so it is unique -sed -r s/^\\S+:/$b:/ 600_exim4-config_userforward >175_$b +## disabled. not using .forward files, but this is still interesting +## for reference. +# ## https://blog.dhampir.no/content/make-exim4-on-debian-respect-forward-and-etcaliases-when-using-a-smarthost +# # i only need .forwards, so just doing that one. +# cd /etc/exim4/conf.d/router +# b=userforward_higher_priority +# # replace the router name so it is unique +# sed -r s/^\\S+:/$b:/ 600_exim4-config_userforward >175_$b +rm -fv /etc/exim4/conf.d/router/175_userforward_higher_priority # todo, consider 'separate' in etc/exim4.conf, could it help on busy systems? @@ -931,11 +1065,30 @@ expertpathologyreview.com * F,1d,10m;F,14d,1h je.b8.nz * F,1d,10m;F,14d,1h zroe.org * F,1d,10m;F,14d,1h eximbackup.b8.nz * F,1d,4m;F,14d,1h + +# The spec says the target domain will be used for temporary host errors, +# but i've found that isn't correct, the hostname is required +# at least sometimes. +nn.b8.nz * F,1d,4m;F,14d,1h +defaultnn.b8.nz * F,1d,4m;F,14d,1h +mx.iankelling.org * F,1d,4m;F,14d,1h +bk.b8.nz * F,1d,4m;F,14d,1h +eggs.gnu.org * F,1d,4m;F,14d,1h +mail.fsf.org * F,1d,15m;F,14d,1h EOF rm -vf /etc/exim4/conf.d/main/000_localmacros # old filename -cat >/etc/exim4/conf.d/main/000_local </etc/exim4/conf.d/main/000_local2 </etc/exim4/conf.d/main/000_local <<'EOF' MAIN_TLS_ENABLE = true # require tls connections for all smarthosts @@ -957,11 +1110,6 @@ MAIN_LOG_SELECTOR = +all # Based on spec, seems like a good idea to be nice. smtp_return_error_details = true -# normally empty, I set this so I can set the envelope address -# when doing mail redelivery to invoke filters. Also allows -# me exiqgrep and stuff. -MAIN_TRUSTED_GROUPS = $u - # default is 10. when exim has been down for a bit, fsf mailserver # will do a big send in one connection, then exim decides to put # the messages in the queue instead of delivering them, to avoid @@ -980,10 +1128,10 @@ DKIM_SELECTOR = li # There could be some circumstance when the # from: isnt our domain, but the envelope sender is # and so still want to sign, but I cant think of any case. -DKIM_DOMAIN = \${lc:\${domain:\$rh_from:}} +DKIM_DOMAIN = ${lc:${domain:$rh_from:}} # The file is based on the outgoing domain-name in the from-header. # sign if key exists -DKIM_PRIVATE_KEY = \${if exists{/etc/exim4/\${dkim_domain}-private.pem} {/etc/exim4/\${dkim_domain}-private.pem}} +DKIM_PRIVATE_KEY = ${if exists{/etc/exim4/${dkim_domain}-private.pem} {/etc/exim4/${dkim_domain}-private.pem}} # most of the ones that gmail seems to use. # Exim has horrible default of signing unincluded @@ -1007,6 +1155,19 @@ hostlist iank_trusted = <; \\ 85.119.82.128 ; 2001:ba8:1f1:f09d::2 ; \\ # fsf_mit_net fsf_mit_net_ip6 fsf_net fsf_net_ip6 fsf_office_net 18.4.89.0/24 ; 2603:3005:71a:2e00::/64 ; 209.51.188.0/24 ; 2001:470:142::/48 ; 74.94.156.208/28 + + +# this is the default delay_warning_condition, plus matching on local_domains. +# If I have some problem with my local system that causes delayed delivery, +# I dont want to send warnings out to non-local domains. +delay_warning_condition = ${if or {\ + { !eq{$h_list-id:$h_list-post:$h_list-subscribe:}{} }\ + { match{$h_precedence:}{(?i)bulk|list|junk} }\ + { match{$h_auto-submitted:}{(?i)auto-generated|auto-replied} }\ + { match_domain{$domain}{+local_domains} }\ + } {no}{yes}} + + EOF rm -fv /etc/exim4/rcpt_local_acl # old path @@ -1066,14 +1227,14 @@ warn EOF -i /etc/exim4/conf.d/router/900_exim4-config_local_user <config.php - m rm tmp.php + m rm -f tmp.php m sudo -u www-data php $ncdir/occ maintenance:update:htaccess list=$(sudo -u www-data php $ncdir/occ --output=json_pretty app:list) # user_external not compaible with nc 23 @@ -2129,11 +2296,12 @@ For logs, run: jr -u $ncbase EOF fi EOFOUTER + chmod +x /usr/local/bin/ncup mkdir -p /var/www/cron-errors chown www-data.www-data /var/www/cron-errors i /etc/cron.d/$ncbase < /etc/mailname - /a/exe/cedit nn /etc/hosts <<'EOF' || [[ $? == 1 ]] 10.173.8.2 nn.b8.nz EOF @@ -2572,9 +2791,10 @@ COMMONOPTIONS='-oP /run/exim4/eximin.pid' UPEX4OPTS='-d /etc/myexim4' EOF + echo bk.b8.nz > /etc/mailname cat >>/etc/exim4/update-exim4.conf.conf </dev/null; then m systemctl --now enable clamav-daemon - out=$(rsync -aiSAX --chown=root:root --chmod=g-s /a/bin/ds/filesystem/etc/systemd/system/epanicclean.{timer,service} /etc/systemd/system) + out=$(rsync -aiSAX --chown=root:root --chmod=g-s /a/bin/ds/filesystem/etc/systemd/system/epanicclean.service /etc/systemd/system) if [[ $out ]]; then reload=true fi @@ -2878,7 +3096,10 @@ rm -f /var/local/mail-setup-reload case $HOSTNAME in - $MAIL_HOST|bk|je) : ;; + $MAIL_HOST|bk|je|li) + # on li, these are never started, except $vpnser + : + ;; *) soff radicale mailclean.timer dovecot spamassassin $vpnser mailnn clamav-daemon ;; @@ -2913,14 +3134,12 @@ case $HOSTNAME in cat >/etc/cron.d/mailtest <>/etc/cron.d/mailtest </usr/local/bin/send-test-forward <<'EOF' #!/bin/bash olds=( -$(/sbin/exiqgrep -o 260 -i -r '^(testignore@(iankelling\.org|zroe\.org|expertpathologyreview\.com|amnimal\.ninja|je\.b8\.nz)|jtuttle@gnu\.org)$') +$(/usr/sbin/exiqgrep -o 260 -i -r '^(testignore@(iankelling\.org|zroe\.org|expertpathologyreview\.com|amnimal\.ninja|je\.b8\.nz)|jtuttle@gnu\.org)$') ) if (( ${#olds[@]} )); then - /sbin/exim -Mrm "${olds[@]}" >/dev/null + /usr/sbin/exim -Mrm "${olds[@]}" >/dev/null fi EOF for test_from in ${test_froms[@]}; do