Pushing CloudTrail logs to ElasticSearch via SQS and Lambda

0

I am ingesting my CloudTrail logs into my self managed ElasticSearch cluster today via CloudWatch an a Lambda subscription. I've noticed that the execution is basically a 1:1 for my messages though, and I would like to batch these messages rather than calling them all immediately right as they are coming in.

With that, I have the following questions: -Is there a method to batch throttle Lambda for this that I'm not aware of? I see this: https://docs.aws.amazon.com/lambda/latest/dg/API_CreateEventSourceMapping.html#SSS-CreateEventSourceMapping-request-BatchSize But it appears to pertain to the maximum size before it fires. I would like the opposite, for it to wait until I have ~10

-Would adding SQS be a possible remedy here? Could SQS replace CloudWatch in my architecture and give me some more control over how quickly the Lambda's are being execute and how they might batch before sending?

2 Answers
2
Accepted Answer

When invoking a Lambda function from a CloudWatch Logs subscription you cannot directly control messaging batching but there are a few options.

Option 1: You could configure reserved concurrency to limit the number of concurrent instances of the function that can be invoked. Whether or not this achieves your goal depends on the average request duration and requests per second, read more about Lambda concurrency. If requests from CloudWatch Logs are throttled, the events are returned to a queue and retried for up to 6 hours (by default); you can configure a SQS queue as a dead-letter queue to hold failed events. The Lambda function could then be invoked by SQS. This could be a bit tricky to configure properly without A) creating a large backlog of unprocessed events in SQS if concurrency is always used by the CloudWatch logs invocation, or B) creating a separate function to process the SQS queue

Option 2: You could create a dummy Lambda function with reserved concurrency set to 0 and the failure destination/dead-letter queue set to SQS. CloudWatch logs would fail to invoke this dummy function (no concurrency available) so the event data would be sent to SQS without retries. The "real" Lambda function could then be invoked by SQS. In this scenario there are several options to control batching and concurrency including batch size (number of records to send to the function from SQS), batch window (amount of time to gather records before invoking the function), and maximum concurrency (maximum number of concurrent functions that SQS can invoke), see Using Lambda with Amazon SQS for more details.

Option 3: If you're only sending CloudTrail logs to CloudWatch for the Lambda subscription filter you could eliminate CloudWatch and use SNS notifications for CloudTrail with a SQS queue subscribed to the SNS topic. As CloudTrail writes logs files to the S3 bucket, a notification is sent to SNS — the notification includes the S3 bucket name and object key(s) of the log file(s). SNS then sends the message to the subscribed SQS queue; SQS would then trigger the Lambda function. In this scenario there are several options to control batching and concurrency including batch size (number of records to send to the function from SQS), batch window (amount of time to gather records before invoking the function), and maximum concurrency (maximum number of concurrent functions that SQS can invoke), see Using Lambda with Amazon SQS for more details. It's important to note that in this scenario, you'd have to retrieve the files from S3 then decompress and process them. Also, each SQS message could contain multiple files and each file could multiple CloudTrail log records.

AWS
answered 10 months ago
profile picture
EXPERT
reviewed 10 months ago
1

One option to consider is using Kinesis Firehose that can batch the messages and deliver it to S3 or OpenSearch directly(but you are using a self managed Elastic cluster). In Firehose, you can control the buffer hint so it waits until certain size or time before writing it to the destination. In this case, you can easily hookup a Lambda to S3 to load every time new batch arrives. The solution would be like this:

CloudWatch->Kinesis Firehose [Buffer]->S3->Lambda->Elastic Cluster

You can see some details here :

AWS
answered 10 months ago
profile picture
EXPERT
reviewed 10 months ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.

Guidelines for Answering Questions