ゆいなです。
この記事はGo Advent Calendar 2021の20日目の記事です。
AWS SES+SNSによるNotificationの受け取りをGolangで実装する機会があったのですが、日本語で解説がある記事がなかったので、あとの人のために残しておこうと思います。
そもそもなんでこの組み合わせなの?
AWS SES+SNSによるNotificationの受け取りは主にメールのバウンス管理で使われます。
今でこそ、AccountレベルのsupressionListがありますが、以前はそれすらもなく全てSESを使うユーザーが実装する必要がありました。
SES+SNSは最小構成でバウンス管理を実装するための仕組みになります。
今回はSNSから特定のエンドポイントへ通知を送信し、エンドポイント側が何かしらに使える状態に持っていくところまでをやっていきます。
で、どうやったの?
AWS設定周り
基本的にはSESからメールバウンスや苦情のリクエストをSNSに流すのは、画面ポチポチで設定可能です。
今回はNotification受け取りに絞るため、設定に関する説明はAWSのマニュアルに任せましょう。
https://docs.aws.amazon.com/ja_jp/ses/latest/DeveloperGuide/configure-sns-notifications.html
SNSからエンドポイントに送信するのもSNSのサブスクリプションをごにょごにょすればすぐに作成できますが、エンドポイントを実装するまでは待ちましょう・・・。
エンドポイント実装
今回のメインはエンドポイント側の実装です。
エンドポイントに何が入っているかについては以下のAWSの記述を見ると大体書いてあります。
https://docs.aws.amazon.com/ja_jp/sns/latest/dg/sns-http-https-endpoint-as-subscriber.html
今回controllerはAWSで提示されているリクエストを受け取れるように実装します。
また、SNSからの初回のsubscribeリクエストも同様のリクエストでくるため、こちらも処理する必要があります。
SNSからの通知の場合、単純にリクエストを受け取って処理してしまうだけではNGです。
メッセージが本当にAWSから送信されてきたものなのかを確認する必要があります。
MessageにはSignatureがついているので、署名が正しいことを確認してから処理をする必要があります。
署名検証については後述。
最終的にNotificationを受け取った後はMessageの中身を再度unmarshalして、必要な値を取得して開ければ問題ないはずです。
Messageの内容の定義についてもAWSのドキュメントにあるため、参照すれば大丈夫。
https://docs.aws.amazon.com/ja_jp/ses/latest/DeveloperGuide/notification-contents.html
署名検証
署名検証についても検証方法のドキュメントは提供されています。
https://docs.aws.amazon.com/ja_jp/sns/latest/dg/sns-verify-signature-of-message.html
一部の言語のSDKでは検証するメソッドが提供されているようですが、GolangのAWS SDKでは提供されていません。
また、AWSもGolangのSDKでは提供する予定がないようです。
有志で作成されたヘルパー等はありますが、多くは使われていないですしそのままコード化できそうです。
ということでAWSから提示された検証方法をそのままコードに落としました。
SNSNotificationPayload
にunmarshialしている前提のコードですが、ほぼAWSから案内されている検証方法通りです。
追加でバリデーションは入れていますが、URLが正しいか等の検証になります。
おわりに
今回はいつものブログ以上に超真面目な記事になりましたが、普段はちゃらんぽらんなのでそんなに真面目な人だと思うでないぞ・・・?