📚

LogwatchのメールをAWS SESでGmailに送る

2024/04/24に公開

ハマったのでメモしておきます。

環境

2024年4月に以下の環境で試しました。

  • Ubuntu 22.04 LTS
  • Logwatch 7.5.6
  • Postfix 3.6.4

AWSの設定

今回は東京リージョンを使いますので、東京リージョンでSESコンソールに入ります。左メニューを開き、「設定」→「ID」の画面を表示します。上部の「IDの作成」ボタンをクリックします。

IDタイプは「ドメイン」を選択します。その後表示されるテキストボックスに追加したいドメイン名を入力して進みます。
カスタムMAIL FROMドメインは、例えばexample.comを追加するときに、mail.example.comのようなサブドメインをFROMメールアドレスに指定するための設定です。Logwatchだけを考えるとあまり重要ではないですが、このSES設定は他の用途でも使い回したいので、カスタム設定をすることにします。

ここまで入力したら、画面下部の「IDを作成」ボタンをクリックして進みます。

すると、必要な作業が全てリストアップされます。ドメインの権威DNSサーバーに、指示のリソースレコードを書いていけばOKです。Route53だと一部自動でやってくれるそうですが、私はRoute53ではなくCloudFlareを使っているので、CloudFlareで設定します。

一応、それぞれのレコードの簡単な解説をしておきます。

  • DKIM: 電子署名用のレコードです。送信者が秘密鍵を使ってメッセージのハッシュ値を送り、受信者が検証できるようにすることで、改ざんを防いでいます。CNAMEレコードを使って登録します。
  • MX: メールサーバーを指定します。カスタムMAIL DOMAIN利用時のみ必要です。
  • SPF: 送信元検証に用いるIPアドレスを指定します。正しいSenderであることを確認するためのレコードです。カスタムMAIL DOMAIN利用時のみ必要だそうなのですが、なぜそうでないと不要なのか、いまいち腑に落ちていません。
  • DMARC: 認証チェックに失敗したメッセージを処理する方法を指定するレコードです。現状、何もしない設定(=noneポリシー)ですが、今後Gmailのポリシーが変わるとnoneポリシーでは許されなくなるかもしれませんね。

さて、それぞれのリソースレコードを登録してしばらくすると、SESが自動でレコードをチェックしてくれます。保留中から成功に変わればOKです。

次に、SMTPサーバーの認証情報を取得します。SESコンソールの左メニュー「SMTP設定」を開き、「SMTP認証情報の作成」ボタンをクリックします。IAMに飛ばされます。

適当なユーザー名を入れて、画面下部の「ユーザーの作成」ボタンをクリックします。ses:SendRawEmail 権限を持つユーザーが生成されます。

次の画面でSMTP認証情報が表示されます。CSVファイルをダウンロードするなどして、控えておきます。完了したら、「SESコンソールに戻る」ボタンをクリックします。

これで、AWS SES側の設定は完了です。なお、まだ一度もSESを使ったことがない方は、制限引き上げのリクエストを上げたり、サンドボックスから本番環境への移行リクエストを上げたりする必要があるかもしれません。その辺はこの記事では触れないことにします。

サーバー側の設定

Logwatch

logwatchでは、/usr/share/logwatch/default.conf/logwatch.conf/etc/logwatch/conf/logwatch.conf では後者の方が強い(上書きされる)。そのため今回は、以下のようにオリジナルをコピーし、 /etc/ 配下の方だけ編集し管理することとします。

$ sudo apt install -y logwatch
$ sudo cp /usr/share/logwatch/default.conf/logwatch.conf /etc/logwatch/conf/logwatch.conf

直接今回の記事と関係のない内容も含みますが、confファイルを以下のように編集します。特にmailerの設定値が重要で、デフォルトではない -f オプションを追加し、送信元メールアドレスを追加しないと動作しません。なぜこれが必要かは、後半で説明します。

$ sudoedit /etc/logwatch/conf/logwatch.conf
    TmpDir = /var/cache/logwatch
    Format = text
    MailTo = <送信先メールアドレス>
    MailFrom = <送信元メールアドレス>
    Range = yesterday
    Detail = Med
    mailer = "/usr/sbin/sendmail -t -f <送信元メールアドレス>"

最後に、環境依存かもしれませんが、インストール直後の状態だと私の手元ではlogwatchがログを送信するときのキャッシュファイルをうまく生成できませんでした。そのためあらかじめログ格納先を作り、権限を与えておきます。

$ sudo mkdir /var/cache/logwatch
$ sudo chmod 700 /var/cache/logwatch/

Logwatchの設定は以上です。

Postfix

Logwatchから引っ張られてインストールされるようです。入ってなければ以下でインストールします。

sudo apt install -y postfix

設定ファイルを編集します。Postfixを公開したくないので、ローカルホストからだけ受け付ける設定にします。relayhostは東京リージョンを前提に記載していますので、別のリージョンをお使いの方はよしなに変更してください。

$ sudoedit /etc/postfix/main.cf
## 末尾に追加

inet_interfaces = 127.0.0.1
inet_protocols = ipv4

smtp_sasl_auth_enable = yes
smtp_sasl_security_options = noanonymous
smtp_use_tls = yes
smtp_tls_security_level = encrypt
smtp_tls_note_starttls_offer = yes
relayhost = [email-smtp.ap-northeast-1.amazonaws.com]:587
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd

$ sudoedit /etc/postfix/sasl_passwd
[email-smtp.ap-northeast-1.amazonaws.com]:587 <SES_LOGIN_ID>:<SES_LOGIN_PASS>

ここで、/etc/postfix/sasl_passwd には、先ほど控えておいたSMTPのユーザー名とパスワードを入力します。その後、以下でハッシュします。

$ sudo postmap hash:/etc/postfix/sasl_passwd

ここまで終わればpostfixの再起動です。

$ sudo postfix check
 # エラーが表示されないことを確認
$ sudo systemctl restart postfix
$ sudo systemctl enable postfix

これで全ての設定が完了しました。

動作確認

まずはpostfixでメールが送信できるかどうかテストしましょう。Logwatchは sendmail コマンド経由でメールを送信しますので、このテストも sendmail で行います。sendmail は最後に . だけの行があると終了として判定しますので、この . を忘れないようにしてください。

$ sendmail -f <From_Address> -t <To_Address>
Subject: test
This is test mail from AWS SES.
.

これでメールが受信できることを確認してください。特にGmailであれば、メッセージのソースを表示から詳細を確認することをお勧めします。

この画面で、amazonses.comから送信されていること、SPF/DKIM/DMARCレコードが正しく設定されていることを確認できます。

大丈夫そうですね。では、Logwatchを介して送ってみます。Logwatchは、実際にはcron.dailyで以下コマンドが呼び出されます。

$ cat /etc/cron.daily/00logwatch 
#!/bin/bash

#Check if removed-but-not-purged
test -x /usr/share/logwatch/scripts/logwatch.pl || exit 0

#execute
/usr/sbin/logwatch --output mail

#Note: It's possible to force the recipient in above command
#Just pass --mailto address@a.com instead of --output mail

今回もそのまま実行してみましょう。

$ sudo /etc/cron.daily/00logwatch

標準出力にはなにも表示されませんが、これで正常に送信できているはずです。

トラブルシューティング

当初、全然送信できませんでした。sendmailコマンドでは成功するのに、logwatchからメールを送ると失敗する状況でした。その際、以下のようなエラーログが出力されていることを見つけました。

Apr 24 02:05:35 host2 postfix/cleanup[2245239]: XXXXXXXXXX: message-id=<20240423170535.XXXXXXXXXX@host2.prd.XXXXXXXX.local>
Apr 24 02:05:35 host2 postfix/qmgr[2243867]: XXXXXXXXXX: from=<"root@host2.prd"@XXXXXXXXXX>, size=15260, nrcpt=1 (queue active)
Apr 24 02:05:35 host2 postfix/smtp[2245241]: XXXXXXXXXX: to=<XXXXXXXXXXX@gmail.com>, relay=email-smtp.ap-northeast-1.amazonaws.com[18.180.254.105]:587, delay=0.76, delays=0.53/0.01/0.16/0.05, dsn=5.0.0, status=bounced (host email-smtp.ap-northeast-1.amazonaws.com[18.180.254.105] said: 554 Transaction failed: Address contains illegal characters in user name: '<"root@host2.prd"@XXXXXXXXXX>'. (in reply to end of DATA command))
Apr 24 02:05:35 host2 postfix/bounce[2245242]: XXXXXXXXXX: sender non-delivery notification: AA31DFFAC9

原因はメールのFromメールアドレスの仕組みにあります。メールには、EnveropeFrom と HeaderFrom と呼ばれる2つのFromがあり、どちらも正しく設定しておかないと SES側が不正なメールだと判断して送信を拒否してしまいます。

一方、Logwatchの設定ファイルの MailFrom は HeaderFrom しか書き換えません。そのため、EnveropeFrom は実行ユーザーを表す適当な文字列になり、結果的にRFC違反のメールアドレスを EnveropeFrom に設定することになってしまいました("や@はRFC違反です)。

解決策として、Logwatchの設定ファイルで mailer を設定するときに、コマンドラインオプションの f を使って EnveropeFromを設定しました。

Discussion