User Tools

Site Tools


bloglike:2021-07

Issue 2021 - July

AWS EventBridge events, Rules, Input Transformation and CloudWatch Logs as a target

I'm probably daft since it took me rather considerable time until I figured this one out. If you want to store events from AWS service as CloudWatch Logs and don't need to perform any transformations then you're golden. It works out of the box, no problem(almost). But what if you want to either strip some (sensitive) data or modify input and still use CloudWatch Logs as output? Then you are in world of hurt.

This feature and its idiosyncrasies isn't exactly documented and demonstrated in examples/tutorials. You will most likely start with storing matched event(no transformation) into CloudWatch Logs to see what is what. Then you will find some example be it from the docs or some web site, copy-paste it and start hacking away. Here comes the first problem. Input Template must be JSON, however which JSON, you're never told. I've tried to guess, a lot. Later on(actually much much later) I got the idea to check boto3 documentation and API call PutLogEvents and then I somehow found a note in docs:

which, to be honest, doesn't make sense to me. What is version-id? You mean version from the original event? API version? And where do I put my message? What??? Of course, relation to anything on that page is 0. Nope, don't see it. I'm daft! Even answer at StackOverflow was more useful than the official documentation! But it was some progress and in the right direction too. Originally, I thought that some keys are reserved, I'm creating loop or time format is wrong and that's why I get FailedInvocations. Wrong is correct, because it seems that expected JSON is:

{
  "timestamp": "2021-07-15T08:43:20Z",
  "message": "Hello world!"
}

And that's it. As for timestamp filed, you can either use eg. time from the original event or one of pre-defined variables aws.events.event.ingestion-time. Note that I've originally used this predefined variable, because boto3 documentation says that U*nix timestamp is expected and I had none, however latter works as well.

As for message field, it seems that string is expected, no exceptions. If you want or need JSON in CloudWatch Logs, it seems that you must escape it by yourself in Input Template like so:

{"timestamp": <time>,"message":"{\"eventTime\":\"<time>\",\"awsRegion\":\"<awsregion>\",[...],\"timeoutSeconds\":\"<timeout>\"}"}

Meh! I haven't found another way to do it nor how to deal with nested data(lists and dicts), eg. {“resources”: [“arn:aws:…”]}, therefore it seems that you must do without. All other fields I've tried to smuggle in have been stripped away, at least in my case. If you turn message into dict, then there will be { in CloudWatch Logs. Note that if escaped JSON is invalid, the result will be a failed invocation and data won't make it into CloudWatch Logs. In theory, you can send output into SQS dead-letter queue when it cannot be delivered, but I haven't tested it. I should've tested it, though, because I bet it'd make debugging a lot easier since I couldn't find related logs anywhere!

I guess all of this could've been done much faster and less painful with a simple Lambda function, but then you have code to maintain and deploy.

Couple more things. Beware of this bug.

Note: CloudWatch Events currently supports a maximum of 10 variables in input path maps. To extract more than 10 variables, pass the entire event to an AWS Lambda function for parsing.

Well, I able to parse 13 variables. Lucky me, I guess. 8-) Or maybe not, because when I've tried to put this into terraform, then:

Error: expected number of items in input_transformer.0.input_paths to be less than or equal to 10, got 16

To that I say, bollocks! It works no-problem from the console, so why would you …?! Geee, thanks! :-\ As I've said, use Lambda function, if you can. Yeah, anything but CloudWatch Logs.

You can filter which events get processed like so:

{
  "source": [
    "aws.batch"
  ],
  "detail-type": [
    "Batch Job State Change"
  ],
  "detail": {
    "status": [
      "FAILED",
      "SUCCEEDED"
    ]
  }
}

This means only FAILED and SUCCEEDED Batch Job State changes will be processed and forwarded to rule's target(output).

Zdenek Styblik 2021/07/20 17:18

bloglike/2021-07.txt · Last modified: 2021/07/21 09:29 by stybla