从 AWS SNS 产生的有效负载中提取类似 JSON 的信息

Extract JSON-like information from payloads produced by AWS SNS

我目前正在实施 SNS 通知作为 S3 存储桶上传和上传处理程序 Lambda 函数之间的中介

信息流应该是这样的:

  1. 将文件上传S3-bucket
  2. 这应该触发 SNS-主题“上传通知”
  3. Lambda-函数(“上传处理程序”)已订阅此 SNS 主题: 根据哪个桶收到文件上传,某个 lambda 函数应由 SNS 通知触发

--> 如何从触发 SNS 通知的事件中获取“S3 存储桶名称”等信息?

我希望有像 lambda 函数这样的可能性,您可以在其中提取信息,例如来自 SNS 生成的 JSON-对象。 如果不存在,我很乐意了解其他方法,但我需要以某种方式从 SNS 中提取此信息 programmatically/automatically 以将其交给步骤 3 中的上传处理程序 lambda 函数。


地形定义块的详细信息:

1. aws_sns_topic_subscription:

resource "aws_sns_topic_subscription" "start_from_upload_topic" {
  topic_arn = var.upload_notification_topic_arn
  protocol  = "lambda"
  endpoint  = module.start_from_upload_handler.arn
}

2。 aws_s3_bucket_notification:

resource "aws_s3_bucket_notification" "start_from_upload_handler" {
  for_each = local.input_bucket_id_map

  bucket = each.value
  topic {
    topic_arn = module.upload_notification.topic_setup.topic_arn
    events    = ["s3:ObjectCreated:*"]
  }
}

3。 SNS 模块“upload_notification”

module "upload_notification" {
  source  = "../../modules/sns_topic"
  name    = "${var.platform_settings.prefix}-upload-notification"
  key_arn = var.platform_settings.logging_settings.logging_key_arn
  allowed_producers = [
    "s3.amazonaws.com",
    "lambda.amazonaws.com",
    "edgelambda.amazonaws.com",
    "events.amazonaws.com",
    "states.amazonaws.com",
  ]
  allowed_consumers = ["lambda.amazonaws.com",
    "edgelambda.amazonaws.com",
    "events.amazonaws.com",
    "states.amazonaws.com",
  ]
  tags = local.tags
}

根据 documentation,S3 存储桶名称(以及区域、事件时间、存储桶 ARN、源 IP 等其他数据)将包含在从 S3 传递到 Lambda 的事件消息中在你的情况下通过 SNS。

Records[0].s3.bucket.name

{  
   "Records":[  
      {  
         "s3":{  
            "bucket":{  
               "name":"bucket-name",
               ...
            },
            ...
         },
         ...
      }
   ]
}

SNS 需要与 Lambda 函数和 S3[=29= 一起设置]-像这样上传(在 terraform 中,本例中不包括 KMS):

resource "aws_lambda_permission" "start_from_upload_sns_topic" {
  statement_id  = "AllowExecutionFromSNStopic"
  action        = "lambda:InvokeFunction"
  function_name = module.start_from_upload_handler.arn
  principal     = "sns.amazonaws.com"
  source_arn    = var.upload_notification_topic_arn
}

resource "aws_s3_bucket_notification" "start_from_upload_handler" {
  for_each = var.input_bucket_name_map

  bucket = each.value
  topic {
    topic_arn = var.upload_notification_topic_arn
    events    = ["s3:ObjectCreated:*"]
  }
}

resource "aws_sns_topic_subscription" "start_from_upload_sns_topic" {
  topic_arn = var.upload_notification_topic_arn
  protocol  = "lambda"
  endpoint  = module.start_from_upload_handler.arn
}

lambda 函数从 SNS 主题接收的 JSON 对象如下所示:

{
    "Records": [
        {
            "EventSource": "aws:sns",
            "EventVersion": "1.0",
            "EventSubscriptionArn": "arn:aws:sns:eu-central-1:...",
            "Sns": {
                "Type": "Notification",
                "MessageId": "...",
                "TopicArn": "arn:aws:sns:eu-central-1:....",
                "Subject": "Amazon S3 Notification",
                "Message": "{\"Records\":[{\"eventVersion\":\"2.1\",\"eventSource\":\"aws:s3\",\"awsRegion\":\"eu-central-1\",\"eventTime\":\"2021-10-27T15:29:38.959Z\",\"eventName\":\"ObjectCreated:Put\",\"userIdentity\":{\"principalId\":\"AWS:...\"},\"requestParameters\":{\"sourceIPAddress\":\"....\"},\"responseElements\":{\"x-amz-request-id\":\"..\",\"x-amz-id-2\":\"...\"},\"s3\":{\"s3SchemaVersion\":\"1.0\",\"configurationId\":\"tf-s3-topic-...\",\"bucket\":{\"name\":\"test-bucket-name\",\"ownerIdentity\":{\"principalId\":\"....\"},\"arn\":\"arn:aws:s3:::test-bucket-name\"},\"object\":{\"key\":\"test_file.json\",\"size\":189,\"eTag\":\"....\",\"versionId\":\"...\",\"sequencer\":\"...\"}}}]}",
                "Timestamp": "2021-10-27T15:29:40.086Z",
                "SignatureVersion": "1",
                "Signature": "...",
                "SigningCertUrl": "https://sns.eu-central-1.amazonaws.com/SimpleNotificationService...",
                "UnsubscribeUrl": "https://sns.eu-central-1.amazonaws.com....",
                "MessageAttributes": {}
            }
        }
    ]
}

我们对传入的 JSON 对象的“消息”感兴趣,这最终看起来确实像@Ermiya Eskandary 在他的回答中提到的指向 S3-notification-JSON-event-structure 的内容:

{
    'Records': [
        {
        's3': {
            'bucket': {
                'arn': 'arn:aws:s3:...',
                'name': 'bucket-name',
                },
            'object': {
                'key': 'upload_file_name.json',
                },
            },
        }
    ]
}

这里的take-away需要注意的是,SNS发出的传入JSON有几个顶层字典关键词,需要被“剥离”或“挖掘”以到达 SNS-Message-body 中的实际 S3-upload-event,它以 string-JSON-format 的形式出现,需要加载进入适当的字典对象。

此外,将 lambda 函数订阅到 SNS 主题并允许 SNS 主题依次调用所述 lambda 函数是最重要的。