SESで送信先メールアドレスをexample.comドメインに制限する

  • AWS
  • SES
  • IAM

この記事は、構成と文章の整理にAIを使っています。
あくまで読みやすくするための補助で、内容そのものをAIにすべて任せて書いているわけではありませんが、ところどころ相談しながら整えています。

先に結論。SESで「受信者をexample.comドメインだけに制限したい」場合、IAMポリシーの条件演算子は ForAllValues:StringLike を使う。

やりたいこと

SendEmail用のIAMポリシーで、送信元と送信先の両方をexample.comドメインに縛りたい。送信元(ses:FromAddress)は単一値のキーなので普通にStringLikeで書けばいい。

{
"Effect": "Allow",
"Action": ["ses:SendEmail"],
"Condition": {
"StringLike": {
"ses:FromAddress": ["*@example.com"]
}
},
"Resource": "*"
}

問題は受信者側の書き方。

受信者制限の実装

ses:Recipients はTo/CC/BCCをまとめた複数値のコンテキストキー。複数値キーに対する集合演算子には ForAllValues と ForAnyValue があって、意味が違う。

  • ForAllValues: リクエストに含まれる全ての値が条件に一致する場合にtrue
  • ForAnyValue: リクエストに含まれる値のうち、少なくとも1つが条件に一致すればtrue

「example.com以外には送らない」を実現したいので、受信者全員がexample.comであることを要求するForAllValuesが正しい。

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["ses:SendEmail"],
"Resource": "*",
"Condition": {
"ForAllValues:StringLike": {
"ses:Recipients": ["*@example.com"]
}
}
}
]
}

ForAnyValueを使うと、受信者リストにuser@example.comとattacker@evil.comが両方入っていても、user@example.comが条件にマッチした時点で条件全体がtrueになる。つまり外部ドメインが混ざっていても送信が許可されてしまうので、受信者制限の用途では使えない。

補足: Nullチェック

AWSの公式ドキュメントでは、Allow効果とForAllValuesを組み合わせる場合の注意点として、リクエストにそのコンテキストキー自体が存在しないケースでも条件がtrueになる、という挙動が挙げられている。ses:RecipientsはSendEmail系APIなら基本的に存在するはずだが、厳密にやるならNull条件を足しておくのが公式の推奨パターンらしい。

"Condition": {
"ForAllValues:StringLike": {
"ses:Recipients": ["*@example.com"]
},
"Null": {
"ses:Recipients": "false"
}
}

実機で「キーが存在しないリクエスト」を意図的に作って検証したわけではないので、ここは公式ドキュメントの記述をそのまま採用している。

参考