Wednesday, May 23, 2018

GDPR or AVG - regain control Part 2: Your Own Mail


Create your own mail server

Drop Yahoo, Google or Microsoft mail - they are reading your mail.

Debian, Postfix, Dovecot, MariaDb, rspamd

This is the second (and last) part of setting up your own internet tools in order to gain back control. Goal is to set up an email server (receive and send), secure it, and filter spam.

Hardware considerations

I used an abandoned ASRock ION330, where I replaced the 5400rpm harddisk for a SSD. I planned using an ODroid C2, but could not get rspamd running within a reasonable amount of time (days, that is...). The SSD is small, by today's standards, but 120GB is plenty of mail. YMMV, adapt storage to your needs.
A colleague had some RAM laying around, so I have an ION330 with maxed out RAM: 4GB...

Basic setup

This time no Etcher, but a bootable CD. Download Debian (debian-9.4.0-amd64-netinst.iso), burn it to CD, and boot from it.
Install, uncheck all options when selecting what to install. Set a root password.

Let's get cracking: security!

Basically, follow the instructions of the previous entry regarding setting up daily users, not allowing password based logins and prohibiting root logins.
You may have to install sudo:
su - apt update && apt upgrade -y && apt dist-upgrade apt install openssh-server sudo -y visodo
change:
# User privilege specification
root ALL=(ALL:ALL) ALL

to
# User privilege specification
root ALL=(ALL:ALL) ALL
frank ALL=(ALL:ALL) ALL

Save (Ctrl-X, return).
Logout of the elevated Super User (su) session (Ctrl-D), and type:
sudo apt update
You should be asked for your own(not root) password, and apt should be executed. You are now sudo'ed.

Security: enable logins over SSH

Installing the latest ssh server version is easier than with Ubuntu:
sudo -s cd /usr/local/src wget http://ftp.nl.debian.org/debian/pool/main/o/openssl/libssl1.1_1.1.0h-2_amd64.deb dpkg -i ./libssl1.1_1.1.0h-2_amd64.deb wget http://ftp.nl.debian.org/debian/pool/main/o/openssl/openssl_1.1.0h-2_amd64.deb dpkg -i openssl_1.1.0h-2_amd64.deb
You should do this before generating long keys, etc.

Your internet exposure

As a result of the previous entry, you have a contract with Domain Registrar. Your IPv4 (A record) and IPv6 (AAAA record) addresses point to [YOUR.DOMAIN], www.[YOUR.DOMAIN] and cloud.[YOUR.DOMAIN].
Now it is time to add your mail exchange (MX) record, and the IPv4 (A) and IPv6 (AAAA) records for your mail server. Your referrals should look like this example zone file:
. # General referral for your TLD to a mail server: [YOUR.DOMAIN]. 86400 IN MX 0 mail.[YOUR.DOMAIN]. # mail server itself should have IPv4 and IPv6 addresses: mail.[YOUR.DOMAIN]. 3600 IN A 11.22.33.999 mail.[YOUR.DOMAIN]. 3600 IN AAAA 2001:aa:bbcc:1:2:ff:43:1234 # Often used aliases, based on protocol: smtp.[YOUR.DOMAIN]. 86400 IN CNAME mail.[YOUR.DOMAIN]. imap.[YOUR.DOMAIN]. 86400 IN CNAME mail.[YOUR.DOMAIN]. # DMARC protection. Generate your own at https://elasticemail.com/dmarc based on your liking _dmarc.[YOUR.DOMAIN]. 3600 IN TXT "v=DMARC1\; p=reject\; rua=mailto:postmaster@[YOUR.DOMAIN]\; aspf=s\; adkim=s\;" # SPF - nice try to avaoid spam [YOUR.DOMAIN]. 3600 IN TXT "v=spf1 a:mail.[YOUR.DOMAIN] ?all"
The smtp and imap entries are not necessary, just common abbreviations for incoming and outgoing mail servers. In fact, these are the names of protocols being used. The CNAME type indicates smtp.[YOUR.DOMAIN] is an alias for your mail.[YOUR.DOMAIN]. Same applies to imap.[YOUR.DOMAIN].

I'll come to spf and dmarc later (and add DKIM as well)

Install: Letsenrypt certificates

Once more, I will use Letsencrypt certificates. Getting them to work is a little different.
sudo -s apt install certbot wget https://dl.eff.org/certbot-auto chmod a+x ./certbot-auto cd /usr/local/src wget http://ftp.nl.debian.org/debian/pool/main/o/openssl/libssl-dev_1.1.0h-2_amd64.deb dpkg -i ./libssl-dev_1.1.0h-2_amd64.deb exit sudo ./certbot-auto certonly --standalone --rsa-key-size 4096 -d mail.[YOUR.DOMAIN] -d imap.[YOUR.DOMAIN] -d smtp.[YOUR.DOMAIN] sudo crontab -e @weekly /root/renewal.sh > /home/frank/renewal.txt 2>&1 cat <<'EOF'>>/root/renewal.sh #!/bin/bash echo "-------------------------------------" echo "Renewals:" /root/certbot-auto renew echo "-------------------------------------" result=$(find /etc/letsencrypt/live/ -type l -mtime -1 ) if [ -n "$result" ]; then echo "Restarting services..." /bin/systemctl postfix reload /bin/systemctl dovecot reload /usr/sbin/service redis-server restart echo "-------------------------------------" fi mail -s "certbot Mail renewal" frank@[YOUR.DOMAIN] < /home/frank/renewal.txt exit 0 EOF

Installation: mail

Mail consists of a Mail transfer Agent (MTA) and a Mail User Agent (MUA). The configuration is kept in a database (MariaDb), and I want filtering against spammers as well as my server to be trusted.
All in all, I will install Postfix, Dovecot, MariaDb, rspamd DKIM, spf, DMARC.

Install postfix (Mail Transfer Agent)

sudo apt install postfix postfix-mysql dovecot-core dovecot-imapd dovecot-lmtpd dovecot-mysql dovecot-sieve dovecot-managesieved mariadb-server
In the Postfix configuration, choose internet site (default), and your [YOUR.DOMAIN] (without the mail prefix)
sudo service dovecot stop sudo service postfix stop sudo -s cd /etc/postfix/ vi main.cf # check/alter: myhostname = mail.[YOUR.DOMAIN] inet_protocols = all #or: inet_protocols = ipv4 mydestination = localhost

MariaDb install & setup

mysql_secure_installation set a new root password Remove anonymous users (Y - default) Disallow remote root (Y - default) Remove demo and Test databases (Y - default) Reload tables (Y - default) # Done. Now, for the db and tables: mysqladmin -p create maildb; mysql -p maildb grant select on maildb.* to mailowner@'127.0.0.1' identified by 'SomeMailPassword'; flush privileges; CREATE or replace TABLE domains ( id int(11) NOT NULL auto_increment, domain varchar(50) NOT NULL, PRIMARY KEY (id), UNIQUE KEY (domain) ) ENGINE=InnoDB; create or replace table users ( id int(11) NOT NULL auto_increment, domain_id int(11) NOT NULL, password varchar(255) NOT NULL, email varchar(127) NOT NULL, quota int unsigned DEFAULT 1024, enabled boolean DEFAULT 0, sendonly boolean DEFAULT 0, PRIMARY KEY (id), UNIQUE KEY ( email), FOREIGN KEY (domain_id) REFERENCES domains(id) ON DELETE CASCADE ) ENGINE=InnoDB; CREATE or replace TABLE aliases ( id int(11) NOT NULL AUTO_INCREMENT, domain_id int(11) NOT NULL, source varchar(100) NOT NULL, destination varchar(100) NOT NULL, enabled boolean DEFAULT 0, PRIMARY KEY (id), FOREIGN KEY (domain_id) REFERENCES domains (id) ON DELETE CASCADE ) ENGINE=InnoDB; CREATE or REPLACE TABLE tlspolicies ( id int(11) NOT NULL AUTO_INCREMENT, domain varchar(127) NOT NULL, policy enum('none', 'may', 'encrypt', 'dane', 'dane-only', 'fingerprint', 'verify', 'secure') NOT NULL, params varchar(255), PRIMARY KEY (id), UNIQUE KEY (domain) )ENGINE=InnoDB; insert into domains (domain) values ('[YOUR.DOMAIN]'); insert into domains (domain) values ('mail.[YOUR.DOMAIN]'); insert into domains (domain) values ('localhost'); insert into domains (domain) values ('home.local'); INSERT INTO maildb.aliases (domain_id, source, destination, enabled) VALUES ('1', 'webmaster@[YOUR.DOMAIN]', 'frank@[YOUR.DOMAIN]',0); INSERT INTO maildb.aliases (domain_id, source, destination, enabled) VALUES ('1', 'postmaster@[YOUR.DOMAIN]', 'frank@[YOUR.DOMAIN]',1); INSERT INTO maildb.aliases (domain_id, source, destination, enabled) VALUES ('1', 'cloudadmin@[YOUR.DOMAIN]', 'frank@[YOUR.DOMAIN]',1); INSERT INTO maildb.aliases (domain_id, source, destination, enabled) VALUES ('1', 'info@[YOUR.DOMAIN]', 'frank@[YOUR.DOMAIN]',1); INSERT INTO maildb.aliases (domain_id, source, destination, enabled) VALUES ('1', 'frank@home.local', 'frank@[YOUR.DOMAIN]',1); INSERT INTO maildb.aliases (domain_id, source, destination, enabled) VALUES ('1', 'root@home.local', 'frank@[YOUR.DOMAIN]',1); insert into tlspolicies (domain, policy, params) values ('gmx.de', 'secure', 'match=.gmx.net'); commit; quit

postfix (Mail Transfer Agent) - connect to MariaDb

mv /etc/postfix/main.cf /etc/postfix/main.cf.sav cat <<'EOF'>>/etc/postfix/main.cf mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 mydestination = localhost relayhost = inet_interfaces = all inet_protocols = all myhostname = mail.[YOUR.DOMAIN] ############################# ### mail queue config ############################# maximal_queue_lifetime = 1h bounce_queue_lifetime = 1h maximal_backoff_time = 15m minimal_backoff_time = 5m queue_run_delay = 5m ############################# ### TLS config ############################# tls_preempt_cipherlist = yes tls_ssl_options = NO_COMPRESSION tls_high_cipherlist = EDH+CAMELLIA:EDH+aRSA:EECDH+aRSA+AESGCM:E6:EECDH:+CAMELLIA128:+AES128:+SSLv3:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!DSS:!RC4:!SEED:!IDEA:!ECDSA:kEDH:CAMELLIA128-SHA:AES128-SHA ############################# ### outgoing SMTP (Postfix sending) ############################# smtp_tls_security_level = dane smtp_dns_support_level = dnssec smtp_tls_policy_maps = mysql:/etc/postfix/sql/tls-policy.cf smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache smtp_tls_protocols = !SSLv2, !SSLv3 smtp_tls_ciphers = high smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt ############################# ### incoming SMTP ############################# smtpd_tls_security_level = may smtpd_tls_protocols = !SSLv2, !SSLv3 smtpd_tls_ciphers = high smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache smtpd_tls_cert_file=/etc/letsencrypt/live/mail.[YOUR.DOMAIN]/fullchain.pem smtpd_tls_key_file=/etc/letsencrypt/live/mail.[YOUR.DOMAIN]/privkey.pem ############################# ### local assignment to Dovecot ############################# virtual_transport = lmtp:unix:private/dovecot-lmtp ############################# ### Spamfilter & DKIM through rspamd ############################# smtpd_milters = inet:localhost:11332 non_smtpd_milters = inet:localhost:11332 milter_protocol = 6 milter_mail_macros = i {mail_addr} {client_addr} {client_name} {auth_authen} milter_default_action = accept ############################# ### Server Restrictions (Clients, Relay, Receiptients) ### Server to server only. Client stuff is in master.cf (Submission part) ############################# ### Allow clients to forward mail, using postfix: ############################# smtpd_relay_restrictions = reject_non_fqdn_recipient reject_unknown_recipient_domain permit_mynetworks reject_unauth_destination ############################# ### Make Postfix accept incoming email, check_recipient_access checks if client is sendonly ############################# smtpd_recipient_restrictions = check_recipient_access mysql:/etc/postfix/sql/recipient-access.cf ############################# ### SMTP-Clients requirements (sending Server) ############################# smtpd_client_restrictions = permit_mynetworks check_client_access hash:/etc/postfix/without_ptr reject_unknown_client_hostname ############################# ### External servers should have valid Hostname in HELO. ############################# smtpd_helo_required = yes smtpd_helo_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_invalid_helo_hostname, reject_non_fqdn_helo_hostname, reject_unknown_helo_hostname, check_helo_access hash:/etc/postfix/helo_access ############################# ### Clients sending too soon need to be blocked smtpd_data_restrictions = reject_unauth_pipelining ############################# ### MUA Restrictions (Mail User Agent) ############################# mua_relay_restrictions = reject_non_fqdn_recipient,reject_unknown_recipient_domain,permit_mynetworks,permit_sasl_authenticated,reject mua_sender_restrictions = permit_mynetworks,reject_non_fqdn_sender,reject_sender_login_mismatch,permit_sasl_authenticated,reject mua_client_restrictions = permit_mynetworks,permit_sasl_authenticated,reject ############################# ### Postscreen Filter ############################# ### Postscreen Whitelist / Blocklist postscreen_access_list = permit_mynetworks cidr:/etc/postfix/postscreen_access postscreen_blacklist_action = drop ############################# ### Incoming speed to high? drop connection (spam...) ############################# postscreen_greet_action = drop ############################# ### DNS blocklists ############################# postscreen_dnsbl_threshold = 2 postscreen_dnsbl_sites = ix.dnsbl.manitu.net*2 zen.spamhaus.org*2 postscreen_dnsbl_action = drop ############################# ### MySQL config ############################# virtual_alias_maps = mysql:/etc/postfix/sql/aliases.cf virtual_mailbox_maps = mysql:/etc/postfix/sql/accounts.cf virtual_mailbox_domains = mysql:/etc/postfix/sql/domains.cf local_recipient_maps = $virtual_mailbox_maps ############################# ### miscellaneous ############################# mailbox_command= mailbox_transport = lmtp:unix:private/dovecot-lmtp ############################# ### Maximal Size all Mailboxes (register with Dovecot, 0 = unlimited) ############################# mailbox_size_limit = 0 ############################# ### Maximal size incoming email in byte (50 MB) ############################# message_size_limit = 52428800 ############################# ### Notify user with new email ############################# biff = no ############################# ### appending .domain should be done by MUA ############################# append_dot_mydomain = no ############################# ### "Address Tagging" symbol ############################# recipient_delimiter = + compatibility_level = 2 EOF cat <<'EOF'>>/etc/postfix/mysql-virtual-mailbox-domains.cf user = mailowner password = SomeMailPassword hosts = 127.0.0.1 dbname = maildb query = SELECT 1 FROM domains WHERE domain ='%s' EOF cat <<'EOF'>>/etc/postfix/mysql-virtual-mailbox-maps.cf user = mailowner password = SomeMailPassword hosts = 127.0.0.1 dbname = maildb query = SELECT 1 FROM users WHERE email='%s' EOF cat <<'EOF'>>/etc/postfix/mysql-virtual-alias-maps.cf user = mailowner password = SomeMailPassword hosts = 127.0.0.1 dbname = maildb query = SELECT destination FROM aliases WHERE source='%s' and enabled=1 EOF cat <<'EOF'>>/etc/postfix/mysql-virtual-email2email.cf user = mailowner password = SomeMailPassword hosts = 127.0.0.1 dbname = maildb query = SELECT email FROM users WHERE email='%s' EOF cat <<'EOF'>>/etc/postfix/helo_access [YOUR.DOMAIN] REJECT Get lost - you are not who you say you are! mail[YOUR.DOMAIN] REJECT Get lost - you are not who you say you are! imap.[YOUR.DOMAIN] REJECT Get lost - you are not who you say you are! smtp.[YOUR.DOMAIN] REJECT Get lost - you are not who you say you are! www.[YOUR.DOMAIN] REJECT Get lost - you are not who you say you are! EOF service postfix restart postmap /etc/postfix/helo_access service postfix reload
Now, TEST the entries:
postmap -q [YOUR.DOMAIN] mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf (result: 1) postmap -q admin@[YOUR.DOMAIN] mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf (result: 1) postmap -q webmaster@[YOUR.DOMAIN] mysql:/etc/postfix/mysql-virtual-alias-maps.cf (no result) postmap -q info@[YOUR.DOMAIN] mysql:/etc/postfix/mysql-virtual-alias-maps.cf (result: frank@[YOUR.DOMAIN]) cp /etc/postfix/master.cf /etc/postfix/master.cf.bak vi /etc/postfix/master.cf: # # Postfix master process configuration file. For details on the format # of the file, see the master(5) manual page (command: "man 5 master" or # on-line: http://www.postfix.org/master.5.html). # # Do not forget to execute "postfix reload" after editing this file. # # ========================================================================== # service type private unpriv chroot wakeup maxproc command + args # (yes) (yes) (no) (never) (100) # ========================================================================== #smtp inet n - y - - smtpd smtp inet n - y - 1 postscreen -o smtpd_sasl_auth_enable=no smtpd pass - - y - - smtpd dnsblog unix - - y - 0 dnsblog tlsproxy unix - - y - 0 tlsproxy submission inet n - y - - smtpd -o syslog_name=postfix/submission -o smtpd_tls_security_level=encrypt -o smtpd_sasl_auth_enable=yes -o smtpd_sasl_type=dovecot -o smtpd_sasl_path=private/auth -o smtpd_sasl_security_options=noanonymous # -o smtpd_reject_unlisted_recipient=no -o smtpd_client_restrictions=$mua_client_restrictions # -o smtpd_helo_restrictions=$mua_helo_restrictions -o smtpd_sender_restrictions=$mua_sender_restrictions -o smtpd_recipient_restrictions=$mua_client_restrictions -o smtpd_relay_restrictions=$mua_relay_restrictions -o smtpd_sender_login_maps=mysql:/etc/postfix/sql/sender-login-maps.cf -o smtpd_helo_required=no -o smtpd_helo_restrictions= -o cleanup_service_name=submission-header-cleanup -o milter_macro_daemon_name=ORIGINATING #smtps inet n - y - - smtpd # -o syslog_name=postfix/smtps # -o smtpd_tls_wrappermode=yes # -o smtpd_sasl_auth_enable=yes # -o smtpd_reject_unlisted_recipient=no # -o smtpd_client_restrictions=$mua_client_restrictions # -o smtpd_helo_restrictions=$mua_helo_restrictions # -o smtpd_sender_restrictions=$mua_sender_restrictions # -o smtpd_recipient_restrictions= # -o smtpd_relay_restrictions=permit_sasl_authenticated,reject # -o milter_macro_daemon_name=ORIGINATING #628 inet n - y - - qmqpd pickup unix n - y 60 1 pickup cleanup unix n - y - 0 cleanup qmgr unix n - n 300 1 qmgr tlsmgr unix - - y 1000? 1 tlsmgr rewrite unix - - y - - trivial-rewrite bounce unix - - y - 0 bounce defer unix - - y - 0 bounce trace unix - - y - 0 bounce verify unix - - y - 1 verify flush unix n - y 1000? 0 flush proxymap unix - - n - - proxymap proxywrite unix - - n - 1 proxymap smtp unix - - y - - smtp relay unix - - y - - smtp # -o smtp_helo_timeout=5 -o smtp_connect_timeout=5 showq unix n - y - - showq error unix - - y - - error retry unix - - y - - error discard unix - - y - - discard local unix - n n - - local virtual unix - n n - - virtual lmtp unix - - y - - lmtp anvil unix - - y - 1 anvil scache unix - - y - 1 scache # # Clean up MUA header: submission-header-cleanup unix n - n - 0 cleanup -o header_checks=regexp:/etc/postfix/submission_header_cleanup # ==================================================================== # Interfaces to non-Postfix software. Be sure to examine the manual # pages of the non-Postfix software to find out what options it wants. # # Many of the following services use the Postfix pipe(8) delivery # agent. See the pipe(8) man page for information about ${recipient} # and other message envelope options. # ==================================================================== # # maildrop. See the Postfix MAILDROP_README file for details. # Also specify in main.cf: maildrop_destination_recipient_limit=1 # maildrop unix - n n - - pipe flags=DRhu user=vmail argv=/usr/bin/maildrop -d ${recipient} # # ==================================================================== # # Recent Cyrus versions can use the existing "lmtp" master.cf entry. # # Specify in cyrus.conf: # lmtp cmd="lmtpd -a" listen="localhost:lmtp" proto=tcp4 # # Specify in main.cf one or more of the following: # mailbox_transport = lmtp:inet:localhost # virtual_transport = lmtp:inet:localhost # # ==================================================================== # # Cyrus 2.1.5 (Amos Gouaux) # Also specify in main.cf: cyrus_destination_recipient_limit=1 # #cyrus unix - n n - - pipe # user=cyrus argv=/cyrus/bin/deliver -e -r ${sender} -m ${extension} ${user} # # ==================================================================== # Old example of delivery via Cyrus. # #old-cyrus unix - n n - - pipe # flags=R user=cyrus argv=/cyrus/bin/deliver -e -m ${extension} ${user} # # ==================================================================== # # See the Postfix UUCP_README file for configuration details. # uucp unix - n n - - pipe flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient) # # Other external delivery methods. # ifmail unix - n n - - pipe flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient) bsmtp unix - n n - - pipe flags=Fq. user=bsmtp argv=/usr/lib/bsmtp/bsmtp -t$nexthop -f$sender $recipient scalemail-backend unix - n n - 2 pipe flags=R user=scalemail argv=/usr/lib/scalemail/bin/scalemail-store ${nexthop} ${user} ${extension} mailman unix - n n - - pipe flags=FR user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py ${nexthop} ${user} chmod -R o-rwx /etc/postfix service postfix restart cat<<"EOF'>>/etc/postfix/submission_header_cleanup ########## ### MUA header cleanup - this file is referenced in master.cf ######### /^Received:/ IGNORE /^X-Originating-IP:/ IGNORE /^X-Mailer:/ IGNORE /^User-Agent:/ IGNORE

Virtual Mail setup

mkdir -p /var/vmail/mailboxes mkdir -p /var/vmail/sieve/global chown -R vmail /var/vmail chgrp -R vmail /var/vmail chmod -R 770 /var/vmail ## Create the mail user - there is a standard "mail" one, so we'll create a virtual one: adduser --disabled-login --disabled-password --home /var/vmail vmail

Dovecot - Mail User Agent

service stop dovecot rm -rf /etc/dovecot/* cat <<'EOF'>>/etc/dovecot/dovecot.conf ############################# ### Activated Protocols ############################# protocols = imap lmtp sieve ############################# ### SSL Config ############################# ssl = required ssl_cert = </etc/letsencrypt/live/mail.[YOUR.DOMAIN]/fullchain.pem ssl_key = </etc/letsencrypt/live/mail.[YOUR.DOMAIN]/privkey.pem ssl_dh_parameters_length = 4096 ssl_protocols = !SSLv3 ssl_cipher_list = EDH+CAMELLIA:EDH+aRSA:EECDH+aRSA+AESGCM:EECDH+aRSA+SHA256:EECDH:+CAMELLIA128:+AES128:!SSLv3:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!DSS:!RC4:!SEED:!IDEA:!ECDSA:kEDH:CAMELLIA128-SHA:AES128-SHA ssl_prefer_server_ciphers = yes ############################# ### Dovecot services ############################# service imap-login { inet_listener imap { port = 0 } inet_listener imaps { port = 993 ssl = yes } } service managesieve-login { inet_listener sieve { port = 4190 } } service lmtp { unix_listener /var/spool/postfix/private/dovecot-lmtp { # mode = 0660 mode = 0600 group = postfix user = postfix } # user = vmail } service auth { ### Postfix Auth socket unix_listener /var/spool/postfix/private/auth { mode = 0660 user = postfix group = postfix } ### LMTP Auth socket unix_listener auth-userdb { mode = 0660 user = vmail group = vmail } } ############################# ### Protocol settings ############################# protocol imap { mail_plugins = $mail_plugins quota imap_quota imap_sieve mail_max_userip_connections = 20 imap_idle_notify_interval = 29 mins } protocol lmtp { postmaster_address = postmaster@[YOUR.DOMAIN] mail_plugins = $mail_plugins sieve } ############################# ### Client authentication ############################# disable_plaintext_auth = yes auth_mechanisms = plain login passdb { driver = sql args = /etc/dovecot/dovecot-sql.conf } userdb { driver = sql args = /etc/dovecot/dovecot-sql.conf } ############################# ### Mail location ############################# mail_uid = vmail mail_gid = vmail mail_privileged_group = vmail mail_home = /var/vmail/mailboxes/%d/%n mail_location = maildir:~/mail:LAYOUT=fs ############################# ### Mailbox configuration ############################# namespace inbox { inbox = yes mailbox Spam { auto = subscribe special_use = \Junk } mailbox Trash { auto = subscribe special_use = \Trash } mailbox Drafts { auto = subscribe special_use = \Drafts } mailbox Sent { auto = subscribe special_use = \Sent } } ############################# ### Mail plugins ############################# plugin { sieve_plugins = sieve_imapsieve sieve_extprograms sieve_before = /var/vmail/sieve/global/spam-global.sieve sieve = file:/var/vmail/sieve/%d/%n/scripts;active=/var/vmail/sieve/%d/%n/active-script.sieve ### ### Spam learning ### # From elsewhere to Spam folder imapsieve_mailbox1_name = Spam imapsieve_mailbox1_causes = COPY imapsieve_mailbox1_before = file:/var/vmail/sieve/global/learn-spam.sieve # From Spam folder to elsewhere imapsieve_mailbox2_name = * imapsieve_mailbox2_from = Spam imapsieve_mailbox2_causes = COPY imapsieve_mailbox2_before = file:/var/vmail/sieve/global/learn-ham.sieve sieve_pipe_bin_dir = /usr/bin sieve_global_extensions = +vnd.dovecot.pipe quota = maildir:User quota quota_exceeded_message = Gebruiker %u gebruikt meer ruimte dan toegestaan. / User %u has exhausted allowed storage space. } EOF

Dovecot (MUA) - connect to MariaDb

cat<<'EOF'>>/etc/dovecot/dovecot-sql.conf # 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 # driver=mysql connect = "host=127.0.0.1 dbname=maildb user=mailowner password=SomeMailPassword" default_pass_scheme = SHA512-CRYPT # select u.email as user, d.domain as domain from users u, domains d where u.domain_id = d.id; password_query = SELECT email AS user, password FROM users where email = '%u' AND enabled = true; user_query = SELECT concat('*:storage=', quota, 'M') AS quota_rule FROM users WHERE email = '%u' AND sendonly = false; iterate_query = SELECT u.email as username, d.domain FROM users u, domains d where u.domain_id = d.id AND u.sendonly = false; EOF chmod 440 /etc/dovecot/dovecot-sql.conf

Files, mentioned in main.cf

mkdir /etc/postfix/sql cd /etc/postfix/sql cat<<'EOF'>>accounts.cf user = mailowner password = SomeMailPassword hosts = 127.0.0.1 dbname = maildb query = select 1 as found FROM users WHERE email = '%s' AND enabled = true LIMIT 1; EOF cat<<'EOF'>>aliases.cf: user = mailowner password = SomeMailPassword hosts = 127.0.0.1 dbname = maildb query = select destination FROM aliases WHERE source = '%s' AND enabled=TRUE EOF cat<<'EOF'>>domains.cf: user = mailowner password = SomeMailPassword hosts = 127.0.0.1 dbname = maildb query = select domain FROM domains WHERE domain='%s' EOF cat<<'EOF'>>recipient-access.cf user = mailowner password = SomeMailPassword hosts = 127.0.0.1 dbname = maildb query = select if(sendonly = true, 'REJECT', 'OK') AS access from users where email = '%s' and enabled = true LIMIT 1; EOF cat<<'EOF'>>sender-login-maps.cf user = mailowner password = SomeMailPassword hosts = 127.0.0.1 dbname = maildb query = select email as 'owns' from users where email = '%s' AND enabled=TRUE union select destination as 'owns' from aliases where source = '%s' AND enabled=TRUE EOF cat<<'EOF'>>tls-policy.cf # option not being used user = mailowner password = SomeMailPassword hosts = 127.0.0.1 dbname = maildb query = SELECT policy, params FROM tlspolicies WHERE domain = '%s' EOF cat<<'EOF'>>/etc/postfix/without_ptr # use postmap /etc/postfix/without_ptr 127.0.0.1 OK EOF # make postfix aware... Need to do after every alteration... postmap /etc/postfix/without_ptr touch /etc/postfix/postscreen_access chmod -R 640 /etc/postfix/sql service postfix restart

Anti Spam - filter & rspamd

cat<<'EOF'>>/var/vmail/sieve/global/spam-global.sieve require "fileinto"; if header :contains "X-Spam-Flag" "YES" { fileinto "Spam"; } if header :is "X-Spam" "Yes" { fileinto "Spam"; } EOF cat<<'EOF'>>/var/vmail/sieve/global/learn-spam.sieve require ["vnd.dovecot.pipe", "copy", "imapsieve"]; pipe :copy "rspamc" ["learn_spam"]; EOF cat<<'EOF'>>/var/vmail/sieve/global/learn-ham.sieve require ["vnd.dovecot.pipe", "copy", "imapsieve"]; pipe :copy "rspamc" ["learn_ham"]; EOF apt install -y lsb-release wget -O- https://rspamd.com/apt-stable/gpg.key | apt-key add - echo "deb http://rspamd.com/apt-stable/ $(lsb_release -c -s) main" > /etc/apt/sources.list.d/rspamd.list echo "deb-src http://rspamd.com/apt-stable/ $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/rspamd.list apt update apt install -y rspamd systemctl stop rspamd cd /etc/rspamd/local.d/ cat<<'EOF'>>/etc/rspamd/local.d/options.inc local_addrs = "127.0.0.0/8, ::1"; dns { nameserver = ["192.168.4.200:53:10"]; } EOF cat<<'EOF'>>worker-normal.inc bind_socket = "localhost:11333"; ### Number of Workers. Defaults to # of cores (4). # count = 1 EOF root@mail:/etc/rspamd/local.d# rspamadm help Rspamadm 1.7.4 Usage: rspamadm [global_options] command [command_options] Available commands: pw Manage rspamd passwords keypair Create encryption key pairs configtest Perform configuration file test fuzzy_merge Merge fuzzy databases configdump Perform configuration file dump control Manage rspamd main control interface confighelp Shows help for configuration options statconvert Convert statistics from sqlite3 to redis fuzzyconvert Convert fuzzy hashes from sqlite3 to redis grep Search for patterns in rspamd logs signtool Sign and verify files tool lua Run LUA interpreter dkim_keygen Create dkim key pairs configwizard Perform guided configuration for Rspamd daemon corpus_test Create logs files from email corpus rescore Estimate optimal symbol weights from log files root@mail:/etc/rspamd/local.d# rspamadm pw [YOUR.RSPAMD.PASSWORD] $2$7..(snipped)..db cat<<'EOF'>>worker-controller.inc password=$2$7..(snipped)..db EOF cat<<'EOF'>>worker-proxy.inc bind_socket = "localhost:11332"; milter = yes; timeout = 120s; upstream "local" { default = yes; self_scan = yes; } EOF cat<<'EOF'>>logging.inc type = "file"; filename = "/var/log/rspamd/rspamd.log"; level = "error"; debug_modules = []; EOF cat<<'EOF'>>milter_headers.conf use = ["x-spamd-bar", "x-spam-level", "authentication-results"]; authenticated_headers = ["authentication-results"]; EOF cat<<'EOF'>>classifier-bayes.conf backend = "redis"; EOF

DKIM

mkdir /var/lib/rspamd/dkim/ rspamadm dkim_keygen -b 2048 -s 2018 -k /var/lib/rspamd/dkim/2018.key > /var/lib/rspamd/dkim/2018.txt chown -R _rspamd:_rspamd /var/lib/rspamd/dkim chmod 440 /var/lib/rspamd/dkim/* cat /var/lib/rspamd/dkim/2018.txt (it's the DKIM DNS record!) 2018._domainkey IN TXT ( "v=DKIM1; k=rsa; " "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzi6rHX6lDrUSsteJFB1r4tv6y+rJ8Yb9Ma6Bf+B0hdLAqh2JBoV1TiqNu8ChuR795wsm6NzwG6l+zU6OxtzsahjwqothX8AFEdpdR0ToagUpVUB6h8VkWds4GtUcw/GLJDt7L++hUUcnMK2yZ0gbeD2hC1dLeDSiA20CHyesIAAld+8QpHQx9uPEKSmUo0JBGLEys5F3NbSv/mBIa" "aha2GPJU6sIb6KVArXp9wFCUaXT26qiEIXck0upcLE7ml9zzUgmyHkqp723o9RW9YJ87GyNk6rzRN5aIUNBeKpcQyTaDHL/UlR8tl31WChw0Tq0vA1WXaHEwV1xf5SBhhElzQIDAQAB" ) ;
Add a TXT record, named 2018._domainkey. It should contain all between the quotes, without the quotes, extra whitespace, etc:
v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzi6rHX6lDrUSsteJFB1r4tv6y+rJ8Yb9Ma6Bf+B0hdLAqh2JBoV1TiqNu8ChuR795wsm6NzwG6l+zU6OxtzsahjwqothX8AFEdpdR0ToagUpVUB6h8VkWds4GtUcw/GLJDt7L++hUUcnMK2yZ0gbeD2hC1dLeDSiA20CHyesIAAld+8QpHQx9uPEKSmUo0JBGLEys5F3NbSv/mBIaaha2GPJU6sIb6KVArXp9wFCUaXT26qiEIXck0upcLE7ml9zzUgmyHkqp723o9RW9YJ87GyNk6rzRN5aIUNBeKpcQyTaDHL/UlR8tl31WChw0Tq0vA1WXaHEwV1xf5SBhhElzQIDAQAB cat<<'EOF'>>/etc/rspamd/local.d/dkim_signing.conf path = "/var/lib/rspamd/dkim/$selector.key"; selector = "2018"; ### Enable DKIM signing for alias sender addresses allow_username_mismatch = true; EOF
Copy to ARC (see: https://rspamd.com/doc/modules/arc.html) config:
cp -R /etc/rspamd/local.d/dkim_signing.conf /etc/rspamd/local.d/arc.conf

Redis cache

apt install -y redis-server cat<<'EOF'>>/etc/rspamd/local.d/redis.conf servers = "127.0.0.1"; EOF systemctl start rspamd

FINALIZE

Add users

Add email users to the database. The passwords are encrypted, and need some work to generate:
doveadm pw -s SHA512-CRYPT Enter new password: [PASSWORD FOR MAIL USER GOES HERE] retype new password: [ Same Password ] {SHA512-CRYPT}$6$...(snipped)... mysql -p use maildb insert into users (domain_id, password , email, enabled, sendonly) values (1, '{SHA512-CRYPT}$6$...(snipped)...', 'frank@[YOUR.DOMAIN]',true, false);
Repeat for admin@[YOUR.DOMAIN] (send-only account):
insert into users (domain_id, password , email, enabled, sendonly) values (1, '{SHA512-CRYPT}$6$...(snipped)...', 'admin@[YOUR.DOMAIN]',true, true);

Connect

Connecting your email program is not straightforward (that is: androids wizards will fail); the account to be used is frank@[YOUR.DOMAIN], not just frank.

The server uses SSL/TLS on port 993 for IMAP, and STARTTLS on port 587 for SMTP.
You may use imap.[YOUR.DOMAIN] for imap (incoming) mail, smtp.[YOUR.DOMAIN] as sending server, of mail.[YOUR.DOMAIN] for either, or both. Your choice.

You will have to go into the details to alter the username; it will probably default to frank where it should be frank@[YOUR.DOMAIN].

No comments: