The setup of the AWS environment is detailed in the Direktiv documentation page. However, this is an example of how the events and data received from AWS look and how the workflow can be configured to start based on an event.
Workflow configuration
The below is a snippet of the workflow configuration:
start: type: event state: check-event event: type: "AWS API Call via CloudTrail" states: # # We need to check that the event is a "TerminateInstances" event for AWS # - id: check-event log: jq(.) type: switch defaultTransition: event-filter-failed conditions: - condition: 'jq(."AWS API Call via CloudTrail".data.detail.eventName == "TerminateInstances")' transition: get-instance-details-aws transform: jq(."AWS API Call via CloudTrail".data) - id: event-filter-failed log: jq(.) type: noop - id: get-instance-details-aws log: jq(.) type: noop
The "start" definition instructs Direktiv to only start this workflow if an event from AWS called "AWS API Call via CloudTrail" is received.
In this case we didn't apply any filter on the AWS EventBridge configuration. So the first state in the workflow will check whether the event matches a "TerminateInstances" event (notifying an EC2 instances is being terminated).
AWS CloudEvent details
Let's look at the structure of the CloudEvent received from AWS:
{ "AWS API Call via CloudTrail": { "data": { "account": "338328518639", "detail": { "awsRegion": "us-west-1", "eventCategory": "Management", "eventID": "73fe93e6-8302-40b7-9848-efcb7585596b", "eventName": "TerminateInstances", "eventSource": "ec2.amazonaws.com", "eventTime": "2023-02-03T03:16:58Z", "eventType": "AwsApiCall", "eventVersion": "1.08", "managementEvent": true, "readOnly": false, "recipientAccountId": "338328518639", "requestID": "d286b9f3-e4fe-4712-94a3-5198db2cbce3", "requestParameters": { "instancesSet": { "items": [ { "instanceId": "i-0772f323027e52c97" } ] } }, "responseElements": { "instancesSet": { "items": [ { "currentState": { "code": 32, "name": "shutting-down" }, "instanceId": "i-0772f323027e52c97", "previousState": { "code": 16, "name": "running" } } ] }, "requestId": "d286b9f3-e4fe-4712-94a3-5198db2cbce3" }, "sessionCredentialFromConsole": "true", "sourceIPAddress": "67.188.77.77", "userAgent": "AWS Internal", "userIdentity": { "accessKeyId": "ASIAU5RPTP7XTA4AZV4X", "accountId": "338328518639", "arn": "arn:aws:iam::338328518639:root", "principalId": "338328518639", "sessionContext": { "attributes": { "creationDate": "2023-02-03T03:13:06Z", "mfaAuthenticated": "false" }, "sessionIssuer": {}, "webIdFederationData": {} }, "type": "Root" } }, "detail-type": "AWS API Call via CloudTrail", "id": "40f83262-7a58-4e20-8633-49829e205eca", "region": "us-west-1", "resources": [], "source": "aws.ec2", "time": "2023-02-03T03:16:58Z", "version": "0" }, "id": "40f83262-7a58-4e20-8633-49829e205eca", "source": "aws.ec2", "specversion": "1.0", "subject": "aws.ec2", "time": "2023-02-03T03:16:58Z", "type": "AWS API Call via CloudTrail" } }
The structure follows the same convention as the CloudEvent specification. The top-level JSON attribute in the object is the event name ("AWS API Call via CloudTrail").
What follows is the "data" object - which contains the payload from AWS and all the information needed for machine operations in the subsequent workflow steps.
To following statement is a condition match using jq to check whether it is a specific type of event:
condition: 'jq(."AWS API Call via CloudTrail".data.detail.eventName == "TerminateInstances")'
The next jq statement removes the top-level object and only keeps the "data" object
transform: jq(."AWS API Call via CloudTrail".data)
The transformed output is printed using a log statement in the noop state called get-instance-details-aws and produces the following input to the state:
{ "account": "338328518639", "detail": { "awsRegion": "us-west-1", "eventCategory": "Management", "eventID": "73fe93e6-8302-40b7-9848-efcb7585596b", "eventName": "TerminateInstances", "eventSource": "ec2.amazonaws.com", "eventTime": "2023-02-03T03:16:58Z", "eventType": "AwsApiCall", "eventVersion": "1.08", "managementEvent": true, "readOnly": false, "recipientAccountId": "338328518639", "requestID": "d286b9f3-e4fe-4712-94a3-5198db2cbce3", "requestParameters": { "instancesSet": { "items": [ { "instanceId": "i-0772f323027e52c97" } ] } }, "responseElements": { "instancesSet": { "items": [ { "currentState": { "code": 32, "name": "shutting-down" }, "instanceId": "i-0772f323027e52c97", "previousState": { "code": 16, "name": "running" } } ] }, "requestId": "d286b9f3-e4fe-4712-94a3-5198db2cbce3" }, "sessionCredentialFromConsole": "true", "sourceIPAddress": "67.188.77.77", "userAgent": "AWS Internal", "userIdentity": { "accessKeyId": "ASIAU5RPTP7XTA4AZV4X", "accountId": "338328518639", "arn": "arn:aws:iam::338328518639:root", "principalId": "338328518639", "sessionContext": { "attributes": { "creationDate": "2023-02-03T03:13:06Z", "mfaAuthenticated": "false" }, "sessionIssuer": {}, "webIdFederationData": {} }, "type": "Root" } }, "detail-type": "AWS API Call via CloudTrail", "id": "40f83262-7a58-4e20-8633-49829e205eca", "region": "us-west-1", "resources": [], "source": "aws.ec2", "time": "2023-02-03T03:16:58Z", "version": "0" }
AWS Filters
An example of an AWS event pattern is shown below:
{ "source": ["aws.ec2"], "detail-type": ["AWS API Call via CloudTrail"], "detail": { "eventSource": ["ec2.amazonaws.com"], "eventName": ["TerminateInstances"] } }
AWS Input Transformer
The input transformer (to create the CloudEvent sent to Direktiv) is shown below:
Input path
{ "id": "$.id", "source": "$.source", "state": "$.detail.state", "subject": "$.source", "time": "$.time", "type": "$.detail-type" }
Input template
{ "specversion":"1.0", "id":"<id>", "source":"<source>", "type":"<type>", "subject":"<subject>", "time":"<time>", "data":"<aws.events.event.json>" }
Was this article helpful?
That’s Great!
Thank you for your feedback
Sorry! We couldn't be helpful
Thank you for your feedback
Feedback sent
We appreciate your effort and will try to fix the article