Linux/postfix、dovecotのSSL対応

メールサーバのSSL化(2016-06-19、更新: 2018-09-22)


(※ここにある情報は古いです。CentOS Stream8での手順 を別途メモしています)


postfix と dovecot を統合しつつ、SSLで通信するようにします。
(前回の postfixインストールdovecotインストール の続きです。)
以下、環境は CentOS 7 です。


はじめに saslauth

postfix のログイン認証も dovecot 側と統合させたいので、SASL認証を導入します。

# yum install cyrus-sasl-devel
# which saslauthd
/sbin/saslauthd
# vi /etc/sysconfig/saslauthd
MECH=shadow  # pamからshadowへ変更。PAMは後日改めて・・・

CentOS 7 など、systemd 環境なら以下。

# systemctl enable  saslauthd

あるいは、/etc/init.d に起動スクリプトを作って chkconfig --add で登録します。
「service saslauthd start」等で起動できると思います。

Dovecot のSSL関連設定

まず、Dovecotの設定から。

conf.d/10-master.conf

service imap-login {
 inet_listener imap {
   #port = 143 # コメントアウト
   port = 0    # 追記
 }
 inet_listener imaps {
   port = 993  # コメント外す
   ssl = yes   # コメント外す
 }

service pop3-login {
  inet_listener pop3 {
    #port = 110 # コメントアウト
    port = 0    # 追記
  }
  inet_listener pop3s {
    port = 995  # コメント外す
    ssl = yes   # コメント外す
  }
  
 # Postfix smtp-auth
 unix_listener /var/spool/postfix/private/auth { # コメント外す
   mode = 0666      # コメント外す
   group = postfix  # 追記
   user = postfix   # 追記
 }

unix_listener はpostfix と連携させるために必要。
アカウント認証をdovecotとpostfixで別々にやらずに、dovecot側で一元管理させるためにやっています。
よって、unix_listener は postfix と divecotで同じPATH設定にしなければいけません。
(postfix のログで、「warning: SASL: Connect to ~~ failed: Permission denied」となったら、この設定が怪しい)

conf.d/10-auth.conf

disable_plaintext_auth = yes

暗号化するのが目的なので、平文で認証を行わないようにします。

conf.d/10-mail.conf

mail_location = maildir:/var/spool/mail/%u

メールの保存場所。postfix に合わせる。

conf.d/10-ssl.conf

ssl = yes
(中略)
ssl_cert = </etc/postfix/certs/ssl_cert.pem
ssl_key = </etc/postfix/certs/ssl_key.pem
(中略)
ssl_protocols = !SSLv3   # v3にする。v2はNG

最後のssl_protocols は古いバージョン(2.2.26以前?)だとデフォルト値が 「!SSLv2」だったので、
新しめの openssl との組み合わせでエラーになってしまいます。
(「Fatal: Invalid ssl_protocols setting: Unknown protocol 'SSLv2'」
 これはopensslが「SSLv2 support removed」状態なので、v2を認識できないらしい。
 せめて受信時ではなく起動時にエラーが出れば分かりやすいのですが・・・)

  • dovecot-2.3以降の場合は
ssl_min_protocol = TLSv1

のように指定。ssl_protocolは無くなったのかな。
それより、引っかかったのは dovecot-2.3以降のこちらの設定です。

ssl_dh = </etc/dovecot/dh.pem

このパラメータが必須になったようで、2.2から2.3に変えたらエラーになって焦りました。

pop3-login: Error: Failed to initialize SSL server context: Couldn't parse DH parameters:
error:0909006C:PEM routines:get_name:no start line: Expecting: DH PARAMETERS:

これは、conf.d/10-ssl.conf の "ssl_dh = </etc/dovecot/dh.pem" の説明にもあるように、

# openssl dhparam -out /etc/dovecot/dh.pem 4096

のように実行して新しくDHファイルを作れ、ということみたいですね。
作成には時間がかかりますが(take a long timeって言われる)まぁ、実行して気長に待ちましょう。

そして必要なサーバ証明書を設定。
以下はオレオレ証明書の作成の例です。 (詳細は Linux/OpenSSL を参照。)

# mkdir -p /etc/postfix/certs/
# cd /etc/postfix/certs/
# openssl req -new -x509 -days 3650 -nodes -out ssl_cert.pem -keyout ssl_key.pem

もちろん自分で作成するのではなく、Let's Encrypt 等の証明書を使ってもOKです。
その場合はcert.pemではなくfullchainの証明書を指定しましょう。

conf.d/10-logging.conf

log_path=/var/log/dovecot.log
(中略))
auth_verbose = yes
(中略)
verbose_ssl = yes

ログ出力はお好みで。色々出力する設定にした上で tail -f /var/log/dovecot.log で追いました。

Postfix のSSL関連設定

ソースから make する前に確認

まず先に、後述のconfig の設定を行ってみて上手く動けば一番良いのですが、postfix のログに
「warning: TLS has been selected, but TLS support is not compiled in」
だの出てきたら、ソースからコンパイルが必要な可能性があります。
で、
既にpostfixのパッケージが入っていたら、削除してからソースからインストールすること。
ソースからのコンパイルについては、postfixのインストールを参照。

make

make tidy  # 以前のビルドで残っているファイルがある場合
make makefiles \
   CCARGS=' \
     -DUSE_TLS \
     -I/usr/local/include \
     -DUSE_SASL_AUTH \
     -DDEF_SERVER_SASL_TYPE=\"dovecot\" \
     -DUSE_CYRUS_SASL \
     -I/usr/include/sasl \
   ' \
   AUXLIBS=" \
     -L/usr/local/lib64 \
     -lssl \
     -lcrypto \
     -L/usr/local/lib \
     -lsasl2 \
   "
make
make install

パッと見は絶望的な make の引数ですが、内容は2つです。
ソースにあるテキストを less 等で確認しましょう。

  • TLS(とOpenSSL)周りの README_FILES/TLS_README
  • SASL周りの README_FILES/SASL_README

これにならって、-I と -L は各環境に合わせたPATHに変えます。
(上記の例だと OpenSSLをソースから 64環境に入れているので、その辺は変わると思います)

main.cf

smtpd_use_tls = yes
smtpd_tls_key_file = /etc/postfix/certs/ssl_key.pem
smtpd_tls_cert_file = /etc/postfix/certs/ssl_cert.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
broken_sasl_auth_clients = yes
smtpd_sasl_type = dovecot
smtpd_sasl_path = /var/spool/postfix/private/auth
smtpd_sasl_local_domain = $myhostname

一体いくつオプションあるんだよ!?細かいチューニングは後日やるとして・・・*1
smtpd_tls_key_file、smtpd_tls_cert_file、smtpd_sasl_path は前述のdovecotに合わせること。

master.cf

 submission inet n       -       n       -       -       smtpd
   -o syslog_name=postfix/submission
   -o smtpd_tls_security_level=encrypt
   -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
 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

submission と smtps のコメントを外して有効化。オプション(-o)は・・・postfixのバージョン上がるとどんどん増えるので、よしなに。

firewall(CentOS 7)

デフォルトではメール送受信もままならないはずなので、ここで必要な通信に穴をあけます。 まず、確認。

# firewall-cmd --list-services  # いま有効なサービス
# firewall-cmd --list-all       # もう少し詳細に有効なサービスを表示
# firewall-cmd --list-all-zones # ほかのゾーンも全て表示
# ls -lta /usr/lib/firewalld/services/  # 「サービス」の内容が書かれたファイルはこちら
# firewall-cmd --add-service=smtp --zone=public --permanent
# firewall-cmd --add-service=pop3s --zone=public --permanent
# firewall-cmd --add-service=imaps --zone=public --permanent
# firewall-cmd --reload
# firewall-cmd --list-all  

必要に応じて submissionポートもfirewallに追加します。将来追加されるかもしれませんが・・・
当時は submission、smtpsともに見つからなかったので、自力で追加しました。
参考までに当時の手順をメモに残しておきます。(コピーしてポート番号変えるだけ)

# cp -pi /usr/lib/firewalld/services/smtp.xml /etc/firewalld/services/smtp_submission.xml
# vi /etc/firewalld/services/smtp_submission.xml
(port="587" に書き換える)
# firewall-cmd --reload
# firewall-cmd --get-services
(smtp_sbumission が増えていることを確認)
# firewall-cmd --add-service=smtp_submission --zone=public --permanent
# firewall-cmd --reload

これで送受信ができるか確認しましょう。
(saslauthd、dovecot、postfixをそれぞれ起動してから、送受信しましょう)
前述のとおり証明書に「オレオレ証明書」を使った場合は、メールアプリによってはエラーになります。
どうしてもメールアプリ側の設定で回避できないならば、あきらめて(?)Let's Encrypt等を導入しましょう。

参考: over SSL と STARTTLS の違い

私の場合はメール送受信がISP(インターネットサービスプロバイダ)経由なので、submissionポートを使わざるを得ないのですが、
その場合はメールアプリ側の設定がややこしいことになります。

  • メールを受信する場合
    たぶん、pop3s や imaps など、いわゆる「over SSL」で繋がる場合が多いかと
  • メールを送信する場合
    smtps が使えない場合が多く、submissionポート(587)経由からの「STARTTLS」で繋ぐことになるかと

何が違うのかというと、

  • 前者は最初からSSL/TLS接続をするのですが、
  • 後者は最初は普通の(安全ではない)通信で接続して、途中からSSL/TLSへ切り替える、

という違いがあります。

技術的な話はさておき、メールアプリ側で受信と送信の方法が変わることに混乱するかもしれません、
いや、混乱しましたので、ここにメモしておきます。


*1 正常なアクセスなのに「SASL LOGIN authentication failed: Invalid authentication mechanism」が出て、どうやら smtpd_sasl_tls_security_options が足りなかったようで追加しました。ここはまだまだ、更新の余地がありそうです・・・