【AWS】EC2インスタンスからPostfix + SESで外部へシステムメールを送信
Contents
はじめに
本サイトは、AWS上のEC2インスタンスに構築されています。
構築当初、EC2インスタンス上のシステム通信用に直接外部にメール送信をしようと試みていたのですが、設定調査の時間が取れず実はメールが送信できていない状態のままでした。(コンタクトフォームからご連絡いただいていた方がいたら申し訳ありません)
今回、きちんと通知メールを送信できるように、以下の設計方針でPostfixとAmazon Simple Email Service(以下SES)を組み合わせたサーバからのメール送信の基盤を構築しました。
[設計方針]
- EC2インスタンス
- EC2インスタンス上のアプリケーションは、OS標準のsendmailコマンドを利用して自ホストのPostfixをメールを送信する
- アプリケーションの送信元メールアドレスは、SESに登録済みのGmailアドレスを使用する
- Postfixは、ローカル配送対象以外の宛先のメールをSESへ外部配送する
- PostfixとSES間のSMTP接続では、SMTP認証(SASL認証)を行い、接続後はSTARTTLSで通信を暗号化する
- SES
- SESは、Postfixから着信したメールの送信元メールアドレスを確認し、登録済みアドレスの場合はメールを外部へ配送する
- 送信元と宛先のメールアドレスはGmailの同じメールアドレスを使用する(設定例ではtest@gmail.comと表記)
- 送信元サーバとメールアドレスがマッチしていないので、メール受信時にGmailの迷惑メールフォルダに振り分けられる可能性があるが、許容して手動で迷惑メール除外を行う
前提条件
本作業の前提条件は以下の通りです。
- EC2インスタンスのOSはAmazon Linux 2
- AWS マネジメントコンソールには、SESの操作権限を持つIAMユーザでログイン
- EC2インスタンス上の操作はroot権限を持つユーザで実施
- SESの送信元メールアドレス用に、予め外部サービスのメールアカウントを作成しておく(今回はGmailを使用)
本設定を行うシステムの全体構成は以下の通りです。
SESの設定
AWS マネジメントコンソールから、SESのメール中継設定を行います。
送信元メールアドレスの登録
SESは、予め確認の取れたメールアドレスが送信元のメールしか中継を行いません。そのため、送信元メールアドレスがユーザ自身のものであることを証明する作業を行います。
Amazon SES コンソール (https://console.aws.amazon.com/ses/) にアクセスし、「Email Addresses」→「Verify a New Email Address」を押下します。
メールアドレスの新規登録画面が表示されるので、送信元として登録したいメールアドレスを入力し、「Verify This Email Address」を押下します。ここで登録するメールアドレスは、現時点で受信が可能なものを使用してください。
指定したメールアドレスに確認メールが送信された旨のメッセージが表示されるので、「Close」を押下して一旦登録画面を閉じます。
登録したメールアドレス宛に以下のメールが届くので開封します。
メール本文に確認用のURLリンクが記載されているので開きます。
検証に成功した旨のメッセージが表示されたことを確認し、同画面を閉じます。
Amazon SES コンソールの「Email Addresses」を開き、登録したメールアドレスが「verified」と表示されていることを確認します。これで、送信元メールアドレスを登録できました。
サンドボックス解除のリクエスト
前述の送信元メールアドレスを登録しただけでは、SESは登録した送信元メールアドレスにしかメールを送れません。これをサンドボックスと言います。
サンドボックスを解除して、外部のメールアドレス宛にメールを送ることができるように、AWSのサポートページからリクエストを行います。
Amazon SES コンソール (https://console.aws.amazon.com/ses/) にアクセスし、「Sending Statistics」→「Request a Sending Limit Increase」を押下します。
サポートケースの作成画面が表示されるので、「Create case」のセクションにて「Service limit increase」を選択します。
「Case classification」のセクションでは、「Limit type」を「SES 送信制限」に指定します。それ以外の項目は用途に応じて適宜記入します。
「Requests」のセクションでは、「リージョン」に送信元メールアドレスを登録したリージョンを選択します。「Limit」は「希望する一日あたりの送信クォータ」を選択し、「New limit value」には1日に送信し得る最大メール通数を記入します。
「Case description」には、サポートケースを起票する理由を記入します。ここまで完了したら、「Submit」を押下し、サポートケースを起票します。
AWS マネジメントコンソールの右上の「サポート」→「サポートセンター」を選択すると、起票したサポートケースを確認できます。
1日程すると、リクエストが承認されます。承認時は、AWSアカウントに登録しているメールアドレス宛に以下のメールが送信されます。これで、サンドボックス解除のリクエストは完了です。
SMTP認証情報の取得
EC2からSESのエンドポイントにSMTP接続を行うにはSMTP認証が必要です。SMTP認証用の認証情報(クレデンシャル)を取得します。
Amazon SES コンソール (https://console.aws.amazon.com/ses/) にアクセスし、「SMTP Settings」を押下します。
「Server Name:」の項目は、後ほどPostfixの設定の中で、SESエンドポイントの指定で使用するので情報を控えておきます。
「Create My SMTP Credentials」を押下します。
SESのSMTPユーザ用IAMユーザの名前を尋ねられるので、デフォルトのままにするか任意の名前を入力し、「作成」を押下します。
「認証情報のダウンロード」を押下します。なお、ここで認証情報をダウンロードせずに「閉じる」を押下してしまうと、二度と該当IAMユーザの認証情報を取得できなくなるので注意してください。
credentials.csv
という名前のCSVファイルがダウンロードされるので、ファイルを開きます。「Smtp Username」と「Smtp Password」の列が、それぞれユーザ名とパスワードを示します。
上記を確認した後、「閉じる」を押下します。これで、SMTP認証情報の取得は完了です。
EC2インスタンスの設定
Postfixの設定
EC2インスタンス上のPostfixを設定します。root権限を持つユーザでログインします。
main.cfの設定
main.cfの設定は、/etc/postfix/main.cf
をテキストエディタで直接編集することも可能ですが、今回は手順化しやすいようにpostconf
コマンドでシェルから追加していきます。
メールのリレー先(中継サーバ)に、SESのエンドポイントを指定します。
SESのエンドポイントは、SMTP認証情報の取得の際に控えておいた情報を使用します。
# postconf -e "relayhost = [email-smtp.us-east-1.amazonaws.com]:587"
SASL認証の設定を追加します。
# postconf -e "smtp_sasl_auth_enable = yes" \
"smtp_sasl_security_options = noanonymous" \
"smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd"
TLSによる外部配送暗号化の設定を追加します。
# postconf -e "smtp_use_tls = yes" \
"smtp_tls_loglevel = 1" \
"smtp_tls_security_level = encrypt" \
"smtp_tls_note_starttls_offer = yes" \
"smtp_tls_CAfile = /etc/ssl/certs/ca-bundle.crt"
メール配送を許可する送信元ネットワークをループバックアドレスに限定し、オープンリレーを防止します。
# postconf -e "mynetworks = 127.0.0.0/8"
sasl_passwdの設定
viなどのテキストエディタで、SMTP認証情報を格納するファイルを開きます。ファイルが存在しない場合は新規作成します。
# vi /etc/postfix/sasl_passwd
SES用認証情報の取得で得られた認証情報を使用して、メール中継先のSESエンドポイントに対応するユーザ名とパスワードを指定します。ユーザ名とパスワードは:
で連結して記載します。
[email-smtp.us-east-1.amazonaws.com]:587 <ユーザ名>:<パスワード>
認証情報が記載された重要なファイルなので、所有権とアクセス権を変更してrootユーザのみファイルを編集できるようにします。
# chown root:root /etc/postfix/sasl_passwd
# chmod 600 /etc/postfix/sasl_passwd
認証情報のハッシュマップDBを作成
先ほど作成したsasl_passwd
のハッシュマップDBファイルを作成します。
# postmap hash:/etc/postfix/sasl_passwd
認証情報が記載された重要なファイルなので、所有権とアクセス権を変更してrootユーザのみファイルを編集できるようにします。
# chown root:root /etc/postfix/sasl_passwd.db
# chmod 600 /etc/postfix/sasl_passwd.db
設定の有効化
設定を有効化するため、postfixサービスを再起動します。
# systemctl restart postfix
メール送信テスト
EC2インスタンス上で以下のコマンドを実行し、外部へのメール送信をテストします。
送信元メールアドレスは、SESに登録したものを指定します。宛先メールアドレスは、自分が受信可能なものを指定します。
本文の最後のピリオドを入力した時点で、それまでの内容がメール送信されます。
# sendmail -f <送信元メールアドレス> <宛先メールアドレス>
From: <送信元メールアドレス>
Subject: <件名>
<本文>
.
メール送信実施後、ログファイルに以下のログが表示されます。末尾から2行目で、smtpプロセスによるメール送信結果がstatus=sent
と表示されていれば、送信は成功です。
# tail /var/log/maillog
(略)
Nov 9 14:58:36 ip-xx-xx-xx-xx postfix/pickup[2808]: B65B3C848CA: uid=0 from=<test@gmail.com>
Nov 9 14:58:36 ip-xx-xx-xx-xx postfix/cleanup[2813]: B65B3C848CA: message-id=<20191109145836.B65B3C848CA@ip-ip-xx-xx-xx-xx.ec2.internal>
Nov 9 14:58:36 ip-xx-xx-xx-xx postfix/qmgr[2809]: B65B3C848CA: from=<test@gmail.com>, size=300, nrcpt=1 (queue active)
Nov 9 14:58:36 ip-xx-xx-xx-xx postfix/smtp[2815]: Trusted TLS connection established to email-smtp.us-east-1.amazonaws.com[18.214.81.247]:587: TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)
Nov 9 14:58:37 ip-xx-xx-xx-xx postfix/smtp[2815]: B65B3C848CA: to=<test@gmail.com>, relay=email-smtp.us-east-1.amazonaws.com[18.214.81.247]:587, delay=16, delays=16/0.02/0.09/0.16, dsn=2.0.0, status=sent (250 Ok 0100016e50ac90c5-e5a0bfbd-f957-4deb-9ebc-634e37e035b4-000000)
Nov 9 14:58:37 ip-xx-xx-xx-xx postfix/qmgr[2809]: B65B3C848CA: removed