おふとんの中から

その辺に転がってるエンジニアの備忘録

AWS SES+SNSによるNotification受け取りをGolangで実装する

ゆいなです。

この記事はGo Advent Calendar 202120日目の記事です。

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では検証するメソッドが提供されているようですが、GolangAWS SDKでは提供されていません。
また、AWSGolangSDKでは提供する予定がないようです。
有志で作成されたヘルパー等はありますが、多くは使われていないですしそのままコード化できそうです。

ということでAWSから提示された検証方法をそのままコードに落としました。

SNSNotificationPayloadにunmarshialしている前提のコードですが、ほぼAWSから案内されている検証方法通りです。
追加でバリデーションは入れていますが、URLが正しいか等の検証になります。

おわりに

今回はいつものブログ以上に超真面目な記事になりましたが、普段はちゃらんぽらんなのでそんなに真面目な人だと思うでないぞ・・・?