从 AWS SNS 产生的有效负载中提取类似 JSON 的信息
Extract JSON-like information from payloads produced by AWS SNS
我目前正在实施 SNS 通知作为 S3 存储桶上传和上传处理程序 Lambda 函数之间的中介。
信息流应该是这样的:
- 将文件上传到S3-bucket
- 这应该触发 SNS-主题“上传通知”
- 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 函数是最重要的。
我目前正在实施 SNS 通知作为 S3 存储桶上传和上传处理程序 Lambda 函数之间的中介。
信息流应该是这样的:
- 将文件上传到S3-bucket
- 这应该触发 SNS-主题“上传通知”
- 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 函数是最重要的。