CentOS5へのメール環境構築 (2007/11/01)

1.インストールするもの

2.yum設定

centosplus、dries、dagの各レポジトリをyumに設定しておく。 (http://tmcosmos.org/linux/centos/co5.html#yumに詳しい)

3.POP3/IMAP4サーバ

dovecotを使用。 yum パッケージインストール。
% yum install dovecot
% chkconfig --add dovecot; chkconfig dovecot on
設定ポリシーは以下の通り。
設定ファイルは /etc/dovecot.conf、変更点は以下。
protocols = imaps pop3s
mail_location = maildir:~/Maildir
mail_extra_groups = mail
opensslにて秘密鍵を /etc/pki/dovecot/private/dovecot.pem として、 証明書を /etc/pki/dovecot/certs/dovecot.pem として生成。 秘密鍵はroot以外から読めないようにしておく。
% /etc/pki/dovecot/dovecot-openssl.cnf を適宜編集
% /usr/share/doc/dovecot-1.0/examples/mkcert.sh
% chown root /etc/pki/dovecot/private/dovecot.pem
% chmod 600 /etc/pki/dovecot/private/dovecot.pem

4.SMTPサーバ

postfix を使用。 デフォルトではsendmailがインストールされているので、 切り替えのためのツール system-switch-mail も併せて yum からパッケージインストール。
% yum install postfix system-switch-mail
% /usr/bin/system-switch-mail
% chkconfig --add postfix; chkconfig postfix on
postfixの設定ファイルはディレクトリ /etc/postfix 以下。

TLS/SSL

秘密鍵、証明書を用意し(dovecotのものをシンボリックリンクで流用) 設定。
% mkdir /etc/pki/postfix/
% ln -s /etc/pki/dovecot/private/dovecot.pem \
	/etc/pki/postfix/mail.key
% ln -s /etc/pki/dovecot/certs/dovecot.pem \
	/etc/pki/postfix/mail.crt
% chown postfix /etc/pki/postfix/mail.key
% chmod 600 //etc/pki/postfix/mail.key
postfixの設定はmain.cfにて下記の通り。
smtpd_use_tls                           = yes
smtpd_tls_received_header               = yes
smtpd_tls_cert_file                     = /etc/pki/postfix/mail.crt
smtpd_tls_key_file                      = /etc/pki/postfix/mail.key
smtpd_tls_ask_ccert                     = no
smtpd_tls_session_cache_database        = btree:/etc/postfix/smtpd_scache

smtp_use_tls                            = yes
smtp_tls_cert_file                      = /etc/pki/postfix/mail.crt
smtp_tls_key_file                       = /etc/pki/postfix/mail.key
smtp_tls_ask_ccert                      = no
smtp_tls_session_cache_database         = btree:/etc/postfix/smtp_scache

SMTP認証 (SMTP Auth)

cyrus-sasl を使用。 認証に用いる方法はUNIXパスワードを用いることにする、 saslpasswd2 で設定するパスワードは使わない。 ただし、dbだけは作っておく(パスワードは適当に設定)。
% yum install cyrus-sasl
% /usr/sbin/saslpasswd2 -c nobody
% /usr/sbin/saslpasswd2 -d nobody
% chkconfig --add saslauthd; chkconfig saslauthd on
saslpasswd2が作成するdbは/etc/sasldb2。 (バイナリファイルだがパスワード等が見える。)

greylisting

postgreyを使用。yumにてパッケージインストール。
% yum install postgrey
% chkconfig --add postgrey; chkconfig postgrey on
TCP 10023ポートで稼働させることにする。 設定は稼働スクリプト/etc/rc.d/init.d/postgreyに直接記述。
OPTIONS="--inet=10023"
main.cf にて smtpd_recipient_restrinctions として
check_policy_service inet:127.0.0.1:10023
を追加。
postgreyのデータベースファイル(/var/spool/postfix/postgrey/postgrey.db等)に対して、 以下を実行することにより登録内容が参照できる。
% db_dump -p /var/spool/postfix/postgrey/postgrey.db

SPF/SenderID

http://www.openspf.org/Software から最新の postfix-policyd-spf-perl をダウンロード。 アーカイブを解凍して postfix-policyd-spf-perl を /usr/libexec/postfix/postfix-policyd-spf.pl へコピー。
また、必要なパッケージ perl-Mail-SPF をインストール。
% yum perl-Mail-SPF
受信時に送信者のSPFをチェックするには master.cf に以下を記述し、
spf       unix  -       n       n       -       -       spawn
  user=nobody argv=/usr/libexec/postfix/postfix-policyd-spf.pl
main.cf にて smtpd_recipient_restrinctions として
check_policy_service unix:private/spf
を追加。
送信側としてSPFに対応するにはDNS(BIND)の設定で、 送信者メールアドレスのドメイン(ホスト)に対して TXTレコードを追加。(書き方については省略、他サイトを参照)
最初は以下が無難か。
        IN      TXT     "v=spf1 ip4:ネットワーク/マスク ip6:v6ネットワーク/マスク ~all"

DKIM

dkimproxy を用いて稼働させることもできたが、 受信時、送信時ともにtcpポート間でフィルターをかけるため 複雑な設定があまり美しくない気もするので (dkim/domainkey両方に対応すると更に複雑) dkim-milterを使用することにする。 (2008/03/05追記2参照)
用意されたパッケージがないので、 http://sourceforge.net/projects/dkim-milter/ から最新ソースをダウンロード。 2007/11/01の時点ではstableバージョンでは dkim-milter-2.3.2 が最新。 解凍したファイル dkim-filter/README にある通り、 受信したメールのDomainKeyチェックを行うには http://sourceforge.net/projects/dk-milter/ から dk-milter の最新版ソースをダウンロードし(2007/11/01の時点でバージョン0.6.0)、 libdk を dkim-milter の展開ディレクトリにコピーorシンボリックリンク。 (送信するメールにDomainKeyを設定することはできないようだ) DomainKeyへの対応を設定すると同時に、 devtool/OS/Linux ではデフォルトのマニュアル配置場所が /usr/man なので変更を、 設定ファイル devtool/Site/site.config.m4 に記述。
define(`confMANROOT', `/usr/share/man/man')
define(`bld_VERIFY_DOMAINKEYS', `true')
define(`bld_USE_ARLIB', `true')
コンパイルには sendmail 付属のライブラリが必要なので パッケージ sendmail-devel、openssl-devel(と依存関係のあるもの) を あらかじめインストール。 dkim-milter のインストールは checkinstall を用いて(yumでインストール可、rpm-buildおよび依存パッケージも必要)、 rpmを作成して行う。
% yum install sendmail-devel openssl-devel
% make
% checkinstall --exclude=/selinux -R
% rpm -i /usr/src/redhat/RPMS/i386/dkim-milter-2.3.2-1.i386.rpm
dkim-milterを動かすためにユーザを作成する。
% useradd -g mail -m -d /var/milter -s /sbin/nologin milter
% chmod 755 /var/milter
DKIMで用いるセレクタ名を決める(任意の文字列)。 秘密鍵を /etc/pki/dkim-filter/セレクタ名.private として生成し、 所有者 milter、グループ mailとして 0640 パーミッションで配置。
% openssl genrsa -out /etc/pki/dkim-filter/セレクタ名.private 1024
公開鍵を得る。
% openssl rsa -in /etc/pki/dkim-filter/セレクタ名.private -pubout
DNSにDKIMのための値を登録する。 上記の公開鍵の内容を「セレクタ名._domainkey.ドメイン名」のTXTレコード内に直接記述する。 (記述方法の詳細は省略、他サイト参照)
_domainkey              IN      TXT     "t=y; o=~;"
セレクタ名._domainkey    IN      TXT     "v=DKIM1; k=rsa; t=y; p=公開鍵"
_policy._domainkey      IN      TXT     "t=y; o=~"
起動のためのスクリプト /etc/rc.d/init.d/dkim-filter を作成。 (chkconfigの値は、postfixの値と整合を取るように設定)
#!/bin/bash
#
#
# dkim-filter:
#
# chkconfig: 2345 75 35
# processname: dkim-filter
# description: dkim filter
source /etc/rc.d/init.d/functions

PROG=/usr/bin/dkim-filter

PID=/var/milter/dkim-filter.pid
SOCKET=/var/milter/dkim-filter.socket

DOMAINLIST="ドメイン"           # 複数ある場合はカンマ区切り
SELECTOR="セレクタ名"           # セレクタ名は複数ドメインでも共通
KEY="/etc/pki/dkim-filter/${SELECTOR}.private"

RETVAL=0

start() {
    echo -n $"Starting dkim-filter: "
    daemon --user milter \
        "umask 117; $PROG -p local:$SOCKET -d $DOMAINLIST -k $KEY -l -P $PID -s $SELECTOR"
    RETVAL=$?
    echo
    [ $RETVAL -eq 0 ] && touch /var/lock/subsys/dkim-filter
    return $RETVAL
}

stop() {
    echo -n $"Shutting down dkim-filter: "
    killproc $PROG
    rm -f $SOCKET
    RETVAL=$?
    echo
    return $RETVAL
}

restart() {
    stop
    start
}

case "$1" in
  start)
    start
    ;;

  stop)
    stop
    ;;
  restart)
    restart
    ;;
  status)
    status $PROG
    RETVAL=$?
    ;;
  *)
    echo $"Usage: $0 {start|stop|restart|status}"
    RETVAL=1
esac

exit;
起動スクリプトを有効化。
% chkconfig --add dkim-filter; chkconfig dkim-filter on
postfixには、main.cfに以下を設定する。
smtpd_milters = unix:/var/milter/dkim-filter.socket
non_smtpd_milters = $smtpd_milters
ただし、フィルタを経由させる目的で 異なるtcpポートを使って転送させているものがある場合には、 master.cf の各エントリに
  -o smtpd_milters=
を追加する必要がある。(後述のamavisの設定では必要となる)

ウイルス検出、スパム判定

avavisd-new、spamassassin、clamd(clamav) を yum にてインストール。 /etc/group を編集し、ユーザ clamav をグループ amavis に追加しておく。
% yum install amavisd-new clamd spamassassin
% chkconfig --add amavisd; chkconfig amavisd on
% chkconfig --add spamassassin; chkconfig spamassassin on
% chkconfig --add clamd; chkconfig clamd on
% エディタ /etc/group
amavisdの設定は/etc/amavisd.confにて行う。
$mydomain = 'ドメイン名';
...
$sa_tag_level_deflt  = 0.0;
$sa_tag2_level_deflt = 13.0;
#$sa_kill_level_deflt = 6.9;
#$sa_dsn_cutoff_level = 10;
...
#$sa_spam_subject_tag = '***SPAM*** ';
...
$final_spam_destiny       = D_PASS;
...
@av_scanners = (
### http://www.clamav.net/
['ClamAV-clamd',
  \&ask_daemon, ["CONTSCAN {}\n", "/var/run/clamav/clamd.socket"],
  qr/\bOK$/, qr/\bFOUND$/,
  qr/^.*?: (?!Infected Archive)(.*) FOUND$/ ],
# NOTE: run clamd under the same user as amavisd, or run it under its own
#   uid such as clamav, add user clamav to the amavis group, and then add
#   AllowSupplementaryGroups to clamd.conf;
# NOTE: match socket name (LocalSocket) in clamav.conf to the socket name in
#   this entry; when running chrooted one may prefer socket "$MYHOME/clamd".
);
postfix へは、 main.cf に以下を設定し、
content_filter=smtp-amavis:[127.0.0.1]:10024
master.cf には以下を追記する。
smtp-amavis
          unix  -       -       n       -       2       smtp
  -o smtp_data_done_timeout=1200
  -o smtp_send_xforwardommand=yes
  -o disable_dns_lookups=yes
  -o smtpd_milters=
127.0.0.1:10025
          inet  n       -       n       -       -       smtpd
  -o content_filter=
  -o local_recipient_maps=
  -o relay_recipient_maps=
  -o smtpd_restriction_classes=
  -o smtpd_client_restrictions=
  -o smtpd_helo_restrictions=
  -o smtpd_sender_restrictions=
  -o smtpd_recipient_restrictions=permit_mynetworks,reject
  -o mynetworks=127.0.0.0/8
  -o strict_rfc821_envelopes=yes
  -o smtpd_error_sleep_time=0
  -o smtpd_soft_error_limit=1001
  -o smtpd_hard_error_limit=1000
  -o smtpd_milters=
/etc/clamd.conf にて、LocalSocket を設定。 tcp接続は行わないので該当箇所はコメントアウト。
LocalSocket /var/run/clamav/clamd.socket
...
#TCPSocket 3310
...
#TCPAddr 127.0.0.1
spamassassinの設定ファイル(/etc/mail/spamassassin/以下)は tlecサイトのものを頂き、定期的な更新を設定。 /etc/cron.weekly/spamassassin を以下の通り作成(一度手動で実行しておく)。 もちろんweeklyじゃなくdailyでもmonthlyでも可。
#!/bin/sh

if [ ! -d /etc/mail/spamassassin ]; then
    exit;
fi

cd /etc/mail/spamassassin

if [ -f user_prefs ]; then
    rm user_prefs;
fi

wget -qN http://tlec.linux.or.jp/docs/user_prefs
if [ ! -f user_prefs ]; then
    exit;
fi

echo "report_safe 0" >> user_prefs
mv user_prefs local.cf

/etc/rc.d/init.d/spamassassin restart >/dev/null
その他の spamassassin 設定として、 v310.pre にて以下を有効にする。
loadplugin Mail::SpamAssassin::Plugin::TextCat
loadplugin Mail::SpamAssassin::Plugin::DomainKeys
Mail::SpamAssassin::Plugin::DomainKeys には パッケージ perl-Mail-DomainKeys のインストールが必要。
v312.pre にて以下を有効にする。
loadplugin Mail::SpamAssassin::Plugin::DKIM
※v320.preとあわせて、他にもロードしたいプラグインがあれば有効にする

メーリングリスト

mailmanを使用。
% yum install mailman
% chkconfig --add mailman; chkconfig mailman on
httpd(apache)の設定(/etc/httpd/conf.d/mailman.conf)や mailman自体の設定は省略。

postfix設定まとめ

main.cf から関連項目のみ抜粋:
# Maildir
home_mailbox = Maildir/


# SMTP Auth
smtpd_sasl_auth_enable = yes
smtpd_sasl_authenticated_header = yes

smtpd_client_restrictions =
        permit_mynetworks,
        reject_non_fqdn_recipient,
        reject_unknown_recipient_domain,
        reject_rbl_client all.rbl.jp,
        permit

smtpd_sender_restrictions =
        permit_mynetworks,
        reject_non_fqdn_sender,
        reject_unknown_sender_domain,
        permit

smtpd_recipient_restrictions =
        permit_mynetworks,
        permit_sasl_authenticated,
        reject_non_fqdn_recipient,
        reject_unlisted_recipient,
        reject_unknown_recipient_domain,
        reject_unauth_destination,
        check_policy_service unix:private/spf,          # spf
        check_policy_service inet:127.0.0.1:10023,      # postgrey
        permit_auth_destination,
        reject

# TLS/SSL
smtpd_use_tls                           = yes
smtpd_tls_received_header               = yes
smtpd_tls_cert_file                     = /etc/pki/postfix/mail.crt
smtpd_tls_key_file                      = /etc/pki/postfix/mail.key
smtpd_tls_ask_ccert                     = no
smtpd_tls_session_cache_database        = btree:/etc/postfix/smtpd_scache

smtp_use_tls                            = yes
smtp_tls_cert_file                      = /etc/pki/postfix/mail.crt
smtp_tls_key_file                       = /etc/pki/postfix/mail.key
smtp_tls_ask_ccert                      = no
smtp_tls_session_cache_database         = btree:/etc/postfix/smtp_scache

#dkim
smtpd_milters = unix:/var/milter/dkim-filter.socket
non_smtpd_milters = $smtpd_milters

# amavis
content_filter=smtp-amavis:[127.0.0.1]:10024

# mailman
owner_request_special = no
recipient_delimiter = +
master.cf から関連項目のみ抜粋:
#
# SPF/SenderID (http://www.openspf.org/)
#
spf       unix  -       n       n       -       -       spawn
  user=nobody argv=/usr/libexec/postfix/postfix-policyd-spf.pl

#
# amavis
#
smtp-amavis
          unix  -       -       n       -       2       smtp
  -o smtp_data_done_timeout=1200
  -o smtp_send_xforwardommand=yes
  -o disable_dns_lookups=yes
  -o smtpd_milters=
127.0.0.1:10025
          inet  n       -       n       -       -       smtpd
  -o content_filter=
  -o local_recipient_maps=
  -o relay_recipient_maps=
  -o smtpd_restriction_classes=
  -o smtpd_client_restrictions=
  -o smtpd_helo_restrictions=
  -o smtpd_sender_restrictions=
  -o smtpd_recipient_restrictions=permit_mynetworks,reject
  -o mynetworks=127.0.0.0/8
  -o strict_rfc821_envelopes=yes
  -o smtpd_error_sleep_time=0
  -o smtpd_soft_error_limit=1001
  -o smtpd_hard_error_limit=1000
  -o smtpd_milters=

5.稼働

chkconfigで追加設定したプログラムを /sbin/service コマンドや 直接 /etc/rc.d/init.d/ 以下のそれぞれのスクリプトから起動させる。
(あるいはOS再起動)
以下の宛先にメールを送るとSPF/SenderID、DKIMのテストができる。

余談

証明書は CAcert.org あたりで用意するのも吉。 その際は postfix では main.cf にて、ダウンロードしたルート証明書の設定を。
smtpd_tls_CAfile                        = /etc/postfix/certs/root.crt

smtp_tls_CAfile                         = /etc/postfix/certs/root.crt
dovecot の場合は、 ルート証明書を ssl_cert_file に包含させるようだ。

2008/03/05追記1

数多くの宛先(To/Cc/Bcc)を設定すると postfix/cleanup からエラーメッセージとして
... can't read SMFIC_HEADER reply packet header: Connection reset by peer
... milter-reject: END-OF-MESSAGE from ホスト[IPアドレス]: 4.7.1 Service unavailable - try again later; from=...
が表示され送信できない模様。
解決策は模索中。

2008/03/05追記2

dkim-milter のバージョンは 2.4.4 が最新(プレリリースなら2.5.0もある)。
tcp ソケットでも動作することが判明。 起動スクリプト /etc/rc.d/init.d/dkim-filter は以下に変更すればよい。 (変数 SOCKET と関連箇所を変更しただけ)
(snip)

#SOCKET=local:/var/milter/dkim-filter.socket
SOCKET=inet:10026

(snip)

start() {
    echo -n $"Starting dkim-filter: "
    daemon --user milter \
	"umask 117; $PROG -p $SOCKET -d $DOMAINLIST -k $KEY -l -P $PID -s $SELECTOR"
    RETVAL=$?
    echo
    [ $RETVAL -eq 0 ] && touch /var/lock/subsys/dkim-filter
    return $RETVAL
}

(snip)

stop() {
    echo -n $"Shutting down dkim-filter: "
    killproc $PROG
#   rm -f $SOCKET
    RETVAL=$?
    echo
    return $RETVAL
}
また、postfix の dkim 設定部分も
#dkim
#smtpd_milters = unix:/var/milter/dkim-filter.socket
smtpd_milters = inet:10026
non_smtpd_milters = $smtpd_milters
に変更。
他のサーバで dkim-filter を動かす場合には
smtpd_milters = inet:サーバホスト:10026
とすればよい。 (ファイアウォールの設定等は必要に応じて設定)

2009/03/10 追記

SPF/SenderID について、IIJから ENMA がリリースされている。