Event-Based Updates
Our AWS integration allows you to trigger a sync of your AWS resources with Port based on real-time events (in addition to the standard scheduled sync). As a result, your software catalog will be updated shortly after a resource is created, updated or deleted.
How it works
Many AWS services emit events to AWS EventBridge service, to the account’s default event bus. Furthermore, the AWS CloudTrail service automatically emits events for API calls from most AWS services.
A user can create an AWS EventBridge rule to consume and transform particular events, and send them to a target, such as an AWS SQS Queue.
The AWS exporter application creates an SQS Queue as part of its installation process, and configures it as an event source for the exporter's lambda.
This allows you to set up an event rule, that consumes any events from the bus and sends them to the AWS exporter's queue.
Each event will have to be transformed as part of the event rule, before reaching the queue, to suit the exporter's lambda expected event structure. The transformation goal is to map an event to a single AWS resource, that the exporter can handle.
The events in the queue are consumed automatically by the exporter's lambda, that will sync the updated state of the relevant AWS resources with Port.
Input structure for a single event
The AWS exporter's lambda accepts JSON events with the following structure:
resource_type
- a hardcoded string representing the AWS resource type that is configured in theconfig.json
of the AWS Exporter;region
- A JQ query to get the region from the event, usually the value will be"\"<awsRegion>\""
;action
(Optional, defaults toupsert
) - A JQ query to define the desired action:upsert
ordelete
the Port entity of the matching resource. Will usually be based on the event name, like in the example below;identifier
- A JQ query to calculate the resource identifier. In case the action isupsert
, it should be the AWS Cloud Control API resource identifier. Otherwise, fordelete
actions, it should be the Port entity identifier. It is recommended to use a Port entity identifier that is identical to the Cloud Control API resource identifier (when applicable), this will make it possible to use the same event rule both for upsert and delete events (while also saving the need for complex JQ filtering patterns).
An example for such a JSON event:
{
"requestFunctionName": "<requestFunctionName>",
"responseFunctionName": "<responseFunctionName>",
"eventName": "<eventName>",
"resource_type": "AWS::Lambda::Function",
"region": "\"<awsRegion>\"",
"action": "if .eventName | startswith(\"Delete\") then \"delete\" else \"upsert\" end",
"identifier": "if .responseFunctionName != \"\" then .responseFunctionName else .requestFunctionName end"
}
To get the identifier formula of a specific resource type, like AWS::Lambda::Function
, you can use the following command:
aws cloudformation describe-type --type RESOURCE --type-name AWS::Lambda::Function --query "Schema" | jq 'fromjson | .primaryIdentifier | join("|")'
# Result
"/properties/FunctionName"
Here you can see that the identifier of a lambda function is the function name.
Another example, for the AWS::ECS::Service
resource type:
aws cloudformation describe-type --type RESOURCE --type-name AWS::ECS::Service --query "Schema" | jq 'fromjson | .primaryIdentifier | join("|")'
# Result
"/properties/ServiceArn|/properties/Cluster"
Here you have two properties in the formula: /properties/ServiceArn
and /properties/Cluster
. When there are multiple properties, the values in the identifier are separated by |
.
For more information, read here.
Event rule
Definition
The event rule is how you specify the exact events you want to consume, and define the target to send the modified event to (including the transformation to the input).
Before diving deep into the event rule properties, here is a complete example of a CloudFormation YAML template
to manage an event rule, for the AWS Exporter:
AWSTemplateFormatVersion: '2010-09-09'
Description: The template used to create event rules for the Port AWS exporter.
Parameters:
PortAWSExporterStackName:
Description: Name of the Port AWS exporter stack name
Type: String
MinLength: 1
MaxLength: 255
AllowedPattern: '^[a-zA-Z][-a-zA-Z0-9]*$'
Default: serverlessrepo-port-aws-exporter
Resources:
EventRule0:
Type: AWS::Events::Rule
Properties:
EventBusName: default
EventPattern:
source:
- aws.lambda
detail-type:
- AWS API Call via CloudTrail
detail:
eventSource:
- lambda.amazonaws.com
eventName:
- prefix: UpdateFunctionConfiguration
- prefix: CreateFunction
- prefix: DeleteFunction
Name: port-aws-exporter-sync-lambda-trails
State: ENABLED
Targets:
- Id: 'PortAWSExporterEventsQueue'
Arn:
{
'Fn::ImportValue':
{ 'Fn::Sub': '${PortAWSExporterStackName}-EventsQueueARN' },
}
InputTransformer:
InputPathsMap:
awsRegion: $.detail.awsRegion
eventName: $.detail.eventName
requestFunctionName: $.detail.requestParameters.functionName
responseFunctionName: $.detail.responseElements.functionName
InputTemplate: |-
{
"resource_type": "AWS::Lambda::Function",
"requestFunctionName": "<requestFunctionName>",
"responseFunctionName": "<responseFunctionName>",
"eventName": "<eventName>",
"region": "\"<awsRegion>\"",
"identifier": "if .responseFunctionName != \"\" then .responseFunctionName else .requestFunctionName end",
"action": "if .eventName | startswith(\"Delete\") then \"delete\" else \"upsert\" end"
}
This example of CloudFormation stack can be used to act on changes of lambda functions.
Moreover, it includes a parameter called PortAWSExporterStackName
, that refers to the main exporter's stack name. That way, we can send the events to the existing exporter's events queue, to sync relevant AWS resources.
Properties
Let's review the properties of the event rule resource from above.
- The
EventBusName
property value isdefault
, as this is the bus that gets events from various AWS services automatically:
Properties:
EventBusName: default
...
- The
EventPattern
property defines which events to consume, including which event sources to process, which filters to apply based on the event structure. Here, we define the event pattern to consume Cloudtrail API calls, sourced from the lambda service; On top of that, we filter only theUpdateFunctionConfiguration
,CreateFunction
andDeleteFunction
events:
Properties:
EventBusName: default
EventPattern:
source:
- aws.lambda
detail-type:
- AWS API Call via CloudTrail
detail:
eventSource:
- lambda.amazonaws.com
eventName:
- prefix: UpdateFunctionConfiguration
- prefix: CreateFunction
- prefix: DeleteFunction
- The
Targets
property defines the targets of the produced events. For the AWS exporter, we want to configure its own event queue as the target:
Properties:
...
Targets:
- Id: "PortAWSExporterEventsQueue"
Arn: { "Fn::ImportValue" : {"Fn::Sub": "${PortAWSExporterStackName}-EventsQueueARN" } }
...
- The
InputTransformer
key in theTargets
property defines the transformation that will be applied to the event, before sending it to the target queue;
Properties:
...
Targets:
- Id: "PortAWSExporterEventsQueue"
Arn: { "Fn::ImportValue" : {"Fn::Sub": "${PortAWSExporterStackName}-EventsQueueARN" } }
InputTransformer:
...
- The
InputPathsMap
key inInputTransformer
defines which fields to extract from the event. It makes use ofJSONPath
syntax to configure the extraction:
Properties:
...
Targets:
- Id: "PortAWSExporterEventsQueue"
Arn: { "Fn::ImportValue" : {"Fn::Sub": "${PortAWSExporterStackName}-EventsQueueARN" } }
InputTransformer:
InputPathsMap:
awsRegion: $.detail.awsRegion
eventName: $.detail.eventName
requestFunctionName: $.detail.requestParameters.functionName
responseFunctionName: $.detail.responseElements.functionName
...
For instance, the event sent to the EventBridge bus for the CreateFunction
lambda API call has the following structure:
{
...
"detail": {
...
"eventSource": "lambda.amazonaws.com",
"eventName": "CreateFunction20150331",
"awsRegion": "eu-west-1",
...
"requestParameters": {
"functionName": "test-function",
...
},
"responseElements": {
"functionName": "test-function",
...
},
...
}
}
The InputPathsMap
in the example below will extract only the awsRegion
, eventName
, and functionName
from the API request and response.
- The
InputTemplate
key inInputTransformer
defines a template of the final input that will be sent to the target queue, in the format the exporter's lambda expects. The template is rendered using the values from theInputPathsMap
:
Properties:
...
Targets:
- Id: "PortAWSExporterEventsQueue"
Arn: { "Fn::ImportValue" : {"Fn::Sub": "${PortAWSExporterStackName}-EventsQueueARN" } }
InputTransformer:
InputPathsMap:
awsRegion: $.detail.awsRegion
eventName: $.detail.eventName
requestFunctionName: $.detail.requestParameters.functionName
responseFunctionName: $.detail.responseElements.functionName
InputTemplate: |-
{
"resource_type": "AWS::Lambda::Function",
"requestFunctionName": "<requestFunctionName>",
"responseFunctionName": "<responseFunctionName>",
"eventName": "<eventName>",
"region": "\"<awsRegion>\"",
"identifier": "if .responseFunctionName != \"\" then .responseFunctionName else .requestFunctionName end",
"action": "if .eventName | startswith(\"Delete\") then \"delete\" else \"upsert\" end"
}
Here, the InputTemplate
takes the information extracted in the InputPathsMap
, and constructs a message that will be sent to the SQS queue and consumed by the exporter’s lambda.
The message includes:
- The hardcoded resource type (
AWS::Lambda::Function
); - The
awsRegion
from the event; - A JQ query to figure out the action (
upsert
ordelete
the Port entity), based on theeventName
; - A JQ query to calculate the identifier, based on the function name from the API response or request.
To read more about input transformer in EventBridge, click here.
Next steps
Examples
- Refer to the examples page for practical configurations and their corresponding blueprint definitions.
- Refer to the Event Bridge rule Terraform example