「Azure にインストールした postfix を SMTP でテストする」
https://qiita.com/nanbuwks/items/fc4a6b0daba712f6bc11
では、telnet で SMTP プロトコルを叩いてメールを送信しましたが、パスワードも何もなしでメールが送れてしまいました。
そのままだと SPAM の踏み台になってしまうので、認証の仕組みを導入することにします。
環境
- Ubuntu 22.04
- Postfix
「Azure で postfix のインストールを試す」
https://qiita.com/nanbuwks/items/38b54aaf8c3ecfdbb3cc
「Azure/Ubuntu にインストールした postfix / dovecot を Maildir 対応にする」
https://qiita.com/nanbuwks/items/10e6dd1224ce0c3f76af
で設定したものです。
EHLO コマンド
先の telnet で 接続したときには、最初に
HELO localhost
として接続し、以下のように返答が返ってきました。
250 test-azure-gen.ugx1l5hl2pbu5oitg4vrqao0jd.phxx.internal.cloudapp.net
もともとの SMTP には認証の仕組みがありませんが、 ESMTP コマンド (SMTP サービス拡張) でサーバーに対してクライアントを認証するために使用される AUTHコマンドが定義されています。
ESMTPコマンドを使うには、最初の接続時に HELO
ではなく EHLO
コマンドを使います。
先の実験と同じサーバで以下のように入力すると
EHLO localhost
以下のように返答が返ってきます。
250-test-azure-gen.ugx1l5hl2pbu5oitg4vrqao0jd.phxx.internal.cloudapp.net
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-STARTTLS
250-ENHANCEDSTATUSCODES
250-8BITMIME
250-DSN
250-SMTPUTF8
250 CHUNKING
AUTH コマンドが使用できる場合、応答に AUTH フレーズが含まれます。しかしながら今回は見当たらないので SMTP-Auth が設定されていないことがわかります。
以下で、postfix に SMTP-Authを設定していきます。
現在の postfix の設定
postfix は /etc/postfix/main.cf で設定されていますが、コメントが多く一覧性が悪いです。以下のようにして設定部分だけを抜き出すことができます。
$ postconf -n
現在の設定内容が表示されます。
alias_database = hash:/etc/aliases
alias_maps = hash:/etc/aliases
append_dot_mydomain = no
biff = no
compatibility_level = 2
home_mailbox = Maildir/
inet_interfaces = all
inet_protocols = all
mailbox_size_limit = 0
mydestination = $myhostname, test-azure-gen.ugx1l5hl2pbu5oitg4vrqao0jd.phxx.internal.cloudapp.net, localhost.ugx1l5hl2pbu5oitg4vrqao0jd.phxx.internal.cloudapp.net, , localhost
myhostname = test-azure-gen.ugx1l5hl2pbu5oitg4vrqao0jd.phxx.internal.cloudapp.net
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
myorigin = /etc/mailname
readme_directory = no
recipient_delimiter = +
relayhost =
setgid_group = postdrop
smtp_tls_CApath = /etc/ssl/certs
smtp_tls_security_level = may
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
smtpd_banner = $myhostname ESMTP $mail_name (Ubuntu)
smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination
smtpd_tls_cert_file = /etc/ssl/certs/ssl-cert-snakeoil.pem
smtpd_tls_key_file = /etc/ssl/private/ssl-cert-snakeoil.key
smtpd_tls_security_level = may
SASL
認証や暗号化を行うにあたり、postfix は自前で処理を行うことに対して否定的な立場をとっています。
cf.,
https://www.postfix-jp.info/trans-2.3/jhtml/TLS_README.html
SASL は RFC4422 で定められている認証やセキュリティに関する処理で、これを呼び出すことで postfix の自前処理でのセキュリティホールを回避します。
現在インストールしている postfix において、利用可能な SASL プラグインを以下のようにしてリストアップします。
$ postconf -a
Postfixで使用できる SASL 実装としてはCyrus SASLとDovecot SASL があり、その両方が利用可能であることがわかります。
cyrus
dovecot
今回は、Dovecot SASLを使うことにします。
SASL メカニズム
SASLには 一連の要求と応答をモデル化したものが SASL メカニズムとして IANA にて定義されています。
https://www.iana.org/assignments/sasl-mechanisms/sasl-mechanisms.xhtml
このうち、SMTP でよく使われる SASL メカニズムには以下のものがありますが、
- PLAIN
- LOGIN
- CRAM-MD5
これらのうち LOGIN および CRAM-MD5 は廃止となっています。そのため最新の IANA にあわせて設定するとなると PLAIN を用いることになります。
postfix の設定
/etc/postfix/main.cf の末尾に、以下を加えます。
# SMTP-AUTH
smtpd_sasl_auth_enable = yes
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
broken_sasl_auth_clients = yes
smtpd_recipient_restrictions =
permit_mynetworks
permit_sasl_authenticated
reject_unauth_destination
最後の、smtpd_recipient_restictions はメール受付の可否の設定です。
- permit_mynetworks
- mynetworks で指定されたネットワークからのメールを許可
- permit_sasl_authenticated
- SASL 認証を通過した場合許可
- reject_unauth_destination
- それ以外を拒否
これを保存して、設定チェックをします。
$ sudo postfix check
postfix/postfix-script: warning: symlink leaves directory: /etc/postfix/./makedefs.out
postfix/postfix-script: warning: /var/spool/postfix/etc/hosts and /etc/hosts differ
と出たので、 /etc/hosts を /var/spool/postfix/etc/hosts にコピーします。
$ sudo cp /etc/hosts /var/spool/postfix/etc/hosts
この設定は、今回の SMTP-Auth とは関係ありませんが、別記事
「Azure/Ubuntu/Apache2 で PHP と VirtulaHost を設定する」
https://qiita.com/nanbuwks/items/d3a1a148e597f5c5df1c
で行った、 /etc/hosts に example.com を追加した設定を postfix に反映するためのものです。
dovecot の設定
/etc/dovecot/conf.d/10-master.conf の中の、 service auth の内容は以下のようになっています。
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).
unix_listener auth-userdb {
#mode = 0666
#user =
#group =
}
# Postfix smtp-auth
#unix_listener /var/spool/postfix/private/auth {
# mode = 0666
#}
# Auth process is run as this user.
#user = $default_internal_user
}
service auth の中身が以下であるようにします。
unix_listener auth-userdb {
#mode = 0666
#user =
#group =
}
# Postfix smtp-auth
unix_listener /var/spool/postfix/private/auth {
mode = 0666
user = postfix
group = postfix
}
dovecot の設定を反映します。
$ sudo service dovecot restart
telnet でテスト
ここまで設定して、telnet で接続してみます。
$ telnet localhost 25
postfix から反応が返ってきて、問題なく接続できています
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
EHLOコマンドを送ります。
EHLO localhost
反応が返ってきます。
220 test-azure-gen.ugx1l5hl2pbu5oitg4vrqao0jd.phxx.internal.cloudapp.net ESMTP Postfix (Ubuntu)
250-test-azure-gen.ugx1l5hl2pbu5oitg4vrqao0jd.phxx.internal.cloudapp.net
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-STARTTLS
250-AUTH PLAIN
250-AUTH=PLAIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250-DSN
250-SMTPUTF8
250 CHUNKING
以下が増えていることがわかります。
250-AUTH PLAIN
250-AUTH=PLAIN
おや、 PLAIN 認証らしきものが2つありますね。これについて、下側のものは
broken_sasl_auth_clients = yes
設定が有効になっているためです。これは旧い Outlook Express にて、250-AUTH=PLAIN
という応答でないと認識をしない問題に対応するためのものです。
接続を一旦終了します。
QUIT
221 2.0.0 Bye
Connection closed by foreign host.
PLAIN 認証を使ってみる。
AUTH PLAIN コマンドで送るパラメータとして、以下のいずれかのフレーズを送る必要があります。
-
ユーザ名\0ユーザ名\0パスワード
を BASE64 エンコードしたもの -
\0ユーザ名\0パスワード
を BASE64 エンコードしたもの
以下のようにして、あらかじめ用意しておきます。
$ printf "%s\0%s\0%s" example example hogehogefugafuga | openssl base64 -e | tr -d '\n'; echo
出力されたものをコピーしておきます。
ZXhhbXBsZQBleGFtcGxlAGhvZ2Vob2dlZnVnYWZ1Z2E=
再度、telnet で接続して EHLO を送ります。
$ telnet localhost 25
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
EHLO localhost
220 test-azure-gen.ugx1l5hl2pbu5oitg4vrqao0jd.phxx.internal.cloudapp.net ESMTP Postfix (Ubuntu)
250-test-azure-gen.ugx1l5hl2pbu5oitg4vrqao0jd.phxx.internal.cloudapp.net
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-STARTTLS
250-AUTH PLAIN
250-AUTH=PLAIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250-DSN
250-SMTPUTF8
250 CHUNKING
AUTH PLAIN ZXhhbXBsZQBleGFtcGxlAGhvZ2Vob2dlZnVnYWZ1Z2E=
235 2.7.0 Authentication successful
認証できました。
なお、
AUTH PLAIN
334
ZXhhbXBsZQBleGFtcGxlAGhvZ2Vob2dlZnVnYWZ1Z2E=
235 2.7.0 Authentication successful
のように、AUTH PLAIN と BASE64フレーズは2行に分けてもOKです。