[マルチアカウント]SESのVPCエンドポイントを集約させて、メール送信してみた

プライベートな環境からSESのSMTPインターフェイスを使用する場合は、インターネット接続のためにNAT GatewayもしくはVPCエンドポイントが必要です。今回はマルチアカウント環境でSESを使用することを想定し、VPCエンドポイントを共通アカウントに集約させて、メール送信してみました。
2023.07.14

マルチアカウントでSESを使いたい

こんにちは!AWS事業本部のおつまみです。

みなさん、マルチアカウントでSESのSMTP インターフェイスを使いたいと思ったことはありますか?私はあります。

SESにはメール配信方法として、こちらの3種類があります。

  • Amazon SES API
  • Amazon SES SMTP インターフェイス
  • Amazon SES コンソール

Amazon SES 認証情報の種類 - Amazon Simple Email Service

そしてプライベートサブネットにあるEC2やECSなどのAWSリソースからAmazon SES SMTP インターフェイスを使用する場合、インターネット接続が必要となります。そのため、NAT GatewayもしくはVPCエンドポイント(SMTPエンドポイント)を配置する必要があります。

ただしマルチアカウントの場合、各アカウントごとにNAT GatewayやVPCエンドポイントを作成するとコストがかかってしまいます。

  • NAT Gatewayの場合
    • NAT Gateway 1 つあたりの料金 (USD/時間)+処理データ 1 GB あたりの料金 (USD)
    • 通信しなくても、1ヶ月あたり最低でも45$程度はかかります(2023/7時点)
  • VPCエンドポイントの場合
    • VPC エンドポイント 1 つあたりの料金 (USD/時間)+処理データ 1 GB あたりの料金 (USD)
    • 通信しなくても、1ヶ月あたり最低でも10$程度はかかります(2023/7時点)

また両者とも可用性高めるために、Multi-AZ配置にした場合は2倍のコストがかかります。

そのため今回はコスト削減のため、1つのアカウント(ここでは共通アカウントと呼びます)にVPCエンドポイントを集約させ、SESでメール配信する方法をご紹介します。

前提条件としては以下のとおりです。

  • 「複数のリソースアカウントVPC」と「共通アカウントVPC」がVPCピアリングによりIP到達可能な状態

※上図はVPCピアリングによって通信可能な状態を想定したものですが、 ここの部分は Transit Gateway(TGW) でも大丈夫です。

なおVPCエンドポイントを集約する手順は、ほぼこちらのブログを参考にしました。ありがとうございました。

やってみた

概要

今回はリソースアカウント #1のみ、検証で確かめます。
前提条件は、リソースアカウント #1共通アカウントのVPCがお互い通信可能な状態であることです。

大まかな流れは以下のとおりです。

  1. セキュリティグループとVPCエンドポイントの作成
  2. プライベートホストゾーンとエイリアスレコードの作成
  3. プライベートホストゾーンの関連付け

まずは、共通アカウント側からの手順になります。

手順1. セキュリティグループとVPCエンドポイントの作成

共通アカウント側でVPCエンドポイントにアタッチするセキュリティグループを作成します。
セキュリティグループには、 接続元のIPアドレス(or CIDR)からの SMTPを許可するインバウンドルールを入れておきます。今回は587を選択しましたが、次のポート番号のいずれかを使用できます。

  • 25、465、587、2465、または 2587

アウトバウンドルールはすべてのトラフィックを開放にします。

次にVPCエンドポイントを作成します。
設定する際、 [プライベート DNS名を有効にする] のチェックは必ず外してください。

サブネットは今回ap-northeast-1aのみを指定していますが、可用性を向上させるためにはMulti-AZ構成にしましょう。セキュリティグループは先ほど作成したものを選択します。

ステータスが[使用可能]になれば、OKです。次の手順で赤枠のDNS名に対するレコードを作成します。

手順2. プライベートホストゾーンとエイリアスレコードの作成

次にプライベートホストゾーンを作成します。

  • ドメイン名: email-smtp.ap-northeast-1.amazonaws.com
  • コメント: (任意)
  • タイプ: プライベートホストゾーン
  • ホストゾーンに関連付ける VPC: VPCエンドポイントを作成した VPC ID

作成したホストゾーンにエイリアスレコードを作成します。

  • レコード名: (空白)
  • レコードタイプ: A
  • 値/トラフィックのルーティング先: 作成したVPCエンドポイントのDNS名

以下のような構成でホストゾーンが作成されていればOKです。赤枠が追加したエイリアスレコードです。

手順3. プライベートホストゾーンの関連付け

作成したプライベートホストゾーンをリソースアカウント #1へ共有します。 この作業は AWS CLI(もしくは SDK)しか対応していません。
今回はAWS CLIが使用できるCloudShellでコマンドを実行します。

共通アカウントで実施する手順とリソースアカウント #1で実施する手順が混在しているので、注意しながら実施してください。

ホストゾーンIDの取得(共通アカウント側)

aws route53 list-hosted-zones コマンドでホストゾーンIDを確認します。 Id部分をコピーし、控えておきます。

  • CloudShell実行結果

ホストゾーンの「関連付けの承認」作成(共通アカウント側)

aws route53 create-vpc-association-authorization コマンドで関連付けの承認を行います。 コマンドの--vpc には接続元となるリソースアカウント側の関連付け先のVPC IDを入力します。

aws route53 create-vpc-association-authorization\
 --hosted-zone-id (先程メモしたホストゾーンID)\
 --vpc VPCRegion=ap-northeast-1,VPCId=(関連付け先のVPC ID)
  • CloudShell実行結果

ホストゾーンの「関連付け」作成(リソースアカウント側)

接続元となるリソースアカウント側で関連付けを実行します。
aws route53 associate-vpc-with-hosted-zone コマンドで関連付けを行います。

aws route53 associate-vpc-with-hosted-zone\
 --hosted-zone-id (先程メモしたホストゾーンID)\
 --vpc VPCRegion=ap-northeast-1,VPCId=(関連付け先のVPC ID)
  • CloudShell実行結果

上図のように、"ChangeInfo"が返されればOKです。

マルチアカウントへの適用

他のリソースアカウントでVPCエンドポイントを使用する場合、 以下の手順が追加で必要となります。

  • 手順1で作成したセキュリティグループに接続元のIPアドレス(or CIDR)のインバウンドルール追加
  • 手順3のホストゾーンの「関連付けの承認」と「関連付け」の作成

これでリソースアカウント側から共通アカウント側のVPCエンドポイントが使用できるようになりました!

動作確認

接続確認

リソースアカウント #1側で作成したSESへ接続できるか確認します。
SESの作成方法はこちらのブログをご参考ください。

SESが以下の状態でテストします。

  • 検証済みID
    • IDのステータスが[検証済み]になっていること
  • アカウントダッシュボード
    • ステータスが[正常]になっており、サンドボックスが解除されていること
  • SMTP設定
    • SMTP認証情報が作成されていること

検証のため EC2 インスタンスからコマンドを実行する必要があります。今回はEC2インスタンスへはマネジメントコンソールからEC2 Instance Connect Endpointを利用してアクセスします。

検証に利用するコマンドは、以下のドキュメントに記載されているものをそのまま利用します。

コマンドラインを使用して、Amazon SES SMTP インターフェイスへの接続をテストする - Amazon Simple Email Service

接続テスト成功のケース

下記のコマンドで接続確認します。

openssl s_client -crlf -quiet -starttls smtp -connect email-smtp.ap-northeast-1.amazonaws.com:587
  • CloudShell実行結果

250 Okが表示され、接続成功した事が確認できました。
約 10 秒間何もしないと、接続は自動的に終了します。

メール配信

メール配信も実行してみます。

コマンドラインを使用し、Amazon SES SMTP インターフェイスを介して E メールを送信する - Amazon Simple Email Service

input.txt

EHLO test-ses.com
AUTH LOGIN
Base64EncodedSMTPUserName
Base64EncodedSMTPPassword
MAIL FROM: sender@test-ses.com
RCPT TO: aaaa.bbbbb@cccc
DATA
From: Sender Name <sender@test-ses.com>
To: aaaa.bbbbb@cccc
Subject: Amazon SES SMTP Test

This message was sent using the Amazon SES SMTP interface.
.
QUIT

下記のコマンドで接続メール配信します。

openssl s_client -crlf -quiet -starttls smtp -connect email-smtp.ap-northeast-1.amazonaws.com:587 < input.txt
  • CloudShell実行結果

  • 配信メール

手元のメールクライアントに、無事メールが届きました!

接続テスト失敗のケース

VPC エンドポイントのセキュリティグループが間違っていたり、ホストゾーンの関連付けができていないと接続が失敗します。
試しにエンドポイントのインバウンドルールを削除してみます。

先ほどと同じコマンドで接続確認します。

  • CloudShell実行結果

しばらく返答がなく、3分ほど経過するとConnection timed outが表示されます。

おまけ:共通アカウント側のSESを共有すればいいのでは?

「わざわざこんなことしなくても共通アカウント側のSESを共有すればいいのでは?」

こんな声も聞こえてきそうです。
その場合、下記の構成になります。

しかし、この場合、以下のようなデメリットがあります。

  • 一部のアカウントによりバウンス率や苦情率が高くなり、SES使用停止になった場合に他システムに影響が出る
  • 共通アカウントのSMTP認証情報を使用するため、どのアカウントが原因でバウンスが高くなっているか追うことができない。(SMTP認証情報は送信アカウントを識別するためのものです)

また、2点目のデメリットを解消するために、以下のような構成をとることも可能です。

  • リソースアカウント側でSMTP認証情報を作成
  • 共通アカウント側のSESで送信承認ポリシーを作成

こちらの方法は下記ブログをご参考ください。

しかし、この場合メール配信時にXヘッダー付与が必要となり、GrafanaやRedmineなどのアプリからはメール配信できなくなります。

Amazon SESの送信承認時のID所有者のE メールの送信 - Amazon Simple Email Service

Amazon SES SMTP インターフェイスの使用 代理送信用の Amazon SES SMTP インターフェイスを使用する場合は、X-SES-SOURCE-ARNX-SES-FROM-ARN、および X-SES-RETURN-PATH-ARN の各ヘッダーをメッセージに含める必要があります。これらのヘッダーは、SMTP 通信で DATA コマンドを発行した後に渡します。

そのため、SESを使用したい場合はマルチアカウントであっても各アカウントごとにSESを作成することを推奨します。

最後に

今回はマルチアカウント環境でSESのVPCエンドポイントを集約させて、メール送信する方法をご紹介しました。

少しでもコストを削減するためにもマルチアカウントではVPCエンドポイントを集約させましょう!

最後までお読みいただきありがとうございました!
どなたかのお役に立てれば幸いです。

以上、おつまみ(@AWS11077)でした!

参考

Amazon SES SMTP インターフェイスを使用して E メールを送信 - Amazon Simple Email Service

マルチアカウントのVPCエンドポイント(インターフェイス型)を1つに集約させる | DevelopersIO

[アップデート] Amazon SES が SMTP エンドポイントの VPC エンドポイントをサポートしました | DevelopersIO

Amazon SES の送信承認機能を利用して他アカウントからメールを送信してみた | DevelopersIO