SendmailでMTA間のSMTP認証をしてみた

2024年08月20日 火曜日


【この記事を書いた人】
YAS

2024年3月に中途入社した一般人。IIJにてメールサービスの開発を通して日々切磋琢磨中です。趣味は美味しいものを食べたりゲームとか。

「SendmailでMTA間のSMTP認証をしてみた」のイメージ

はじめに

はじめまして。IIJにてメールサービスの開発業務をしているYASです。

個人メールサーバを構築して実際に他人に対してメールを送ってみたいと考える人がいるかもしれません。
しかし個人でメールサーバを建てたところで通常は直接インターネットに接続できないので、どこかのプロバイダのメールサーバを経由してメールを送信することになるでしょう。
この時プロバイダのメールサーバに対してSMTP認証をすることが考えられます。

メールを扱う上でSMTP認証というのをよく聞くとは思います。
SMTP認証(SMTP-AUTH)は元々SMTPというメール送信プロトコルに送信した人の認証機能がなかったことから生まれた、認証に関するSMTPの拡張です。
このことからユーザ認証のイメージがあるかもしれませんが、MTA間での認証という側面での利用でも一般的に使われています。

今回は勉強として有名なMTAであるSendmailにてMTA間のSMTP認証を試してみたいと思います。

Sendmailは非常に古くから使われてきた代表的なMTAです。
このMTAは柔軟な設定ができますが、その分複雑であることが特徴です。
そのためSendmailにて別MTAへのSMTP認証を行うのは
メールサービスの勉強をしていくにあたって非常に意義のあることと思いSendmailを選定しました。

ちなみにこの動作はRocky Linux 8、Ubuntu 22.04.4、openSUSE 15.6にて検証済です。

また条件としてSMTP認証対応サーバであるrelay.example.jpがPLAINでのSMTP認証を許可していることと、
個人設備のサーバで既にsendmailやsendmail-cfがインストールされていてSendmailが動いているなど
Sendmailの基本的な設定は既に行われていることを前提に進めていきます。

Sendmailから送る手順

  1. 必要なパッケージのインストール
    Sendmailを使って運用しているサーバにssh接続し、ターミナル上で以下のコマンドを叩きます。


    Rocky Linuxの場合
    $ su
    # dnf update
    # dnf install cyrus-sasl cyrus-sasl-plain
    Ubuntuの場合
    $ su
    # apt-get update
    # apt-get install libsasl2-2 libsasl2-modules
    openSUSEの場合
    $ su
    # zypper update
    # zypper install cyrus-sasl cyrus-sasl-plain

    ちなみにcyrus-sasl及びlibsasl2-2が認証系のライブラリで、これを使って内部的にSMTP認証を行っています。

  2. 認証情報を変更する
    接続先MTAで入手したSMTP認証におけるIDとパスワードを/etc/mail/authinfoに書き込んだ後、
    データベース化してauthinfo.dbとして保存します。
    しかしその前に適切な権限を設定しておきます。
    何故ならこれらのファイルにはSMTP認証のIDとパスワードが暗号化せずに直接書かれているため、
    管理者以外が読み書きできないようにしなければならないからです。
    認証情報を書いてから権限を変更することもできますが
    その権限を変更するまでの短い間にIDとパスワードを盗み見られる可能性も考慮して
    認証情報を書く前に権限を設定しておきます。
    存在しないファイルは権限設定することもできないのでまずtouchでファイルを新規作成してからchmodで権限を変更しましょう。

    # touch /etc/mail/authinfo
    # touch /etc/mail/authinfo.db
    # chmod 600 /etc/mail/authinfo
    # chmod 600 /etc/mail/authinfo.db

    権限設定を行ったのでIDとパスワードを/etc/mail/authinfoに書き込みます。

    例:

    設定が以下の場合だった時
    SMTP認証対応サーバのドメイン:relay.example.jp
    SMTP認証ID:id-smtpauth
    パスワード:password-smtpauth

    # cd /etc/mail
    # vi authinfo
    AuthInfo:relay.example.jp "U:id-smtpauth" "P:password-smtpauth" "M:PLAIN"

      ※relay.example.jp、id-smtpauth、password-smtpauthは適宜変更すること!

    最後にauthinfoをデータベース化してauthinfo.dbとします。

    # makemap hash /etc/mail/authinfo < /etc/mail/authinfo
    

    これでauthinfo.dbが作成されました。

  3. 接続時にSMTP認証を行うための設定
    Sendmailの設定はRocky LinuxとUbuntuは/etc/mail/sendmail.cf、openSUSEは/etc/sendmail.cfに書かれていますが人間には複雑であり直接編集するのは難しいです。
    そこでマクロファイルを編集し、m4というマクロプロセッサに読み込ませてその出力をsendmail.cfに書き込むことで、
    間接的にsendmail.cfを編集するのが一般的です。
    なおマクロファイルの場所はRocky LiunxとUbuntuに関しては/etc/mail/sendmail.mc、openSUSEに関しては/etc/mail/linux.mcとなっています。
    とりあえず一旦安全のためにsendmail.cfのバックアップをsendmail.cf.bakとして取っておきます。

    Rocky Linux、Ubuntuの場合
    # cp -p sendmail.cf sendmail.cf.bak
    openSUSEの場合
    # cp -p /etc/sendmail.cf /etc/sendmail.cf.bak

    次にマクロファイルを編集していきます。
    先ほどもあった通り、Rocky LinuxやUbuntuとopenSUSEで編集するマクロファイルが異なることに注意です。
    しかしマクロファイルの中身はほぼ同一で編集する内容は同一なので安心です。
    内容としては最下段の方に『MAILER』から始まる行が複数行あるのでそれよりも前に以下の2行を追加します。
    以下にSMTP認証対応サーバのドメインがrelay.example.jpだった時の例を書きます。

    Rocky Linux、Ubuntuの場合
    # vi sendmail.mc
    openSUSEの場合
    # vi linux.mc
    それぞれviで開いたマクロファイルで追記する内容
    define(`SMART_HOST',`[relay.example.jp]')dnl
    FEATURE(`authinfo',`hash /etc/mail/authinfo.db')dnl

     ※relay.example.jpは適宜変えること!

    なおSMART_HOSTがリレー先のホストを設定する場所です。
    ちなみにdefine(`SMART_HOST’,`relay.example.jp’)dnlではなくdefine(`SMART_HOST’,`[relay.example.jp]’)dnlと指定するように括弧でくくるとDNSのMXレコードではなくAレコードで指定することになります。

    また、FEATURE(`authinfo’,~)と指定することで認証情報に~以下で指定する特別なデータベースを使用することになります。

  4. 設定を適用してSendmail再起動
    いよいよm4を使ってsendmail.cfにマクロファイルに書き込んだ内容を流し込みます!
    ターミナルから以下のコマンドを叩きます。

    Rocky Linux、Ubuntuの場合
    # m4 sendmail.mc > sendmail.cf
    openSUSEの場合
    # m4 linux.mc > /etc/sendmail.cf

    そしてSendmailを再起動させるとSendmailから外部のSMTP認証対応サーバを使用してメールを送れるようになりました!

    # systemctl restart sendmail

手打ちでSMTP認証対応サーバに接続できるか確認したい

上の手順でそのまま動けば無問題なのですが動かなくて問題を切り分けしたいときもあるかもしれません…
そのためSendmailから送る手順で上位のSMTP認証対応サーバ側での設定がきちんとできているか確認したい場合の手順を示したいと思います。

概要

以下の構成でSMTP認証対応サーバへのSMTP認証を試します

手順

以下のtest-smtpauth.shをSendmailを運用しているサーバ上の任意の場所に保存します。
USER、PASS、FROM、RCPTはコメントの内容に従って適宜変更してください
relay.example.jpもSMTP認証対応サーバのドメインに適宜変更してください

USER="id-smtpauth"             # SMTP認証のID
PASS="password-smtpauth"       # SMTP認証のパスワード
FROM="mailfrom@example.jp"     # テストメールの送信先メールアドレス
RCPT="mailrcpt@example.jp"     # テストメールの送信元メールアドレス
MYDOMAIN="mydomain.example.jp" # 個人設備のSendmailが動いているサーバのドメイン

AUTH="`echo -ne "${USER}\x00${USER}\x00${PASS}"|base64 -w 0`"
(
 echo -en "EHLO relay.example.jp\r\n"
 sleep 1
 echo -en "AUTH PLAIN ${AUTH}\r\n"
 sleep 1
 echo -en "MAIL FROM:<${FROM}>\r\n"
 sleep 1
 echo -en "RCPT TO:<${RCPT}>\r\n"
 sleep 1
 echo -en "DATA\r\n"
 echo -en "From:<${FROM}>\r\n"
 echo -en "To:<${RCPT}>"
 echo -en "\r\n"
 echo -en "smtp-auth test\r\n"
 echo -en ".\r\n"
 sleep 1
 echo -en "QUIT\r\n"
) | nc relay.example.jp 25

保存した後実行してください

# bash test-smtpauth.sh

これでテストメールの送信先メールアドレスに対して本文に『smtp-auth test』と書かれたメールが届いていれば成功です!
届かなかった場合はSMTP認証のIDやパスワードが間違っていないことを確認してください。

なお、この確認のために使用したSMTP認証対応サーバのIDとパスワードは
平文でIDとパスワードを送信しているので、確認が終わり次第破棄して
実運用するときには別のIDとパスワードを使用するのがよりセキュアでしょう。
逆にIDやパスワードが容易に変えられない環境の場合はopensslなどで経路暗号化した状態で試すのをお勧めします。

 

まとめ

自分としてもまだまだメールサービスを勉強し始めたばかりでSendmailを構築するのは一苦労しました。
特にサーバとSMTP認証対応サーバとの連携が取れてるか手打ちで確認する際に
test-smtpauth.shコード上でAUTHを${USER}\x00${USER}\x00${PASS}と設定していますが、
\x00を区切り文字とせずに\0としてしまうとUSERやPASSの先頭文字がエスケープシーケンスに含まれてしまうのは罠で
結構ここで足止めを喰らってしまいました…
これからも勉強してよりメールサービスに詳しくなりたいです。

 

おまけ

ここまでの設定でうまく行くのが一番なのですが、どこかしらでミスをしてうまく思った通りの動作ができないこともあるかもしれません。
そのような場合は各Linuxディストリビューションの商用サポートに頼ってみてはどうでしょうか。

例)

関連リンク

PostfixでMTA間のSMTP認証をしてみた

YAS

2024年08月20日 火曜日

2024年3月に中途入社した一般人。IIJにてメールサービスの開発を通して日々切磋琢磨中です。趣味は美味しいものを食べたりゲームとか。

Related
関連記事