Commit e713af5f authored by Joshua Tauberer's avatar Joshua Tauberer

refactor the mail setup scripts

As the scripts keep growing, it's time to split them up to
keep them understandable.

This splits mail.sh into mail-postfix.sh, mail-dovecot.sh,
and mail-users.sh, which has all of the user database-related
configurations shared by Dovecot and Postfix. Also from
spamassassin.sh the core sieve configuration is moved into
mail-dovecot.sh and the virtual transport setting is moved
into mail-postfix.sh.

Also revising one of the sed scripts in mail-dovecot to
not insert a new additional # at the start of a line each
time the script is run.
parent 6f51b496
#!/bin/bash
#
# Dovecot (IMAP and LDA)
#
# Dovecot is *both* the IMAP server (the protocol that email applications
# use to query a mailbox) as well as the local delivery agent (LDA),
# meaning it is responsible for writing emails to mailbox storage on disk.
# You could imagine why these things would be bundled together.
#
# As part of local mail delivery, Dovecot executes actions on incoming
# mail as defined in a "sieve" script.
#
# Dovecot's LDA role comes after spam filtering. Postfix hands mail off
# to Spamassassin which in turn hands it off to Dovecot. This all happens
# using the LMTP protocol.
source setup/functions.sh # load our functions
source /etc/mailinabox.conf # load global vars
# Install packages.
apt_install \
dovecot-core dovecot-imapd dovecot-lmtpd dovecot-sqlite sqlite3 dovecot-sieve
# The dovecot-imapd dovecot-lmtpd packages automatically enable IMAP and LMTP protocols.
# Set the location where we'll store user mailboxes.
tools/editconf.py /etc/dovecot/conf.d/10-mail.conf \
mail_location=maildir:$STORAGE_ROOT/mail/mailboxes/%d/%n \
mail_privileged_group=mail \
first_valid_uid=0
# IMAP
# Require that passwords are sent over SSL only, and allow the usual IMAP authentication mechanisms.
# The LOGIN mechanism is supposedly for Microsoft products like Outlook to do SMTP login (I guess
# since we're using Dovecot to handle SMTP authentication?).
tools/editconf.py /etc/dovecot/conf.d/10-auth.conf \
disable_plaintext_auth=yes \
"auth_mechanisms=plain login"
# Enable SSL, specify the location of the SSL certificate and private key files,
# and allow only good ciphers per http://baldric.net/2013/12/07/tls-ciphers-in-postfix-and-dovecot/.
tools/editconf.py /etc/dovecot/conf.d/10-ssl.conf \
ssl=required \
"ssl_cert=<$STORAGE_ROOT/ssl/ssl_certificate.pem" \
"ssl_key=<$STORAGE_ROOT/ssl/ssl_private_key.pem" \
"ssl_cipher_list=TLSv1+HIGH !SSLv2 !RC4 !aNULL !eNULL !3DES @STRENGTH"
# Disable in-the-clear IMAP and POP because we're paranoid (we haven't even
# enabled POP).
sed -i "s/#port = 143/port = 0/" /etc/dovecot/conf.d/10-master.conf
sed -i "s/#port = 110/port = 0/" /etc/dovecot/conf.d/10-master.conf
# LDA (LMTP)
# Enable Dovecot's LDA service with the LMTP protocol. It will listen
# in port 10026, and Spamassassin will be configured to pass mail there.
#
# The disabled unix socket listener is normally how Postfix and Dovecot
# would communicate (see the Postfix setup script for the corresponding
# setting also commented out).
#
# Also increase the number of allowed IMAP connections per mailbox because
# we all have so many devices lately.
cat > /etc/dovecot/conf.d/99-local.conf << EOF;
service lmtp {
#unix_listener /var/spool/postfix/private/dovecot-lmtp {
# user = postfix
# group = postfix
#}
inet_listener lmtp {
address = 127.0.0.1
port = 10026
}
}
protocol imap {
mail_max_userip_connections = 20
}
EOF
# Setting a postmaster_address seems to be required or LMTP won't start.
tools/editconf.py /etc/dovecot/conf.d/15-lda.conf \
postmaster_address=postmaster@$PRIMARY_HOSTNAME
# SIEVE
# Enable the Dovecot sieve plugin which let's us set a script that automatically moves
# spam into the user's Spam mail filter. (Note: Be careful if we want to use multiple
# plugins later.)
#
# The actual sieve script is copied into user mailboxes at the time the user account
# is created. Our script moves spam into the user's Spam folder.
sudo sed -i "s/#mail_plugins = .*/mail_plugins = \$mail_plugins sieve/" /etc/dovecot/conf.d/20-lmtp.conf
# PERMISSIONS
# Make the place for mailboxes.
mkdir -p $STORAGE_ROOT/mail
# Ensure configuration files are owned by dovecot and not world readable.
chown -R mail:dovecot /etc/dovecot
chmod -R o-rwx /etc/dovecot
# Ensure mailbox files have a directory that exists and are owned by the mail user.
mkdir -p $STORAGE_ROOT/mail/mailboxes
chown -R mail.mail $STORAGE_ROOT/mail/mailboxes
# Allow the IMAP port in the firewall.
ufw_allow imaps
# Restart services.
service dovecot restart
#!/bin/bash
# SMTP/IMAP: Postfix and Dovecot
################################
# The SMTP server is listening on port 25 for incoming mail (mail for us) and on
# port 587 for outgoing mail (i.e. mail you send). Port 587 uses STARTTLS (not SSL)
# and you'll authenticate with your full email address and mail password.
#
# The IMAP server is listening on port 993 and uses SSL. There is no IMAP server
# listening on port 143 because it is not encrypted on that port.
# We configure these together because postfix's configuration relies heavily on dovecot.
# Install packages.
# Postfix (SMTP)
#
# Postfix handles the transmission of email between servers
# using the SMTP protocol. It is a Mail Transfer Agent (MTA).
#
# Postfix listens on port 25 (SMTP) for incoming mail from
# other servers on the Internet. It is responsible for very
# basic email filtering such as by IP address and greylisting,
# it checks that the destination address is valid, rewrites
# destinations according to aliases, and passses email on to
# another service for local mail delivery.
#
# The first hop in local mail delivery is to Spamassassin via
# LMTP. Spamassassin then passes mail over to Dovecot for
# storage in the user's mailbox.
#
# Postfix also listens on port 587 (SMTP+STARTLS) for
# connections from users who can authenticate and then sends
# their email out to the outside world. Postfix queries Dovecot
# to authenticate users.
#
# Address validation, alias rewriting, and user authentication
# is configured in a separate setup script mail-users.sh
# because of the overlap of this part with the Dovecot
# configuration.
source setup/functions.sh # load our functions
source /etc/mailinabox.conf # load global vars
apt_install \
postfix postgrey postfix-pcre \
dovecot-core dovecot-imapd dovecot-lmtpd dovecot-sqlite sqlite3
# Install packages.
mkdir -p $STORAGE_ROOT/mail
apt_install postfix postgrey postfix-pcre
# POSTFIX
#########
# Basic Settings
# Have postfix listen on all network interfaces, set our name (the Debian default seems to be localhost),
# and set the name of the local machine to localhost for xxx@localhost mail (but I don't think this will have any effect because
......@@ -34,6 +44,8 @@ tools/editconf.py /etc/postfix/main.cf \
smtpd_banner="\$myhostname ESMTP Hi, I'm a Mail-in-a-Box (Ubuntu/Postfix; see https://github.com/joshdata/mailinabox)" \
mydestination=localhost
# Outgoing Mail
# Enable the 'submission' port 587 smtpd server and tweak its settings.
# a) Require the best ciphers for incoming connections per http://baldric.net/2013/12/07/tls-ciphers-in-postfix-and-dovecot/.
# but without affecting opportunistic TLS on incoming mail, which will allow any cipher (it's better than none).
......@@ -52,7 +64,9 @@ tools/editconf.py /etc/postfix/master.cf -s -w \
# Install the `outgoing_mail_header_filters` file required by the new 'authclean' service.
cp conf/postfix_outgoing_mail_header_filters /etc/postfix/outgoing_mail_header_filters
# Enable TLS and require it for all user authentication.
# Enable TLS on incoming connections (i.e. ports 25 *and* 587) and
# require TLS before a user is allowed to authenticate. This also makes
# opportunistic TLS available on *incoming* mail.
tools/editconf.py /etc/postfix/main.cf \
smtpd_tls_security_level=may\
smtpd_tls_auth_only=yes \
......@@ -72,14 +86,29 @@ tools/editconf.py /etc/postfix/main.cf \
smtp_dns_support_level=dnssec \
smtp_tls_loglevel=2
# Who can send outbound mail?
# Incoming Mail
# Pass any incoming mail over to a local delivery agent. Spamassassin
# will act as the LDA agent at first. It is listening on port 10025
# with LMTP. Spamassassin will pass the mail over to Dovecot after.
#
# In a basic setup we would pass mail directly to Dovecot like so:
# tools/editconf.py /etc/postfix/main.cf virtual_transport=lmtp:unix:private/dovecot-lmtp
#
tools/editconf.py /etc/postfix/main.cf virtual_transport=lmtp:[127.0.0.1]:10025
# Who can send outbound mail? The purpose of this is to prevent
# non-authenticated users from sending mail that requires being
# relayed elsewhere. We don't want to be an "open relay".
#
# permit_sasl_authenticated: Authenticated users (i.e. on port 587).
# permit_mynetworks: Mail that originates locally.
# reject_unauth_destination: No one else. (Permits mail whose destination is local and rejects other mail.)
tools/editconf.py /etc/postfix/main.cf \
smtpd_relay_restrictions=permit_sasl_authenticated,permit_mynetworks,reject_unauth_destination
# Who can send mail to us?
# Who can send mail to us? Some basic filters.
#
# reject_non_fqdn_sender: Reject not-nice-looking return paths.
# reject_unknown_sender_domain: Reject return paths with invalid domains.
# reject_rhsbl_sender: Reject return paths that use blacklisted domains.
......@@ -101,168 +130,11 @@ tools/editconf.py /etc/postfix/main.cf \
tools/editconf.py /etc/postfix/main.cf \
message_size_limit=134217728
# In a basic setup we would handle all local mail delivery by passing
# it directly to dovecot over LMTP. However when we setup spamassassin
# we will instead pass mail to spampd which will in turn pass it off
# to dovecot. So we will skip setting this here and instead set it in
# spamassassin.sh.
#tools/editconf.py /etc/postfix/main.cf virtual_transport=lmtp:unix:private/dovecot-lmtp
# Postfix will query dovecot for user authentication.
tools/editconf.py /etc/postfix/main.cf \
smtpd_sasl_type=dovecot \
smtpd_sasl_path=private/auth \
smtpd_sasl_auth_enable=yes
# Use a Sqlite3 database to check whether a destination email address exists,
# and to perform any email alias rewrites.
tools/editconf.py /etc/postfix/main.cf \
virtual_mailbox_domains=sqlite:/etc/postfix/virtual-mailbox-domains.cf \
virtual_mailbox_maps=sqlite:/etc/postfix/virtual-mailbox-maps.cf \
virtual_alias_maps=sqlite:/etc/postfix/virtual-alias-maps.cf \
local_recipient_maps=\$virtual_mailbox_maps
# Here's the path to the database.
db_path=$STORAGE_ROOT/mail/users.sqlite
# SQL statement to check if we handle mail for a domain, either for users or aliases.
cat > /etc/postfix/virtual-mailbox-domains.cf << EOF;
dbpath=$db_path
query = SELECT 1 FROM users WHERE email LIKE '%%@%s' UNION SELECT 1 FROM aliases WHERE source LIKE '%%@%s'
EOF
# SQL statement to check if we handle mail for a user.
cat > /etc/postfix/virtual-mailbox-maps.cf << EOF;
dbpath=$db_path
query = SELECT 1 FROM users WHERE email='%s'
EOF
# SQL statement to rewrite an email address if an alias is present.
cat > /etc/postfix/virtual-alias-maps.cf << EOF;
dbpath=$db_path
query = SELECT destination FROM aliases WHERE source='%s'
EOF
# Allow the two SMTP ports in the firewall.
# Create an empty database if it doesn't yet exist.
if [ ! -f $db_path ]; then
echo Creating new user database: $db_path;
echo "CREATE TABLE users (id INTEGER PRIMARY KEY AUTOINCREMENT, email TEXT NOT NULL UNIQUE, password TEXT NOT NULL, extra);" | sqlite3 $db_path;
echo "CREATE TABLE aliases (id INTEGER PRIMARY KEY AUTOINCREMENT, source TEXT NOT NULL UNIQUE, destination TEXT NOT NULL);" | sqlite3 $db_path;
fi
# DOVECOT
#########
# The dovecot-imapd dovecot-lmtpd packages automatically enable IMAP and LMTP protocols.
# Set the location where we'll store user mailboxes.
tools/editconf.py /etc/dovecot/conf.d/10-mail.conf \
mail_location=maildir:$STORAGE_ROOT/mail/mailboxes/%d/%n \
mail_privileged_group=mail \
first_valid_uid=0
# Require that passwords are sent over SSL only, and allow the usual IMAP authentication mechanisms.
# The LOGIN mechanism is supposedly for Microsoft products like Outlook to do SMTP login (I guess
# since we're using Dovecot to handle SMTP authentication?).
tools/editconf.py /etc/dovecot/conf.d/10-auth.conf \
disable_plaintext_auth=yes \
"auth_mechanisms=plain login"
# Query our Sqlite3 database, and not system users, for authentication.
sed -i "s/\(\!include auth-system.conf.ext\)/#\1/" /etc/dovecot/conf.d/10-auth.conf
sed -i "s/#\(\!include auth-sql.conf.ext\)/\1/" /etc/dovecot/conf.d/10-auth.conf
# Configure how to access our Sqlite3 database. Not sure what userdb is for.
cat > /etc/dovecot/conf.d/auth-sql.conf.ext << EOF;
passdb {
driver = sql
args = /etc/dovecot/dovecot-sql.conf.ext
}
userdb {
driver = static
args = uid=mail gid=mail home=$STORAGE_ROOT/mail/mailboxes/%d/%n
}
EOF
# Configure the SQL to query for a user's password.
cat > /etc/dovecot/dovecot-sql.conf.ext << EOF;
driver = sqlite
connect = $db_path
default_pass_scheme = SHA512-CRYPT
password_query = SELECT email as user, password FROM users WHERE email='%u';
EOF
chmod 0600 /etc/dovecot/dovecot-sql.conf.ext # per Dovecot instructions
# Disable in-the-clear IMAP and POP because we're paranoid (we haven't even
# enabled POP).
sed -i "s/#port = 143/port = 0/" /etc/dovecot/conf.d/10-master.conf
sed -i "s/#port = 110/port = 0/" /etc/dovecot/conf.d/10-master.conf
# Have dovecot provide authorization and LMTP (local mail delivery) services.
#
# We have dovecot listen on a Unix domain socket for these services
# in a manner that made postfix configuration above easy.
#
# We also have dovecot listen on port 10026 (localhost only) for LMTP
# in case we have other services that want to deliver local mail, namely
# spampd.
#
# Also increase the number of allowed connections per mailbox because we
# all have so many devices lately.
cat > /etc/dovecot/conf.d/99-local.conf << EOF;
service auth {
unix_listener /var/spool/postfix/private/auth {
mode = 0666
user = postfix
group = postfix
}
}
service lmtp {
unix_listener /var/spool/postfix/private/dovecot-lmtp {
user = postfix
group = postfix
}
inet_listener lmtp {
address = 127.0.0.1
port = 10026
}
}
protocol imap {
mail_max_userip_connections = 20
}
EOF
# postmaster_address seems to be required or LMTP won't start
tools/editconf.py /etc/dovecot/conf.d/15-lda.conf \
postmaster_address=postmaster@$PRIMARY_HOSTNAME
# Drew Crawford sets the auth-worker process to run as the mail user, but we don't care if it runs as root.
# Enable SSL, specify the location of the SSL certificate and private key files,
# and allow only good ciphers per http://baldric.net/2013/12/07/tls-ciphers-in-postfix-and-dovecot/.
tools/editconf.py /etc/dovecot/conf.d/10-ssl.conf \
ssl=required \
"ssl_cert=<$STORAGE_ROOT/ssl/ssl_certificate.pem" \
"ssl_key=<$STORAGE_ROOT/ssl/ssl_private_key.pem" \
"ssl_cipher_list=TLSv1+HIGH !SSLv2 !RC4 !aNULL !eNULL !3DES @STRENGTH"
# PERMISSIONS / RESTART SERVICES
# Ensure configuration files are owned by dovecot and not world readable.
chown -R mail:dovecot /etc/dovecot
chmod -R o-rwx /etc/dovecot
# Ensure mailbox files have a directory that exists and are owned by the mail user.
mkdir -p $STORAGE_ROOT/mail/mailboxes
chown -R mail.mail $STORAGE_ROOT/mail/mailboxes
# Restart services.
service postfix restart
service dovecot restart
# Allow mail-related ports in the firewall.
ufw_allow smtp
ufw_allow submission
ufw_allow imaps
# Restart services
service postfix restart
#!/bin/bash
#
# User Authentication and Destination Validation
#
# This script configures user authentication for Dovecot
# and Postfix (which relies on Dovecot) and destination
# validation by quering an Sqlite3 database of mail users.
source setup/functions.sh # load our functions
source /etc/mailinabox.conf # load global vars
# The database of mail users (i.e. authenticated users, who have mailboxes)
# and aliases (forwarders).
db_path=$STORAGE_ROOT/mail/users.sqlite
# Create an empty database if it doesn't yet exist.
if [ ! -f $db_path ]; then
echo Creating new user database: $db_path;
echo "CREATE TABLE users (id INTEGER PRIMARY KEY AUTOINCREMENT, email TEXT NOT NULL UNIQUE, password TEXT NOT NULL, extra);" | sqlite3 $db_path;
echo "CREATE TABLE aliases (id INTEGER PRIMARY KEY AUTOINCREMENT, source TEXT NOT NULL UNIQUE, destination TEXT NOT NULL);" | sqlite3 $db_path;
fi
# User Authentication
#####################
# Have Dovecot query our database, and not system users, for authentication.
sed -i "s/#*\(\!include auth-system.conf.ext\)/#\1/" /etc/dovecot/conf.d/10-auth.conf
sed -i "s/#\(\!include auth-sql.conf.ext\)/\1/" /etc/dovecot/conf.d/10-auth.conf
# Specify how the database is to be queried for user authentication (passdb)
# and where user mailboxes are stored (userdb).
cat > /etc/dovecot/conf.d/auth-sql.conf.ext << EOF;
passdb {
driver = sql
args = /etc/dovecot/dovecot-sql.conf.ext
}
userdb {
driver = static
args = uid=mail gid=mail home=$STORAGE_ROOT/mail/mailboxes/%d/%n
}
EOF
# Configure the SQL to query for a user's password.
cat > /etc/dovecot/dovecot-sql.conf.ext << EOF;
driver = sqlite
connect = $db_path
default_pass_scheme = SHA512-CRYPT
password_query = SELECT email as user, password FROM users WHERE email='%u';
EOF
chmod 0600 /etc/dovecot/dovecot-sql.conf.ext # per Dovecot instructions
# Have Dovecot provide an authorization service that Postfix can access & use.
# Drew Crawford sets the auth-worker process to run as the mail user, but we don't care if it runs as root.
cat > /etc/dovecot/conf.d/99-local-auth.conf << EOF;
service auth {
unix_listener /var/spool/postfix/private/auth {
mode = 0666
user = postfix
group = postfix
}
}
EOF
# And have Postfix use that service.
tools/editconf.py /etc/postfix/main.cf \
smtpd_sasl_type=dovecot \
smtpd_sasl_path=private/auth \
smtpd_sasl_auth_enable=yes
# Destination Validation
########################
# Use a Sqlite3 database to check whether a destination email address exists,
# and to perform any email alias rewrites in Postfix.
tools/editconf.py /etc/postfix/main.cf \
virtual_mailbox_domains=sqlite:/etc/postfix/virtual-mailbox-domains.cf \
virtual_mailbox_maps=sqlite:/etc/postfix/virtual-mailbox-maps.cf \
virtual_alias_maps=sqlite:/etc/postfix/virtual-alias-maps.cf \
local_recipient_maps=\$virtual_mailbox_maps
# SQL statement to check if we handle mail for a domain, either for users or aliases.
cat > /etc/postfix/virtual-mailbox-domains.cf << EOF;
dbpath=$db_path
query = SELECT 1 FROM users WHERE email LIKE '%%@%s' UNION SELECT 1 FROM aliases WHERE source LIKE '%%@%s'
EOF
# SQL statement to check if we handle mail for a user.
cat > /etc/postfix/virtual-mailbox-maps.cf << EOF;
dbpath=$db_path
query = SELECT 1 FROM users WHERE email='%s'
EOF
# SQL statement to rewrite an email address if an alias is present.
cat > /etc/postfix/virtual-alias-maps.cf << EOF;
dbpath=$db_path
query = SELECT destination FROM aliases WHERE source='%s'
EOF
# Restart Services
##################
service postfix restart
service dovecot restart
......@@ -12,7 +12,7 @@
source setup/functions.sh # load our functions
# Install packages.
apt_install spampd razor pyzor dovecot-sieve dovecot-antispam
apt_install spampd razor pyzor dovecot-antispam
# Allow spamassassin to download new rules.
tools/editconf.py /etc/default/spamassassin \
......@@ -21,19 +21,11 @@ tools/editconf.py /etc/default/spamassassin \
# Configure pyzor.
pyzor discover
# Hook into postfix. Replace dovecot with spampd as the mail delivery agent.
tools/editconf.py /etc/postfix/main.cf virtual_transport=lmtp:[127.0.0.1]:10025
# Pass messages on to docevot on port 10026.
# This is actually the default setting but we don't want to lose track of it.
# We've already configured Dovecot to listen on this port.
tools/editconf.py /etc/default/spampd DESTPORT=10026
# Enable the Dovecot sieve plugin which let's us set a script that automatically moves
# spam into the user's Spam mail filter.
# (Note: Be careful if we want to use multiple plugins later.)
sudo sed -i "s/#mail_plugins = .*/mail_plugins = \$mail_plugins sieve/" /etc/dovecot/conf.d/20-lmtp.conf
# Enable the Dovecot antispam plugin to detect when a message moves between folders so we can
# pass it to sa-learn for training. (Be careful if we use multiple plugins later.)
sudo sed -i "s/#mail_plugins = .*/mail_plugins = \$mail_plugins antispam/" /etc/dovecot/conf.d/20-imap.conf
......
......@@ -182,7 +182,9 @@ EOF
. setup/system.sh
. setup/ssl.sh
. setup/dns.sh
. setup/mail.sh
. setup/mail-postfix.sh
. setup/mail-dovecot.sh
. setup/mail-users.sh
. setup/dkim.sh
. setup/spamassassin.sh
. setup/web.sh
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment