有了前两章的概念基础,这章终于步入正题,开始搭建自有的电子邮件系统。系统搭建需要用到两个开源软件:postfix和dovecot。其中postfix 主要实现smtp收件服务器和smtp发件服务器的功能,dovecot主要实现pop3/imap收件的功能。
postfix 安装配置
postfix 是Wietse Venema在IBM的 GPL 协议之下开发的一款 MTA 软件。postfix是Wietse Venema想要为使用最广泛的 sendmail 提供替代品的一个尝试。在 postfix 之前,sendmail 是广泛用于使用的用于邮件传输的 MTA 软件。Postfix试图更快、更容易管理、更安全,同时还与sendmail保持足够的兼容性。
postfix现在是预置在各大主流linux发行版中,且默认服务状态是开启的(所以你的服务器25端口默认是开启的,呵呵)。互联网的设计者当初是想把每一台主机都当成 open relay 来看待,当然互联网发展到现在和他们当初设想的已经大相径庭。如果系统里面没有postfix,可以通过下面的命令进行安装:
centos/redhat:
yum install postfix
debian/ubuntu
apt install postfix
可以通过以下命令查看系统中当前默认的MTA:
[root]# alternatives --display mta
mta - status is manual.
link currently points to /usr/sbin/sendmail.postfix
/usr/sbin/sendmail.postfix - priority 30
slave mta-pam: /etc/pam.d/smtp.postfix
slave mta-mailq: /usr/bin/mailq.postfix
slave mta-newaliases: /usr/bin/newaliases.postfix
slave mta-rmail: /usr/bin/rmail.postfix
slave mta-sendmail: /usr/lib/sendmail.postfix
slave mta-mailqman: /usr/share/man/man1/mailq.postfix.1.gz
slave mta-newaliasesman: /usr/share/man/man1/newaliases.postfix.1.gz
slave mta-aliasesman: /usr/share/man/man5/aliases.postfix.5.gz
slave mta-sendmailman: /usr/share/man/man1/sendmail.postfix.1.gz
Current `best' version is /usr/sbin/sendmail.postfix.
postfix的配置非常复杂,默认的配置文件就有600多行(这还不是全部的配置,很多配置只列在了官方文档中,没写在配置文件里),学习曲线很陡峭,本系列文章仅对于主要配置进行一下说明,其余的配置使用方法可参考官方文档:https://www.postfix.org/postconf.5.html
基础配置
主要是一些邮件服务器的域名、后缀等等一些的配置:
myhostname = mail.abc.mail //邮件服务器主机名,一般为smtp.domain或者mail.domain这样的形式
mydomain = abc.mail //域名,也需要设置
myorigin = $mydomain //设置本地邮件的接收规则,即定义哪些属于本地邮件,一般和mydomain一致
传输安全配置
从之前的系列文章中我们可以了解到,安全性可以主要分为传输安全和身份认证安全。根据电子邮件系统架构图,邮件在传输过程中,跨可信网络区域的传输主要有发送用户MUA-->发送方MTA、发送方MTA-->接收方MTA、接收用户MUA-->接收方MTA这几个环节,其余的MTA至MDA,或者MRA至mailbox等等,一般我们认为都在邮件服务商内部网络区域,安全传输的需求不突出。那么要解决上述的几个may环节的传输安全,技术上来说就是通过SSL/TLS、STARTTLS等方式来解决。传输加密非常重要,否则你的邮件在互联网上就相当于裸奔,任何传输中间环节的网络设备、服务器节点都可以轻易获取你的发送内容。根据谷歌的统计数据,目前gmail上面超过90%的进出站邮件都是通过TLS加密传输的。
那么回到具体的软件,发送用户MUA-->发送方MTA、发送方MTA-->接收方MTA这两个环节是由postfix来解决的,接收用户MUA-->接收方MTA是由dovecot来解决的。postfix 的核心配置是 /etc/postfix/main.cf
和 /etc/postfix/master.cf
这两个文件。注意postfix有smtp和smtpd两个模块,其中smtpd是服务端模块,用于接收客户端或其他MTA发送过来的请求,smtp是客户端模块,用于向其他MTA发送请求,许多配置的前缀也是基于上述描述,要注意区分。
客户端tls安全传输配置:
# stmp config here(smtp client)
# Mandatory (high-grade) TLS encryption.
smtp_tls_security_level = encrypt //与其他smtp服务器建立连接使用encrypt强制加密方式,其他可选项还有none、may等
smtp_tls_mandatory_ciphers = high //要求对方开启高级别的加密传输等级
这样设置只要对方smtp服务器支持tls加密传输,那么postfix在传输邮件时就会开启tls加密会话。
未启用传输加密,以gmail为例,会在收件人下方显示一个红色小锁的图标,提示这封邮件未通过加密传输:
而如果发送方启用了加密传输,则邮件信息中会显示已加密:
服务端安全传输配置:
# stmpd config here(smtp server)
smtpd_tls_security_level = may //安全级别,may意思是如果客户端支持tls则使用加密传输,但不强制
smtpd_tls_received_header = yes //把tls认证相关信息加入 Received 标头中
smtpd_tls_cert_file=/etc/ssl/myfullchain.pem //服务端tls证书
smtpd_tls_key_file=/etc/ssl/mykey.pem //服务端tls私钥
这段配置,会使用配置里面的ssl证书,建立tls的安全传输通道。注意这里服务端的参数要选择may,不能开启encrypt进行强制加密,依据是rfc 2487规范,不设置为may可能会导致某些不支持加密的邮件服务商发过来的邮件被拒收。具体可查看官方文档:https://www.postfix.org/postconf.5.html#smtpd_tls_security_level
这里碰到个问题,smtpd_tls_security_level 设置为may后,理论上发送方的MTA如果支持tls,应该就会通过starttls 开启加密传输通道,但是实测国内的邮箱服务商如163、189等都还是使用明文传输(qq邮箱是加密的),而gmail、outlook等国际邮件服务商都使用了tls加密,不知道是国内的支持有问题还是配置问题,但163直接发gmail又是加密的,只能说国内邮箱尽量少用吧。
这时候还需要配置 master.cf
这个配置文件,打开465和587监听端口,以允许邮件客户端建立加密连接通道。
smtps inet n - n - - smtpd
submission inet n - n - - smtpd
把上述配置前面的#去除即可。
邮件转发配置
为了防止我们搭建的邮件服务器成为 open relay 被人利用滥发垃圾邮件,邮件转发的配置非常重要。它定义了postfix的smtpd模块对于哪些邮件发送请求是可以处理的,哪些邮件请求是需要拒绝的。核心配置参数为smtpd_relay_restrictions,它的默认值为permit_mynetworks, permit_sasl_authenticated, defer_unauth_destination,下面分别介绍一下:
- permit_mynetworks:允许从本地网络发起的请求,一般需要和邮件服务器在一个子网下,也可以设置特定的ip规则(cidr格式)
- permit_sasl_authenticated:允许通过sasl 用户身份认证的请求
- defer_unauth_destination:拒绝未认证的收件地址
这是一个邮件转发的最佳实践,正常情况下已经足够我们使用。第一个同一子网比较好理解,第二个配置,要求postfix配置一个sasl认证。关于sasl认证,这里不展开讲,否则又是一大篇。这里我们只要知道,postfix默认配置的sasl认证是 cyrus,为了要完成认证,还需要安装 saslauthd 工具,而 cyrus 本身又是一个门面,需要借助其他的工具 pam、/etc/shadow等完成认证,而pam也不做实际的认证,只做集成,还需要配合实际的认证方式。。。总之,为了方便,我们这里不使用默认的cyrus,而使用 dovecot 作为认证方式(postfix只支持这两种方式),可使用 postconf -a
命令查看支持的认证方式。相关配置如下:
smtpd_sasl_auth_enable = yes //开启认证,默认是no,不开启的话 smtpd 将拒绝所有目标地址非本地的发送请求
smtpd_sasl_type = dovecot //sasl的认证方式设置为 dovecot
smtpd_sasl_path = private/auth //认证接口路径,需要和dovecot中的保持一致
smtpd_sasl_authenticated_header = yes //配置完后,postfix 将在日志中记录认证信息
光通过sasl认证身份还不够,我们还必须要保证发件人邮箱和通过认证的用户相匹配,这里需要启用reject_sender_login_mismatch 这个参数(其实就是reject_authenticated_sender_login_mismatch, reject_unauthenticated_sender_login_mismatch 这两个参数的别名),要实现这两个参数,必须要配置smtpd_sender_login_maps,定义认证用户名与发件人邮箱的对应关系。注意,这里使用到了db,也就是需要把配置转换成db文件,postfix才能识别出来。我一开始就是卡在这里,以为做好maps的配置文件就可以,实际是需要转换一下,postfix才能识别的。关于postfix支持的db格式,可以参考这里:https://www.postfix.org/DATABASE_README.html。smtpd_sender_login_maps默认使用的是 Berkeley DB(也支持mysql、Postgres等其他数据库),转换使用的工具为:postmap,具体用法参考:https://www.postfix.org/postmap.1.html。
这里我们先准备一个文本文件 sender_login_maps:
bob@abc.mail bob
postmaster@abc.mail bob
上面的配置,给bob这个用户绑定了两个邮箱,分别是bob@abc.mail 和postmaster@abc.mail,bob用户可以分别以这两个发件人身份往外发件。我们使用postmap把这个配置文件转换成 db 文件:
[root@ethical-ponies-1 ~]# postmap sender_login_maps //将文本文件转换成berleley db
[root@ethical-ponies-1 ~]# postmap -q bob@abc.mail sender_login_maps //根据key查询db文件
bob
把我们做好的db文件进行配置,就可以正常进行发件人校验了:
smtpd_sender_restrictions = reject_sender_login_mismatch
smtpd_sender_login_maps = hash:/etc/postfix/sender_login_maps
到这里我们postfix的基本配置就都完成了,可以看出来这并不是一个开箱即用的配置,还是稍许有点复杂,通过上述配置的postfix的转发规则概括为:
- 发件人为本地邮箱,收件人为非本地邮箱:会进行sasl用户认证及发件人匹配认证,通过后才会转发邮件,相当于smtp服务器的角色
- 发件人为非本地邮箱,收件人为本地邮箱:这类情况相当于mx服务器的角色,会强制要求对方通过tls方式传输邮件,邮件会投递到本机的mailbox中
- 发件人为非本地邮箱,收件人为非本地邮箱:这类其实就是 open relay 了,全部拒绝
基本满足一个邮箱的安全配置,当然为了防止垃圾邮件滥发,一般还需要做spf、dkim、dmarc、rDNS等认证,这个放到后面再讲。
dovecot安装配置
dovecot 是一个实现了 pop3/imap协议的开源软件,通过读取主机的mailbox来将邮件传输到客户端。
dovecot 在系统中没有自带,需要自己安装:
centos/redhat:
yum install dovecot
debian/ubuntu
apt install dovecot
如果你准备使用roundcube这样的webmail,那么dovecot也可以不安装,仅在使用邮件客户端的时候需要安装 dovecot
安全传输设置
dovecot默认启用了tls安全传输,需要进行证书配置
/etc/dovecot/conf.d/10-ssl.conf:
# 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/ssl/myfullchain.pem
ssl_key = </etc/ssl/mykey.pem
身份认证配置
/etc/dovecot/conf.d/10-auth.conf:
# Username formatting before it's looked up from databases. You can use
# 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 = %n
dovocot默认使用pam进行用户认证,正常dovecot认证只能输入用户名,这个配置可以让用户名加上@后面的域名,也可以通过认证,dovecot会忽略@后面的内容,只看前面的用户名(很多邮箱客户端会默认加上@后面的部分作为用户名)
postfix 认证对接
/etc/dovecot/conf.d/10-master.conf:
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
# full permissions to this socket are able to get a list of all usernames and
# get the results of everyone's userdb lookups.
#
# The default 0666 mode allows anyone to connect to the socket, but the
# userdb lookups will succeed only if the userdb returns an "uid" field that
# matches the caller process's UID. Also if caller's uid or gid matches the
# socket's uid or gid the lookup succeeds. Anything else causes a failure.
#
# To give the caller full permissions to lookup all users, set the mode to
# something else than 0666 and Dovecot lets the kernel enforce the
# permissions (e.g. 0777 allows everyone full permissions)
# Postfix smtp-auth
unix_listener /var/spool/postfix/private/auth {
mode = 0666
}
}
配置认证监听的unix套接字地址为/var/spool/postfix/private/auth ,注意这里要和postfix中配置的要一致,这样postfix就可以把sasl认证请求转发给dovecot处理。这样配置的好处是两边的认证方式是一样的,不会出现smtp认证和imap认证不一致的情况。
日志配置
/etc/dovecot/conf.d/10-logging.conf:
# Log file to use for error messages. "syslog" logs to syslog,
# /dev/stderr logs to stderr.
log_path = /var/log/dovecot
防火墙配置
为了有效进行访问安全控制,需要开启防火墙,并打开特定端口,这里以centos自带的firewalld举例,其他防火墙也差不多:
firewalld的命令行工具为firewall-cmd,它有一个zone的概念,通过不同的zone可以配置不同的访问控制规则。我们通过 --add service命令添加相关的服务端口:
[root@ethical-ponies-1 ~]# firewall-cmd --get-zones
block dmz drop external home internal public trusted work
[root@ethical-ponies-1 ~]# firewall-cmd --get-active-zones
dmz
sources:
public
interfaces: eth0 eth1
[root@ethical-ponies-1 ~]# firewall-cmd --get-default-zone
public
[root@ethical-ponies-1 ~]# firewall-cmd --add-service=imaps smtp smtp-submission smtps --permanent
success
[root@ethical-ponies-1 ~]# firewall-cmd --reload
success
[root@ethical-ponies-1 ~]# firewall-cmd --list-all
public (active)
target: default
icmp-block-inversion: no
interfaces: eth0 eth1
sources:
services: dhcpv6-client imaps smtp smtp-submission smtps ssh
ports: 28068/tcp
protocols:
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
上面的命令添加了邮箱相关的服务端口,--permanent 参数告诉防火墙是永久生效的,reload之后参数生效。
这里需要注意的是,对于默认的zone,interfaces和sources这两个参数是不生效的,也就是不匹配其他zone的interfaces和sources规则的流量,都会进默认的zone,里面配置的访问控制规则都会生效。而如果其他zone里面配置了interfaces和sources这两个参数,符合匹配规则的流量会优先进入其他zone,流量适用该zone的访问控制规则。
域名配置
以上各类配置工作就差不多了,要能够正常收邮件,我们还需要进行域名配置。我们需要设置一条mx记录和一条a记录(mx记录可以告诉客户端@abc.mail这个邮箱后缀所指向的mx服务器地址,它只能设置为域名,所以要设置两条,以下为示例,非真实dns服务商):
HOSTNAME | TYPE | ADDRESS / VALUE | TTL |
---|---|---|---|
MX | mail.abc.mail | 3600 | |
A | 123.123.123.123 | 3600 |
调试服务
现在我们的基础搭建工作就完成了,我们可以使用telnet/openssl工具进行smtp/imap服务的调试,调试方式已经在系列二的文章中详细的介绍过了,大家使用命令行方式可以方便的进行发送邮件、收取邮件的调试。注意要善于查看应用日志来解决问题,postfix的日志位置在/var/log/maillog
,dovecot日志位置在/var/log/dovecot
。
参考资料
1、Debian 8 Server搭建Postfix+Dovecot邮件服务器
https://www.linuxdashen.com/debian-8-server%E6%90%AD%E5%BB%BApostfixdovecot%E9%82%AE%E4%BB%B6%E6%9C%8D%E5%8A%A1%E5%99%A8
2、在 CentOS 7 上搭建属于自己的 “完美” 邮件系统
https://zhuanlan.zhihu.com/p/28816035
3、安装和配置 Postfix
https://chloerei.com/2015/04/22/install-and-configure-postfix/
4、The Postfix Mail Server
https://paulgorman.org/technical/postfix.txt.html