本記事は
AWSアワード記念!夏のアドベントカレンダー
16日目の記事です。
🎆🏆
15日目
▶▶ 本記事 ▶▶
17日目
🏆🎆
最近、Amazon Simple Email Service(以下:SES) の承認ポリシーを設定する機会があったので、今回は備忘もかねて書いてみます。
はじめに
SES は API エンドポイントまたは SMTP インターフェイス を利用してメール配信を行えるサービスです。SES を利用するためには検証済みIDとしてメールアドレスもしくはドメインを作成します。IDステータスが検証済みになっていれば利用可能です。承認ポリシーは検証済みIDの詳細ページに表示されている承認タブから設定できます。特定の検証済みIDに対して許可または拒否されるAPIアクションとその条件を指定するステートメントを json 形式で設定することで個々の検証済みIDがどのように使用されるかを定義、制限することができます。
本記事では、承認ポリシーのユースケースと設定例とついて書いていきます。
送信元を特定のメールアドレスに制限する
no-reply
のような実際に受信できないメールアドレスを利用したいときは、ドメインを検証済みIDで登録することがあります。ドメインを検証済みIDとして登録するとメールアドレスを個別に検証する必要がなく、検証済みドメインの任意のサブドメインまたはメールアドレスからメールを送信できます。本番環境で利用想定がないメールアドレス(例えばtest-case123-20240730@example.net
)も送信元として使用可能になります。これを防ぐために、ポリシーを使って制限します。
以下の例では、送信元をno-reply@example.net
に制限しています。
{ "Version": "2012-10-17", "Statement": [ { "Sid": "stmt1721805312724", "Effect": "Deny", "Principal": { "AWS": "arn:aws:iam::123456789012:root" }, "Action": [ "ses:SendEmail", "ses:SendRawEmail" ], "Resource": "arn:aws:ses:us-west-2:123456789012:identity/example.net", "Condition": { "StringNotLike": { "ses:FromAddress": "no-reply@example.net" } } } ] }
これにより、意図しないメールアドレスを利用したメール配信を防ぐことができます。
$ aws ses send-email --from test-case123-20240730@example.net --to mail-to@example.org --subject subject --text body An error occurred (AccessDenied) when calling the SendEmail operation: User `arn:aws:sts::123456789012:assumed-role/role-for-ec2/i-085d53c347635f98a' is not authorized to perform `ses:SendEmail' on resource `arn:aws:ses:us-west-2:123456789012:identity/example.net'
メールの送信先ドメインを制限する
すべての新しいアカウントは初めにサンドボックスに配置され、メールの送信先は検証済みIDとして作成したメールアドレスやドメインに制限されています。このため、未検証の宛先にはメールが送信されないので送信先を制限することは少ないかなと思います。ただし上限緩和(サンドボックスからのアカウント削除)を行ったアカウントはこの限りではありません。AWSに上限緩和申請を行うことで、検証されていないメールアドレスやドメインにもメールを送信できるようになります。またサンドボックス環境では、送信クォータは24時間あたり200メッセージ、送信レートは1秒あたり1メッセージに制限されており、これらの制限も上限緩和申請することで引き上げることができます。送信クォータや送信レートを引き上げつつ、送信先は制限したい場合は承認ポリシーを使用することで実現が可能です。
以下の例では、送信先を*@example.org
に制限しています。
{ "Version": "2012-10-17", "Statement": [ { "Sid": "stmt1721805435092", "Effect": "Deny", "Principal": { "AWS": "arn:aws:iam::123456789012:root" }, "Action": [ "ses:SendRawEmail", "ses:SendEmail" ], "Resource": "arn:aws:ses:us-west-2:123456789012:identity/example.net", "Condition": { "ForAllValues:StringNotLike": { "ses:Recipients": "*@example.org" } } } ] }
送信元のIPアドレスを制限する
外部への通信を許容できずメール配信処理をプライベートサブネット内で行いたい場合には送信元の制限にIPアドレスを指定することも可能です。
以下の例では、送信元を172.31.0.0/16
のみに制限しています。
{ "Version": "2012-10-17", "Statement": [ { "Sid": "stmt1721803415601", "Effect": "Deny", "Principal": { "AWS": "arn:aws:iam::123456789012:root" }, "Action": [ "ses:SendEmail", "ses:SendRawEmail" ], "Resource": "arn:aws:ses:us-west-2:123456789012:identity/example.net", "Condition": { "NotIpAddress": { "aws:SourceIp": "172.31.0.0/16" } } } ] }
実際にVPCエンドポイントを作成したプライベートサブネットの CIDR を設定しインターネットを経由しないメール配信を試してみました。
$ aws ses send-email --from mail-from@example.net --to mail-to@example.org --subject subject --text body Connect timeout on endpoint URL: "https://email.us-west-2.amazonaws.com/"
結果は API のエンドポイントに到達できずタイムアウトになりました。公式ドキュメントには SES のVPCエンドポイントへの接続は SMTP インターフェースを利用する手順が記載されています。実際に SES のVPCエンドポイントは SMTP インターフェースの対応のみで API のVPCエンドポイントは用意されていません。そのため、外部への通信を許容できずメール配信処理をプライベートサブネット内で行いたい場合は SMTP での実装が必要になります。SMTP インターフェースを利用するためには API 利用と異なる部分があるので簡単ですが以下にまとめています。
利用 | 通信要件 | 権限付与 | 実装 |
---|---|---|---|
API | インターネット | EC2 や ECS などメール配信を行うサービスにアタッチしている IAM Role に権限付与 | 直接 HTTPS リクエストを作成する AWS SDK を使用する AWS CLI を使用する |
SMTP | インターネット VPCエンドポイント |
SMTP認証情報としてアクセスキー/シークレットキーを発行して利用 | SMTP 対応ソフトウェアを使用する SMTP対応言語でプログラムする |
最後に
以上、SES の承認ポリシーについて試してみました。 個人的に SES はAWSサービスの中でも比較的導入や検証が容易な反面、セキュリティインシデントにも繋がりやすいサービスだと思います。意図しないメール配信を防ぐために承認ポリシーについて考えてみるきっかけになれば幸いです。