@@ -204,6 +204,87 @@ def format_guardduty_finding(message: Dict[str, Any], region: str) -> Dict[str,
204
204
"text" : f"AWS GuardDuty Finding - { detail .get ('title' )} " ,
205
205
}
206
206
207
+ def format_security_announcements (message : Dict [str , Any ]) -> Dict [str , Any ]:
208
+ """
209
+ Format GuardDuty & SecurityHub announcements into Slack message format
210
+
211
+ :params message: SNS message body containing the announcements
212
+ :returns: formatted Slack message payload
213
+ """
214
+
215
+ if "findingDetails" in message :
216
+ detail = message ["findingDetails" ][0 ]
217
+
218
+ return {
219
+ "color" : "#00FF00" ,
220
+ "fallback" : "GuardDuty Announcement - New/Updated Findings" ,
221
+ "fields" : [
222
+ {
223
+ "title" : "Finding Type" ,
224
+ "value" : f"`{ detail ['findingType' ]} `" ,
225
+ "short" : False ,
226
+ },
227
+ {
228
+ "title" : "Description" ,
229
+ "value" : f"`{ detail ['findingDescription' ]} `" ,
230
+ "short" : False ,
231
+ },
232
+ {
233
+ "title" : "Link" ,
234
+ "value" : f"`{ detail ['link' ]} `" ,
235
+ "short" : False ,
236
+ },
237
+ ],
238
+ "text" : "AWS GuardDuty Announcement" ,
239
+ }
240
+
241
+ elif "featureDetails" in message :
242
+ detail = message ["featureDetails" ][0 ]
243
+
244
+ return {
245
+ "color" : "#00FF00" ,
246
+ "fallback" : "GuardDuty Announcement - New Feature" ,
247
+ "fields" : [
248
+ {
249
+ "title" : "Description" ,
250
+ "value" : f"`{ detail ['featureDescription' ]} `" ,
251
+ "short" : False ,
252
+ },
253
+ {
254
+ "title" : "Link" ,
255
+ "value" : f"`{ detail ['featureLink' ]} `" ,
256
+ "short" : False ,
257
+ },
258
+ ],
259
+ "text" : "AWS GuardDuty Announcement" ,
260
+ }
261
+
262
+ elif "AnnouncementType" in message and "Title" in message :
263
+ return {
264
+ "color" : "#00FF00" ,
265
+ "fallback" : "SecurityHub Announcement" ,
266
+ "fields" : [
267
+ {
268
+ "title" : "Title" ,
269
+ "value" : f"`{ message ['Title' ]} `" ,
270
+ "short" : False ,
271
+ },
272
+ {
273
+ "title" : "Type" ,
274
+ "value" : f"`{ message ['AnnouncementType' ]} `" ,
275
+ "short" : False ,
276
+ },
277
+ {
278
+ "title" : "Description" ,
279
+ "value" : f"`{ message ['Description' ]} `" ,
280
+ "short" : False ,
281
+ },
282
+ ],
283
+ "text" : "AWS SecurityHub Announcement" ,
284
+ }
285
+
286
+ else :
287
+ return False
207
288
208
289
class AwsHealthCategory (Enum ):
209
290
"""Maps AWS Health eventTypeCategory to Slack message format color
@@ -360,6 +441,10 @@ def get_slack_message_payload(
360
441
elif "attachments" in message or "text" in message :
361
442
payload = {** payload , ** message }
362
443
444
+ elif "findingDetails" in message or "featureDetails" in message or "AnnouncementType" in message :
445
+ notification = format_security_announcements (message = message )
446
+ attachment = notification
447
+
363
448
else :
364
449
attachment = format_default (message = message , subject = subject )
365
450
@@ -406,7 +491,12 @@ def lambda_handler(event: Dict[str, Any], context: Dict[str, Any]) -> str:
406
491
407
492
for record in event ["Records" ]:
408
493
sns = record ["Sns" ]
409
- subject = sns ["Subject" ]
494
+
495
+ if "Subject" in sns :
496
+ subject = sns ["Subject" ]
497
+ else :
498
+ subject = ""
499
+
410
500
message = sns ["Message" ]
411
501
region = sns ["TopicArn" ].split (":" )[3 ]
412
502
0 commit comments