メールサーバとの通信を暗号化してほしいとの依頼が来た。いつもはアプライアンスのSSLアクセラレータで処理させてるので、サーバ側でSSLを考えることはしていないのだが、SSLアクセラレータが無い環境での依頼だったのでやらざるを得ないハメに。設定内容自体は簡単だけど想定以上に苦労した。理由はあとがきにでも記載。今回設定をしていく上で色々勉強になったのでそのまとめ。(適当な解釈もあるので鵜呑みにしないでね)
postfix マルチインスタンス
postfixはシングルインスタンスで複数のポートをlistenさせることができるが、各ポート毎で動作を変える(relayhost先を変えるなど)時などにマルチインスタンスを使うと便利。
マルチインスタンスの生成
・名前は管理しやすいように好きなのをつければOK
# 初期化・有効化
$ postmulti -e init
# postfixのmain.cfにマルチインスタンス有効化の設定が加えられる
$ cat /etc/postfix/main.cf | grep multi_instance
multi_instance_wrapper = ${command_directory}/postmulti -p --
multi_instance_enable = yes
# 新規インスタンスの生成
postmulti -I postfix-2525 -e create
# 新規インスタンス用のDirectoryが生成されている
$ ls -ld /etc/postfix*
drwxr-xr-x 3 root root 4096 5月 25 10:52 2022 /etc/postfix
drwxr-xr-x 3 root root 4096 5月 24 21:17 2022 /etc/postfix-2525
# 新規インスタンス用のDirectoryの中身は下記
$ ls -l /etc/postfix-2525
-rw-r--r-- 1 root root 26346 5月 26 01:51 2022 main.cf
-rw-r--r-- 1 root root 6200 9月 14 12:07 2015 master.cf
# postfixのmain.cfに生成したマルチインスタンスの設定が加えられる
$ cat /etc/postfix/main.cf | grep multi_instance_directories
multi_instance_directories = /etc/postfix-2525
# TCP/IPの待ち受け許可
$ vi /etc/postfix-2525/main.cf
===== inetを削除 or 行自体を削除/コメント =====
master_service_disable = inet
=============================================
# 新規インスタンスの生成(さらに追加)
$ postmulti -I postfix-hoge -e create
# 大元のpostfixのmain.cfに追加した分のマルチインスタンスの情報が加えられる
$ cat /etc/postfix/main.cf | grep multi_instance_directories
multi_instance_directories = /etc/postfix-2525 /etc/postfix-hoge
マルチインスタンス 有効/無効、起動/停止、ステータス
・起動する前にmaster.cfやmain.cfなどの設定ファイルを変更
・メインのpostfixをsystemdなどからstop/startすればマルチインスタンスも連動して動作する
・postmultiにrestartは無く、使えるものはこんな感じ(start , stop, reload, abort, flush, check, status, set-permissions, upgrade-configuration)
# 有効
$ postmulti -i postfix-2525 -e enable
$ cat main.cf | grep multi_instance_enable
multi_instance_enable = yes
# 無効
$ postmulti -i postfix-2525 -e disable
$ cat main.cf | grep multi_instance_enable
multi_instance_enable = no
# 起動
$ postmulti -i postfix-2525 -p start
postfix-2525/postfix-script: starting the Postfix mail system
# 停止
$ postmulti -i postfix-2525 -p stop
postfix-2525/postfix-script: stopping the Postfix mail system
# 子インスタンスのステータス
$ postmulti -i postfix-2525 -p status
postfix-2525/postfix-script: the Postfix mail system is running: PID: 24047
# 全てのステータス
$ postmulti -p status
postfix/postfix-script: the Postfix mail system is running: PID: 23907
postfix-2525/postfix-script: the Postfix mail system is running: PID: 24047
postfix-hoge/postfix-script: the Postfix mail system is not running
postfix 暗号化設定
やりかたは2種類。接続時から暗号化するTLS(暗黙的TLS)と、接続後に暗号化するSTARTTLSがある。TLSでやる場合は465を使い、STARTTLSなら25,587を使う。
LISTENポートの有効化
・mater.cfの中を編集して、コメントを外す
・smtpは25、smtpsは465、submissionは587を表している
・独自のポート番号を使いたい場合は左端の項目にポート番号を書けば良い
・「- o」で続くオプションはmaster.cfの中で有効化しなくても、main.cfの中で書くことも可能
smtp inet n - n - - smtpd
smtps inet n - n - - smtpd
submission inet n - n - - smtpd
2525 inet n - n - - smtpd
# -o smtpd_tls_security_level=may
# -o smtpd_sasl_auth_enable=yes
465の暗黙的TLS設定
・main.cfの中を編集 ※master.cfでも良い
・以下は必須じゃない項目も含まれる
# ラッパーモードの有効化
smtpd_tls_wrappermode = yes
# 証明書のパス
smtpd_tls_cert_file = /usr/share/cert/server.crt
# 秘密鍵のパス
smtpd_tls_key_file = /usr/share/cert/server.key
# 中間証明書のパス
smtpd_tls_CAfile = /usr/share/cert/ca.crt
# 受け入れプロトコル 「!」を付けると拒否
smtpd_tls_mandatory_protocols = !SSLv2,!SSLv3,!TLSv1,!TLSv1.1
# 暗号化通信に必要なものを毎回取り出さずにキャッシュとその保持期間
smtpd_tls_session_cache_database = btree:/var/lib/postfix/smtpd_scache
smtpd_tls_session_cache_timeout = 3600s
# ヘッダへ情報の付与 securityの一環
smtpd_tls_received_header = yes
# ログ出力 0:無効 1以上:有効
smtpd_tls_loglevel = 1
25,587のSTARTTLS設定
・main.cfの中を編集 ※master.cfでも良い
・1つのインスタンスで複数ポートをlistenさせてる場合、各種設定は共有化されると思われる。設定を分ける場合はmaster.cf配下の-oオプションで記載すればできそう(未検証)。一番わかりやすいのはマルチインスタンスを使って設定ファイルを明示的に分けるのがラク。
# STARTTLSの有効化 (may:任意 encrypt:強制)
## 外部メールサーバと通信が有る場合にencryptは非推奨
smtpd_tls_security_level = may
# 証明書のパス
smtpd_tls_cert_file = /usr/share/cert/server.crt
# 秘密鍵のパス
smtpd_tls_key_file = /usr/share/cert/server.key
# 中間証明書のパス
smtpd_tls_CAfile = /usr/share/cert/ca.crt
# 受け入れプロトコル 「!」を付けると拒否
smtpd_tls_mandatory_protocols = !SSLv2,!SSLv3,!TLSv1,!TLSv1.1
# 暗号化通信に必要なものを毎回取り出さずにキャッシュとその保持期間
smtpd_tls_session_cache_database = btree:/var/lib/postfix/smtpd_scache
smtpd_tls_session_cache_timeout = 3600s
# ヘッダへ情報の付与 securityの一環
smtpd_tls_received_header = yes
# ログ出力 0:無効 1以上:有効
smtpd_tls_loglevel = 1
smtpdとsmtpの違い
・main.cfの中で下記のような設定がある
・smtpdで始まるものはpostfixがメールを受信するサーバとしての役割時に設定するもの
・smtpで始まるものはpostfixが外部メールサーバへ送信するクライアントとしての役割時に設定するもの
smtpd_tls_security_level = may
smtp_tls_security_level = may
dovecot 暗号化設定
dovecotのバージョンで設定方法が変わっているので注意。以下は「2.2.15」で検証した内容
SSLの有効化
・「ssl = required」の場合、SSL必須らしいが、検証バージョンだとSSL無くても110で通信が可能だった
$ vi /etc/dovecot/conf.d/10-ssl.conf
===================================================
# 有効化 (no:無効 yes:任意 required:強制)
ssl = yes
# 証明書のパス
ssl_cert = </usr/share/cert/server.crt
# 秘密鍵のパス
ssl_key = </usr/share/cert/server.key
# 中間証明書のパス
ssl_ca = </usr/share/cert/ca.crt
# 受け入れプロトコル 「!」を付けると拒否
ssl_protocols = !SSLv2,!SSLv3,!TLSv1,!TLSv1.1
===================================================
暗号化無しの無効化
・port番号を0にすることでlistenしなくなる
$ vi /etc/dovecot/conf.d/10-master.conf
===================================================
inet_listener pop3 {
port = 0
}
===================================================
動作確認方法などのコマンド
SSL証明書
# 証明書が使えてるか
$ openssl s_client -showcerts -connect localhost:465
====== このような応答が返ってきている場合はNG =========================================================
139878197389128:error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol:s23_clnt.c:769:
---
no peer certificate available
---
No client certificate CA names sent
---
====================================================================================================
# TLSのバージョン指定して確認 ( -ssl2 , -ssl3 , -tls1 , -tls1_1 , -tls1_2 )
$ openssl s_client -showcerts -connect localhost:465 -tls1_2
STARTTLS
・STARTTLSが使えているかどうかは、「helo」じゃなくて、「ehlo」を使い、「STARTTLS」の応答が返ってくれば使える状態にある。
$ telnet localhost 587
:
ehlo hoge
:
250-STARTTLS
メール送信
・STARTTLS使う場合はopensslで実行する
# port:25 普通のメール送信
$ telnet localhost 25
:
helo hoge
mail from: from-test@piteki.com
rcpt to: to-test@piteki.com
data
subject: test-mail
hoge-test
.
quit
# port:587 STARTTLSを使ったメール送信
$ openssl s_client -connect localhost:587 -starttls smtp
:
以下、上記と同じ
メール受信
・retrの1はリスト番号を入力
# port:110 普通のメール受信
$ telnet localhost 110
:
user piteki
pass hogehoge
list
retr 1
quit
# port:995 暗号化メール受信
$ openssl s_client -connect localhost:995
:
以下、上記と同じ
AUTH PLAIN
・ユーザー名\0ユーザー名\0パスワード\0 という文字列をBase64でエンコード
# user:piteki
# pass:hogehoge
$ perl -MMIME::Base64 -e 'print encode_base64("piteki\0piteki\0hogehoge");'
cGl0ZWtpAHBpdGVraQBob2dlaG9nZQ==
# メール送信をコマンドで実行してるときに下記を入れて認証が通るとsuccessfulが出る
auth plain cGl0ZWtpAHBpdGVraQBob2dlaG9nZQ==
235 2.7.0 Authentication successful
暗号化で苦労した理由
冒頭で書いた「想定以上に苦労した」理由について
上記の設定をやってもpostfixの強制TLSやSTARTTLSが動かなかった。ポートはlistenしているのだが、ehloを打ってもSTARTTLSを使いますかと聞いてこない。最初はpostfixのversionによる不具合の可能性も視野に入れていたが、結論。
ソースから入れていたpostfixでSSLをコンパイルしていなかった
これに気づいてなくて、めちゃくちゃ時間かかった。時間かけたおかげでスゴイ勉強することになったので、忘れないために備忘しておこうと思った。
コメント