[アップデート] SNS サブスクリプションフィルターのスコープとしてメッセージ属性に加えメッセージ本文がサポートされました
コンバンハ、千葉(幸)です。
Amazon SNS でペイロード(メッセージ本文)ベースでのメッセージフィルタリングがサポートされました。
これまではメッセージ属性でだけフィルタリングが可能でしたが、メッセージ本文でもできるようになりました。
ネタが被りました
いそいそとアップデートブログを書いていたら 若槻 が同じネタでブログを書いていました。
若干アプローチが違うので、あわせて読むとより理解が捗るかと思います!!!
何が変わったのか
イメージは以下です。
SNS トピックはイベントソースからイベントを受け取り、サブスクライブしたエンドポイントにメッセージを発行します。
イベントソースとなる AWS サービスは多々あり、その一覧は以下にまとまっています。
例えば Amazon RDS イベントサブスクリプションをイベントソースとするイベントを例にとると、その内訳は以下の構造になっています。
{ "Records": [ { "EventSource": "aws:sns", "EventVersion": "1.0", "EventSubscriptionArn": "arn:aws:sns:ap-northeast-1:012345678910:Publish-to-Lambda:b54a1670-6021-4da7-9a58-86ba7ff436e1", "Sns": { "Type": "Notification", "MessageId": "862f377d-4fd4-5a82-8156-6c9246b1629a", "TopicArn": "arn:aws:sns:ap-northeast-1:012345678910:Publish-to-Lambda", "Subject": "RDS Notification Message", "Message": "{\"Event Source\":\"db-cluster\",\"Event Time\":\"2022-11-16 15:52:04.443\",\"Identifier Link\":\"https://console.aws.amazon.com/rds/home?region=ap-northeast-1#dbclusters:id=database-1\",\"Source ID\":\"database-1\",\"Source ARN\":\"arn:aws:rds:ap-northeast-1:012345678910:cluster:database-1\",\"Event ID\":\"http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_Events.html#RDS-EVENT-0150\",\"Event Message\":\"DB cluster stopped\"}", "Timestamp": "2022-11-16T15:52:05.043Z", "SignatureVersion": "1", "Signature": "qo30sQiOPS8r1WBVHFCvyrAnX6+q7FYGZYKga(略)vP1Mnv/D6KYrovs13E3YqjrXPw==", "SigningCertUrl": "https://sns.ap-northeast-1.amazonaws.com/SimpleNotificationService-56e(略)385.pem", "UnsubscribeUrl": "https://sns.ap-northeast-1.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:ap-northeast-1:012345678910:Publish-to-Lambda:b54a1(略)ff436e1", "MessageAttributes": { "Resource": { "Type": "String", "Value": "arn:aws:rds:ap-northeast-1:012345678910:cluster:database-1" }, "EventID": { "Type": "String", "Value": "RDS-EVENT-0150" } } } } ] }
12 行目がメッセージ本文(ペイロード)、18-27 行目がメッセージ属性です。
(メッセージ本文を整形すると以下のようになります。)
{ "Event Source": "db-cluster", "Event Time": "2022-11-16 15:52:04.443", "Identifier Link": "https://console.aws.amazon.com/rds/home?region=ap-northeast-1#dbclusters:id=database-1", "Source ID": "database-1", "Source ARN": "arn:aws:rds:ap-northeast-1:012345678910:cluster:database-1", "Event ID": "http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_Events.html#RDS-EVENT-0150", "Event Message": "DB cluster stopped" }
なお、今回のイベント例ではメッセージ属性が含まれていましたが、すべてのイベントに含まれているわけではありません。
SNS トピックでは宛先エンドポイントごとにサブスクリプションを作成します。デフォルトではすべてのメッセージをサブスクリプションしたエンドポイントに発行しますが、オプションでフィルタリングポリシーを設定することでフィルタリングが可能です。
従来はフィルタリングポリシーのスコープとなるのはメッセージ属性のみでしたが、今回のアップデートによりメッセージ本文もスコープにできるようになりました。
設定画面でもこのようにスコープの選択ができますね。
メッセージの内容に応じて後続のリソースに振り分ける、というのを、間に何か挟んだりトピックを分けたりすることなくお手軽に実現できるようになりました。
詳細は以下ドキュメントを詳細してください。
やってみた
今回は以下ブログで取り上げられている構成を試してみます。
ここでは S3 バケットに特定の接頭辞(auto
もしくはhome
)を持つオブジェクトが格納された際に、それぞれに応じた SQS キューにメッセージを振り分ける仕組みが想定されています。
そしてありがたいことに一式の構成をデプロイできる SAM テンプレートが用意されています。
(画像は上記ブログより引用)
SAM によるリソース一式のデプロイ
今回は AWS Cloud9 環境から実行していきます。使用した SAM CLI のバージョンは以下です。
$ sam --version SAM CLI, version 1.57.0
以下に SAM のテンプレートが公開されています。
ローカルにテンプレートをダウンロードします。
$ curl -O https://raw.githubusercontent.com/aws-samples/aws-sns-samples/master/templates/SNS-Payload-Based-Filtering-SAM.template % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 2757 100 2757 0 0 9108 0 --:--:-- --:--:-- --:--:-- 9099
テンプレートを指定してビルドを行います。
$ sam build -t SNS-Payload-Based-Filtering-SAM.template Build Succeeded Built Artifacts : .aws-sam/build Built Template : .aws-sam/build/template.yaml Commands you can use next ========================= [*] Validate SAM template: sam validate [*] Invoke Function: sam local invoke [*] Test Function in the Cloud: sam sync --stack-name {stack-name} --watch [*] Deploy: sam deploy --guided
ガイドに従いデプロイを行います。
$ sam deploy --guided Configuring SAM deploy ====================== Looking for config file [samconfig.toml] : Not found Setting default arguments for 'sam deploy' ========================================= Stack Name [sam-app]: sns-payload AWS Region [ap-northeast-1]: #Shows you resources changes to be deployed and require a 'Y' to initiate deploy Confirm changes before deploy [y/N]: y #SAM needs permission to be able to create roles to connect to the resources in your template Allow SAM CLI IAM role creation [Y/n]: y #Preserves the state of previously provisioned resources when an operation fails Disable rollback [y/N]: y Save arguments to configuration file [Y/n]: y SAM configuration file [samconfig.toml]: SAM configuration environment [default]: Looking for resources needed for deployment: Managed S3 bucket: aws-sam-cli-managed-default-samclisourcebucket-58h089x7vwj A different default S3 bucket can be set in samconfig.toml Saved arguments to config file Running 'sam deploy' for future deployments will use the parameters saved above. The above parameters can be changed by modifying samconfig.toml Learn more about samconfig.toml syntax at https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html Deploying with following values =============================== Stack name : sns-payload Region : ap-northeast-1 Confirm changeset : True Disable rollback : True Deployment s3 bucket : aws-sam-cli-managed-default-samclisourcebucket-58h089x7vwj Capabilities : ["CAPABILITY_IAM"] Parameter overrides : {} Signing Profiles : {} Initiating deployment ===================== Uploading to sns-payload/0f37e669edf344868277b8a6a14533ae.template 3190 / 3190 (100.00%) Waiting for changeset to be created.. CloudFormation stack changeset --------------------------------------------------------------------------------------------------------------------- Operation LogicalResourceId ResourceType Replacement --------------------------------------------------------------------------------------------------------------------- + Add AutoInsuranceEventsQueue AWS::SQS::Queue N/A + Add AutoInsuranceEventsSubscrip AWS::SNS::Subscription N/A tion + Add HomeInsuranceEventsQueue AWS::SQS::Queue N/A + Add HomeInsuranceEventsSubscrip AWS::SNS::Subscription N/A tion + Add InsuranceEventsBucket AWS::S3::Bucket N/A + Add InsuranceEventsQueuePolicy AWS::SQS::QueuePolicy N/A + Add InsuranceEventsTopicPolicy AWS::SNS::TopicPolicy N/A + Add InsuranceEventsTopic AWS::SNS::Topic N/A --------------------------------------------------------------------------------------------------------------------- Changeset created successfully. arn:aws:cloudformation:ap-northeast-1:012345678910:changeSet/samcli-deploy1669179940/80e18d2f-c484-4b7d-ab2e-e26c22d0f9f5 Previewing CloudFormation changeset before deployment ====================================================== Deploy this changeset? [y/N]: y 2022-11-23 05:06:03 - Waiting for stack create/update to complete CloudFormation events from stack operations (refresh every 0.5 seconds) --------------------------------------------------------------------------------------------------------------------- ResourceStatus ResourceType LogicalResourceId ResourceStatusReason --------------------------------------------------------------------------------------------------------------------- CREATE_IN_PROGRESS AWS::SQS::Queue HomeInsuranceEventsQueue - CREATE_IN_PROGRESS AWS::SNS::Topic InsuranceEventsTopic - CREATE_IN_PROGRESS AWS::SQS::Queue AutoInsuranceEventsQueue - CREATE_IN_PROGRESS AWS::SQS::Queue HomeInsuranceEventsQueue Resource creation Initiated CREATE_IN_PROGRESS AWS::SNS::Topic InsuranceEventsTopic Resource creation Initiated CREATE_IN_PROGRESS AWS::SQS::Queue AutoInsuranceEventsQueue Resource creation Initiated CREATE_COMPLETE AWS::SNS::Topic InsuranceEventsTopic - CREATE_IN_PROGRESS AWS::SNS::TopicPolicy InsuranceEventsTopicPolicy - CREATE_IN_PROGRESS AWS::SNS::TopicPolicy InsuranceEventsTopicPolicy Resource creation Initiated CREATE_COMPLETE AWS::SNS::TopicPolicy InsuranceEventsTopicPolicy - CREATE_IN_PROGRESS AWS::S3::Bucket InsuranceEventsBucket - CREATE_IN_PROGRESS AWS::S3::Bucket InsuranceEventsBucket Resource creation Initiated CREATE_COMPLETE AWS::S3::Bucket InsuranceEventsBucket - CREATE_COMPLETE AWS::SQS::Queue HomeInsuranceEventsQueue - CREATE_COMPLETE AWS::SQS::Queue AutoInsuranceEventsQueue - CREATE_IN_PROGRESS AWS::SNS::Subscription HomeInsuranceEventsSubscrip - tion CREATE_IN_PROGRESS AWS::SNS::Subscription HomeInsuranceEventsSubscrip Resource creation Initiated tion CREATE_COMPLETE AWS::SNS::Subscription HomeInsuranceEventsSubscrip - tion CREATE_IN_PROGRESS AWS::SQS::QueuePolicy InsuranceEventsQueuePolicy - CREATE_IN_PROGRESS AWS::SNS::Subscription AutoInsuranceEventsSubscrip - tion CREATE_IN_PROGRESS AWS::SQS::QueuePolicy InsuranceEventsQueuePolicy Resource creation Initiated CREATE_COMPLETE AWS::SQS::QueuePolicy InsuranceEventsQueuePolicy - CREATE_IN_PROGRESS AWS::SNS::Subscription AutoInsuranceEventsSubscrip Resource creation Initiated tion CREATE_COMPLETE AWS::SNS::Subscription AutoInsuranceEventsSubscrip - tion CREATE_COMPLETE AWS::CloudFormation::Stack sns-payload - --------------------------------------------------------------------------------------------------------------------- CloudFormation outputs from deployed stack ------------------------------------------------------------------------------------------------------------------------ Outputs ------------------------------------------------------------------------------------------------------------------------ Key InsuranceEventsBucketName Description The name of the S3 bucket to which insurance documents are uploaded, and from which events are triggered Value sns-payload-insuranceeventsbucket-l93auq0ntam1 ------------------------------------------------------------------------------------------------------------------------ Successfully created/updated stack - sns-payload in ap-northeast-1
これにより、以下が作成されました。
- S3 バケット(イベント含む)
- SNS トピック(トピックポリシー含む)
- SQS キュー *2 (キューポリシー含む)
- SNS サブスクリプション *2 (フィルタリングポリシー含む)
メッセージ本文に応じたフィルタリングを確認する
2 つある SNS サブスクリプションのフィルタリングポリシーはそれぞれ以下のような値で作成されています。
{ "Records": { "s3": { "object": { "key": [{ "prefix": "auto-" }] } }, "eventName": [{ "prefix": "ObjectCreated:" }] } }
{ "Records": { "s3": { "object": { "key": [{ "prefix": "home-" }] } }, "eventName": [{ "prefix": "ObjectCreated:" }] } }
対応する接頭辞を持つオブジェクトの Put イベントがあれば後続の SQS キューにメッセージを発行する、という状態です。
S3 バケットにオブジェクトを Put することでイベントを発火させます。今回はauto
を 4 つ、home
を 2 つ Put しました。
S3 イベント→ SNS トピック→ SQS キューという形でイベントが流れていきます。SQS キューを確認すると、それぞれ対応したメッセージを受信していることがわかります。
SQS キューに入ったメッセージはこのような感じ。ここにはメッセージ属性は含まれていないので、アップデート前ではフィルタリングポリシーが使えなかったことが分かります。
{ "Type" : "Notification", "MessageId" : "d485d7de-dae5-51a2-bd1e-8c2968933974", "TopicArn" : "arn:aws:sns:ap-northeast-1:012345678910:insurance-events-topic", "Subject" : "Amazon S3 Notification", "Message" : "{\"Records\":[{\"eventVersion\":\"2.1\",\"eventSource\":\"aws:s3\",\"awsRegion\":\"ap-northeast-1\",\"eventTime\":\"2022-11-23T05:31:33.233Z\",\"eventName\":\"ObjectCreated:Put\",\"userIdentity\":{\"principalId\":\"AWS:AROAQ3BIIH732QEGJXBGU:cm-chiba.yukihiro\"},\"requestParameters\":{\"sourceIPAddress\":\"xx.xx.25.83\"},\"responseElements\":{\"x-amz-request-id\":\"YSR0M0C13618E6QH\",\"x-amz-id-2\":\"02QUPfFMnDzo1enRtf2Q12KYVcFEs7A1XHgD6REOUMfqZJiWDwAZzhMMMD8LblWJjCBrYqcGSTUg3FtyUVcV8rkuZEU6FMfoUg++XJnMK8A=\"},\"s3\":{\"s3SchemaVersion\":\"1.0\",\"configurationId\":\"46cc3514-078b-4fd3-a1dd-39fc5ee5f826\",\"bucket\":{\"name\":\"sns-payload-insuranceeventsbucket-l93auq0ntam1\",\"ownerIdentity\":{\"principalId\":\"A21653DPHJ2PYW\"},\"arn\":\"arn:aws:s3:::sns-payload-insuranceeventsbucket-l93auq0ntam1\"},\"object\":{\"key\":\"auto-sample.txt\",\"size\":4,\"eTag\":\"13d6a250f529e31f9dfda14bcba250ee\",\"sequencer\":\"00637DB03532F77F43\"}}}]}", "Timestamp" : "2022-11-23T05:31:34.414Z", "SignatureVersion" : "1", "Signature" : "R0Y7dqKTNb0EJbAEz9eZ1KN(略)gjGnQvU5utNzGHorQn3xqyvrgiUSA==", "SigningCertURL" : "https://sns.ap-northeast-1.amazonaws.com/SimpleNotificationService-56(略)85.pem", "UnsubscribeURL" : "https://sns.ap-northeast-1.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:ap-northeast-1:012345678910:insurance-events-topic:b(略)1c6" }
(ちなみにメッセージ本文を整形するとこのような形になっています。)
{ "Records": [ { "eventVersion": "2.1", "eventSource": "aws:s3", "awsRegion": "ap-northeast-1", "eventTime": "2022-11-23T05:31:33.233Z", "eventName": "ObjectCreated:Put", "userIdentity": { "principalId": "AWS:AROAQ3BIIH732QEGJXBGU:cm-chiba.yukihiro" }, "requestParameters": { "sourceIPAddress": "xx.xx.25.83" }, "responseElements": { "x-amz-request-id": "YSR0M0C13618E6QH", "x-amz-id-2": "02QUPfFMn(略)nMK8A=" }, "s3": { "s3SchemaVersion": "1.0", "configurationId": "46cc3514-078b-4fd3-a1dd-39fc5ee5f826", "bucket": { "name": "sns-payload-insuranceeventsbucket-l93auq0ntam1", "ownerIdentity": { "principalId": "A21653DPHJ2PYW" }, "arn": "arn:aws:s3:::sns-payload-insuranceeventsbucket-l93auq0ntam1" }, "object": { "key": "auto-sample.txt", "size": 4, "eTag": "13d6a250f529e31f9dfda14bcba250ee", "sequencer": "00637DB03532F77F43" } } } ] }
CloudWatch メトリクスではNumberOfNotificationsFilteredOut-MessageBody
というメトリクスで「メッセージ本文でフィルタリングが行われたイベント」の数が確認できます。
SNS サブスクリプションでメッセージ本文を用いたフィルタリングができることを確認しました。
終わりに
Amazon SNS でペイロード(メッセージ本文)ベースでのメッセージフィルタリングがサポートされた、というアップデートでした。
例えば今回試したような「S3 バケットに Put されたオブジェクトのプレフィックスに応じてメッセージを振り分ける」ということをやろうとした場合、アップデート前であれば以下のような構成を採る必要がありました。
- S3 イベント通知、それを受ける SNS トピックを 2 セット準備するパターン
- S3 イベントを Lambda 関数が受け、接頭辞を判断して SQS に振り分けるパターン
- SNS トピックのメッセージを Lambda 関数が受け、接頭辞を判断して SQS に振り分けるパターン
今回のアップデートによりシンプルな構成で振り分けを実現できるようになったことが分かります。
SNS のイベントソースとなり得る AWS サービスは多数ありますので、今回のアップデートを活かせる構成が無いか考えてみると楽しそうです。
以上、 チバユキ (@batchicchi) がお送りしました。