NRIネットコム社員が様々な視点で、日々の気づきやナレッジを発信するメディアです

注目のタグ

    AWS SES の承認ポリシーを設定してみた

    本記事は  AWSアワード記念!夏のアドベントカレンダー  16日目の記事です。
    🎆🏆  15日目  ▶▶ 本記事 ▶▶  17日目  🏆🎆

    こんにちは、坂本です。 今年の 2024 Japan AWS All Certifications Engineer に選ばれましたので AWSアワード記念!夏のアドベントカレンダー を機にブログ初投稿になります。

    最近、Amazon Simple Email Service(以下:SES) の承認ポリシーを設定する機会があったので、今回は備忘もかねて書いてみます。

    はじめに

    SES は API エンドポイントまたは SMTP インターフェイス を利用してメール配信を行えるサービスです。SES を利用するためには検証済みIDとしてメールアドレスもしくはドメインを作成します。IDステータスが検証済みになっていれば利用可能です。承認ポリシーは検証済みIDの詳細ページに表示されている承認タブから設定できます。特定の検証済みIDに対して許可または拒否されるAPIアクションとその条件を指定するステートメントを json 形式で設定することで個々の検証済みIDがどのように使用されるかを定義、制限することができます。

    本記事では、承認ポリシーのユースケースと設定例とついて書いていきます。

    AWS マネジメントコンソール

    送信元を特定のメールアドレスに制限する

    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サービスの中でも比較的導入や検証が容易な反面、セキュリティインシデントにも繋がりやすいサービスだと思います。意図しないメール配信を防ぐために承認ポリシーについて考えてみるきっかけになれば幸いです。