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.jsonof 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:upsertordeletethe 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, fordeleteactions, 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 
EventBusNameproperty value isdefault, as this is the bus that gets events from various AWS services automatically: 
Properties:
  EventBusName: default
  ...
- The 
EventPatternproperty 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,CreateFunctionandDeleteFunctionevents: 
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 
Targetsproperty 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 
InputTransformerkey in theTargetsproperty 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 
InputPathsMapkey inInputTransformerdefines which fields to extract from the event. It makes use ofJSONPathsyntax 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 
InputTemplatekey inInputTransformerdefines 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 
awsRegionfrom the event; - A JQ query to figure out the action (
upsertordeletethe 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