Linux/CentOS Stream8でサーバ構築/メール編

メール関連(2022-03-11)


引き続き、CentOS Stream8での作業となります。*1

そして前提条件としてドメイン名とサーバ証明書を取得済みであること。
(IPアドレス直指定でも動くと思いますが、私が試していないので…)
あと通信には基本的にSSL/TLSを使います(smtps/pop3s/imaps)。


SASLのインストール

postfix, dovecot で認証に使うsaslauthd をインストールします。

$ dnf install cyrus-sasl

無事にインストールできたら起動します。config設定は特に変更なしです。

 $ systemctl enable saslauthd
 $ systemctl start  saslauthd

postfixのインストール

メール送受信に必要なパッケージをインストールします。

$ dnf install postfix

以下、各パラメータについては「postfix 各パラメータ名」でググれば postfix-jp.info に行き着くと思います。自分が使うパラメータについて一度ざっと目を通しておきましょう。

それぞれ後述する dovecot、opendkim、spf、spamassasin と<b>連携させた後</b>の設定を記載しています。
(なのでTLSやSASLを使わない、SpamAssasinと連携させない場合はもっと簡易な設定になると思います)

まずは /etc/postfix/main.cf の変更箇所です。

mydomain = 自分のドメイン
inet_interfaces = all    # 必要に応じてIPアドレス等を指定
inet_protocols = ipv4    # v4とv6両方ならば all を指定
mydestination = $myhostname, localhost.$mydomain, localhost
mynetworks = 127.0.0.0/8

# ここでは Mailbox ではなく Maildir/ スタイルで指定しています(/を指定)
# /etc/default/useradd 設定で CREATE_MAIL_SPOOL=no にしておいて
# "chmod 777 /var/spool/mail" で送受信時にディレクリを自動生成させます
mail_spool_directory = /var/spool/mail/  # 語尾の"/"の有無に注意!

smtpd_banner = $myhostname ESMTP hoge # myhostnameは必須だけど他は隠したかったので(=hoge)
smtpd_tls_cert_file = 証明書のPATH    # letsencrypt ならば live/ドメイン名/fullchain.pem を指定
smtpd_tls_key_file = 秘密鍵のPATH     # letsencrypt ならば live/ドメイン名/privkey.pem を指定

smtpd_sasl_security_options = noanonymous
 smtpd_sasl_tls_security_options = $smtpd_sasl_security_options
 smtpd_sasl_auth_enable = yes
 smtpd_recipient_restrictions =
         permit_mynetworks
         permit_sasl_authenticated
         reject_unauth_destination
         check_policy_service unix:private/policy-spf  # policy は master.cf へ記述
 policy-spf_time_limit = 1800     # policy-spf の time_limit を設定
 # broken_sasl_auth_clients = yes # 古いMicroSoft Outlook Expressとかに対応するらしい
 smtpd_sasl_type = dovecot
 smtpd_sasl_path = private/auth # /var/spool/postfix/private/auth を相対PATHで
 smtpd_sasl_local_domain = $myhostname
 
 smtpd_milters = inet:127.0.0.1:8891  # opendkimに合わせる
 non_smtpd_milters = $smtpd_milters
 milter_default_action = accept # ゆるめ(accept)、SpamAssassinと連携する目的

上記コメント内にも書きましたが、
今回はOSインストール後に useradd でメールボックスを作らない設定にしています。
メール送受信時に各ユーザで自力で書き込めるようにするために、
「chmod 777 /var/spool/mail」を忘れずに。

IPv4のみにしている(IPv6を使わない)のは手抜きです。いずれv6対応すると思います。*2

/etc/postfix/master.cf の方は使う場所のコメントアウト(#)を外して、必要な個所は変更する感じで。
注意点として先頭一文字目の空欄は前行との連結とみなされるので、うっかりスペースを入れたり削ったりしないように。
以下、変更箇所のみ抜粋。

# smtpを SpamAssasinと連携させる
smtp      inet  n       -       n       -       -       smtpd -o content_filter=spamfilter

# submissionポートはISP経由で自サーバにアクセスするために必要
submission inet n       -       n       -       -       smtpd
   -o syslog_name=postfix/submission
   -o smtpd_tls_security_level=encrypt
   -o smtpd_sasl_auth_enable=yes
   -o smtpd_tls_auth_only=yes
   -o smtpd_client_restrictions=permit_sasl_authenticated,reject
   -o smtpd_relay_restrictions=permit_sasl_authenticated,reject
   -o milter_macro_daemon_name=ORIGINATING
 
 # smtps を有効化する
 smtps     inet  n       -       n       -       -       smtpd
   -o syslog_name=postfix/smtps
   -o smtpd_tls_wrappermode=yes
   -o smtpd_sasl_auth_enable=yes
   -o smtpd_client_restrictions=permit_sasl_authenticated,reject
   -o smtpd_relay_restrictions=permit_sasl_authenticated,reject
   -o milter_macro_daemon_name=ORIGINATING
 
 # main.cf で書いた policy-spfとの連携用の設定
 # policyd-spf のPATHは rpm -ql pypolicyd-spf などで確認し、phython3のPATHも合わせる
 policy-spf  unix  -       n       n       -       0       spawn
   user=nobody argv=/usr/bin/python3 /usr/libexec/postfix/policyd-spf
                /etc/python-policyd-spf/policyd-spf.conf
 # master.cf 前段一行目のSpamAssassin との連携用の設定
 # spamfilter.sh は自分で用意する、作り方は後述
 spamfilter unix  -       n       n       -       -       pipe
   flags=Rq user=daemon argv=/usr/bin/spamfilter.sh -oi -f ${sender} ${recipient}



一通り設定したら確認してみましょう。

$ postfix check


問題なければ firewalld のポートを開けます。

$ firewall-cmd --add-service=smtp --zone=public --permanent
$ firewall-cmd --add-service=smtp-submission --zone=public --permanent
$ firewall-cmd --add-service=smtps --zone=public --permanent
$ firewall-cmd --reload
$ firewall-cmd --list-all   # 上記 smtp, smtp-submission, smtps の3つが増えていることを確認

起動します…といっても、この時点ではまだ SpamAssasinや OpenDKIMなど入って無いのでまだ動きませんが、先にコマンドだけ書いておきます。

$ systemctl enable postfix
$ systemctl start  postfix

動作確認は以下で…と思ったら、mailコマンドがまだ入っていませんでした。

$ dnf install mailx

そして、mailコマンドでメールを送るときは以下。

$ echo "this is test mail." | mail -s 件名   誰か@どこか.ne.jp

うまく動かない場合は
master.cf から SpamAssasinを除いたり(smtp ~ content_filter=spamfilter の行を元のフィルタ無し設定に戻す)、
ps -ef で opendkim や dovecot や saslauthd が動いているか grep したりログを見たりして確認しましょう。


これはPCやスマホ側での設定の話ですが、メールを送受信するアプリについて。
この postfix がメール「送信」設定になります。(受信は後述の dovecot)
ポート番号を 587(submissionポート)にして送受信方法をSTARTTLSで試しましょう。
通常の 25(smtp)や 465(smtps、SSL/TLS)を使った直接の接続はISP(インターネット・サービス・プロバイダ)が不許可にしています、たぶん。

dovecotのインストール

メール受信(POP3やIMAP)のために必要なやつです。

$ dnf install dovecot

設定ですが、/etc/dovecot.conf の最初にこう書いてあります。

# If you're in a hurry, see http://wiki2.dovecot.org/QuickConfiguration

(2022/03現在で https://doc.dovecot.org/configuration_manual/quick_configuration/ に移転していましたが)
とにかく、ここに英語で基本的な設定方法は書いてあるので読んでみましょう。英語が苦手? えぇ、実は私も苦手です [worried]


以下は /etc/dovecot/ のconfig設定です。

conf.d/10-mail.conf

mail_location = maildir:/var/spool/mail/%u  # postfix の設定に合わせること

conf.d/10-logging.conf ※変えなくても可、自分が使いやすいように

log_path = /var/log/dovecot.log  # syslogとは別にしておきたい
auth_verbose = yes               # 解析用にログを細かく出しておく
auth_verbose_passwords = yes     # 自分用サーバなのでログイン失敗passwdも表示してみる
verbose_ssl = yes                # 解析用にSSL動作ログも出す

conf.d/10-ssl.conf

ssl_cert = </証明書のPATH  # letsencrypt なら live/ドメイン/fullchain.pem
ssl_key = </秘密鍵のPATH   # letsencrypt なら live/ドメイン/privkey.pem

# このファイルは自分で作る必要があります
# 作り方は 10-ssl.conf 内にあるコメント文を参照
# -> Generate new params with `openssl dhparam -out /etc/dovecot/dh.pem 4096`
ssl_dh = </etc/dovecot/dh.pem

上記コメントの通り、/etc/dovecot/dh.pem を別途作成する必要があります。

conf.d/10-master.conf

  inet_listener imaps {
    port = 993   # コメントを外す
    ssl = yes    # コメントを外す
  }

  inet_listener pop3s {
    port = 995   # コメントを外す
    ssl = yes    # コメントを外す
  }

  unix_listener /var/spool/postfix/private/auth {
    mode = 0666       # コメントを外す
    group = postfix   # 追記、postfix に合わせる
    user = postfix    # 追記、postfix に合わせる
  }


最後に、今回は IPv4のみに限るので以下を設定します。
/etc/dovecot/dovecot.conf

listen = *  # v4v6両方なら "*, ::" にする



設定できたら firewalld のポートを開けます。

$ firewall-cmd --add-service=pop3s --zone=public --permanent
$ firewall-cmd --add-service=imaps --zone=public --permanent
$ firewall-cmd --reload
$ firewall-cmd --list-all   # 上記 smtp, smtp-submission, smtps の3つが増えていることを確認

起動します。

$ systemctl enable dovecot
$ systemctl start  dovecot


これはPCやスマホ側での設定の話ですが、メールを送受信するアプリについて。
この dovecot がメール「受信」設定になります。(送信は前述の postfix)
ポート番号を 995(pop3s)や993(imaps)にして送受信方法を SSL/TLSにしましょう。

opendkimのインストール

DKIM認証を行うために追加します。フィッシングメールが多い昨今、ぜひ導入しておきたいです。
(詳細はここでは触れませんが(検索:DKIMとは)、送信元で署名をつけて本人確認するための仕組みです。最近の迷惑メールはもう Fromヘッダーとかも詐称して送ってきますので…)

$ dnf --enablerepo=epel install opendkim

インストールすると opendkimユーザが新たに増えます。

署名用の秘密鍵、DNS記載用の公開鍵の作成

$ mkdir /etc/opendkim/keys/ドメイン名
$ cd  /etc/opendkim/keys/ドメイン名
$ opendkim-genkey -d ドメイン名 -s セレクタ名
$ chown -R opendkim:opendkim ../ドメイン名 
$ ls
 セレクタ名.private  セレクタ名.txt  (秘密鍵と、DNSに書くTXTの2ファイル)

鍵のサイズなどの初期値は man opendkim-genkey で確認できます。

(参考)さくらのVPSでのドメイン設定(DKIM)

私の場合はドメイン名をさくらインターネットで取得しているので、そこでDKIM設定も行います。
さくらのVPSにログインして、コントロールパネルからDNS設定画面に行きます。
(VPSのコンソール設定画面から - DNS登録 - ドメインコントロールパネル - ドメインを選択して - ゾーン画面 - 「編集」ボタン)

ともかく前述の opendkim-genkey で生成された「セレクタ.txt」の中身をお手持ちのDNSサーバに反映する必要があります。

エントリ名: セレクタ名._domainkey
タイプ: テキスト(TXT)
データ: カッコで囲まれた長いやつ「"v=DKIM1;(中略)p=~"」
     (ダブルクウォート(")は先頭と末尾だけに付け直した方がいいかも)


結果は自分のサーバ上で digコマンドを使って確認できます。

$ dig セレクタ名._domainkey.自分のドメイン  txt
 (自分で設定した v=DKIM1; k=rsa;~ が取得できるはず)

鍵の設定

引き続きDKIM認証に必要な鍵を設定します。

$ cd /etc/opendkim
$ vi KeyTable
 セレクタ._domainkey.ドメイン  ドメイン:セレクタ名:/etc/opendkim/keys/ドメイン/セレクタ.private
(私の場合は s._domainkey.null-i.net null-i.net:s:/etc/opendkim/keys/null-i.net/s.private)

$ vi SigningTable
 *@ドメイン セレクタ._domainkey.ドメイン
(私の場合は *@null-i.net  s._domainkey.null-i.net)

/etc/opendkim.conf を更新して鍵ファイルを指定します… どうして /etc/opendkim.conf にインストールされるんでしょうね?
(/etc 直下よりも他と同じ /etc/opendkim に置いた方がおさまりが良い気がするんですが…)

# KeyFile               /var/db/dkim/example.private  # コメントアウト
KeyTable                refile:/etc/opendkim/KeyTable

起動と動作確認

 $ systemctl enable opendkim
 $ systemctl start  opendkim

確認はまだこの後にSpamAssassinを入れた後になる話ですが、 メモだけここに先に書きます。

このサーバからメールを送信して、メールの受信先でメールのヘッダを見てみましょう。

Outlookだとメールのプロパティとかで確認できます。
サーバにログインして mailコマンドや /var/spool/mail/ユーザ/ の new/やら cur/やらを直読みしても見れます。
その中に

Authentication-Results: (中略)dkim=pass (ok);

のような記述があればOK。
それ以外で
「dkim=neutral (no sig); 」署名無し、とか
「dkim=permerror (bad sig);」署名エラー、とかになった場合は、
残念ながら、うまくいっていません。

あと、ローカル無いの送受信では付きません、サーバ間をまたいだメールで確認しましょう。主要なプロバイダのメールならDKIMヘッダを付けたり確認したりしていると思います。

SPFのインストール

DKIMと同じく、メール認証の強化を行います。特にSpamAssassinで判定するためにもぜひ入れておきたい。

$ dnf --enablerepo=epel install pypolicyd-spf

そして /etc/python-policyd-spf/policyd-spf.conf を少し変えました。

$ vi /etc/python-policyd-spf/policyd-spf.conf
HELO_reject = False         # Fail から False へ変更
Mail_From_reject = False    # Fail から False へ変更

今回はSPF認証に失敗した場合もそのままスルーしつつ、SpamAssassinでスパム判定させます。

(参考)さくらのVPSでのドメイン設定(SPF)

私の場合はドメイン名をさくらインターネットで取得しているので、そこでSPF設定も行います。
さくらのVPSにログインして、コントロールパネルからDNS設定画面に行きます。
(VPSのコンソール設定画面から - DNS登録 - ドメインコントロールパネル - ドメインを選択して - ゾーン画面 - 「編集」ボタン)

エントリ名: 自分のドメインやサブドメイン(@とかを指定)
タイプ: テキスト(TXT)
データ: "v=spf1 ip4:xx.xx.xx.xx -all" など(xx.xx.xx.xxは自分のIPアドレス)

SpamaAsassin のインストール

スパムメールを殺す係です。

$ dnf install spamassassin

/etc/mail/spamassassin/local.cf はそのままでも良いですが、例えば「add_header ham HAM-Report _REPORT_」とかを追加するとSPAM判定の詳細が分かるようになります。
各パラメータについては「perldoc Mail::SpamAssassin::Conf」で確認できます。

postfix との連携方法は、以下が参考になります。
https://wiki.apache.org/spamassassin/IntegratedSpamdInPostfix
この例にならって、PATH は直して、/usr/bin/spamfilter.sh を作りました。

/usr/bin/spamfilter.sh

#!/bin/sh
SENDMAIL=/usr/sbin/sendmail   # 自分の環境のsendmailに合わせる
#SPAMASSASSIN=/usr/bin/spamc  # 負荷が増えたら spamc & spamd 構成へ移行予定。
SPAMASSASSIN=/usr/bin/spamassassin # こちらは spamd ではなくコマンドライン方式

logger <<<"Spam filter piping to SpamAssassin, then to: $SENDMAIL $@"
${SPAMASSASSIN} | ${SENDMAIL} "$@"

exit $?

上記では動作確認用にメール受信の度に loggerで syslog(=/var/log/messages)に書いてますが、動作確認できたら削除します。
上のコメントに書いている通り、
spamc(クライアント)から常駐させた spamd へ処理を依頼する形の方が処理効率は良いらしいのですが、まずはシンプルに受信の都度 spamassassin コマンドを起動する形にしました*3
動作の詳細は「man spamc」などでも確認できます。

あとは実行権限を変えます。

$ chmod 755 /usr/bin/spamfilter.sh
(そしてこのshellスクリプトを前述の /etc/postfix/master.cf の中で呼んでいます)


それから、/etc/sysconfig/sa-update を更新。定期的にチェックルールを更新してもらいます。

$ vi /etc/sysconfig/sa-update
SAUPDATE=yes  にする

これでメール送受信ができるようになったはずです。

動作確認

あらためて、コマンドラインでメールを送ります。mailxパッケージをインストールしてから以下。

$ echo "this is test mail." | mail -s 件名   誰か@どこか.ne.jp

自サーバ内だけでのやりとりだとSPFやDKIMなどの確認はできませんが、
外部のメールサーバを経由して送受信すれば以下のようなメールヘッダが付与されているはずです。

Authentication-Results: (中略)dkim=pass  # DKIM認証に問題が無い
Received-SPF: Pass           # SPF確認に問題が無い
X-Spam-Status: No, score=~  # SpamAssasinの判定。デフォルトだとscore=5以上でスパム扱い
DKIM-Signature: ~           # 送信者が送ってきたDKIM署名、
                             # そもそも送信者側がDKIM未対応なら付与されない

メールアプリによっては上記のヘッダ部分が読めないかもしれません。
(たとえばMicrosoft Outlook とかなら メールのプロパティから読めます)
サーバ上なら mail コマンドで読めます、または、/var/spool/mail/ユーザ名/new/ の下に(既読ならcur/の下に)メールが入るので less コマンドとかで直接確認することもできます。

もしスパムメールと判定された場合は、SpamAssassinによってメールの件名に[SPAM]が追加されるはずです。

中身の文章に対する判定には大した効果はないですが、送信元に対してはブラックリストとつき合わせて判定してくれたりするので、海外からの詐称メールも多いこの頃ではきっと重宝することになるでしょう。


備忘録として、SpamAssasinを経由したときに中継ループしてしまう場合は sendmailが上手くいっていない可能性があります。
postfix の mynetwork に不備があると(前述のmynetworks = 127.0.0.0/8など)自分自身から自分自身へ転送し続けてしまいます。*4

設定ミスでループしてしまった場合は systemctl stop postfix で一旦止めた後に、メールのキューを削除しましょう。

$ postqueue -p      # メールのキューの一覧を表示
$ postsuper -d ID名 # 指定したキューを削除
(ぜんぶ消す場合は postsuper -d ALL)

以上、メール関連の設定でした。

次は サーバ構築/Webサーバ編 です。


*1 お手持ちのOSバージョンは「cat /etc/redhat-release」で確認できます。
*2 別で自力で作ってるファイアウォールがまだIPv4しか対応していないのと、使っている端末からのアクセスがv4のみだったのでIPv6は後回しです
*3 少ないメールのためにわざわざ spamdを常駐するのも気が引けるし、そんなに処理スピードは求めていないので
*4 CentOS7以降でsendmailが非推奨になった影響か、/sbin/sendmail の中身が旧sendmail からsendmail.postfixへと新旧OSで異なっていたりします。だから旧OSで問題なかったのに新OSだと失敗なんてこともあります