基于事件的更新
通过我们的 AWS 集成,您可以根据实时事件(除标准的计划同步外)触发 AWS 资源与 Port 的同步。 因此,在创建、更新或删除资源后,您的软件目录将很快得到更新。
工作原理
许多 AWS 服务都会向AWS EventBridge 服务和账户的默认事件总线发送事件。此外,AWS CloudTrail 服务还会自动为来自大多数 AWS 服务的 API 调用发送事件。
用户可以创建一个AWS EventBridge rule ,用于消费和转换特定事件,并将其发送至目标,如AWS SQS Queue 。
The AWS exporter application 在安装过程中会创建一个 SQS 队列,并将其配置为输出程序 lambda 的事件源。
这样,您就可以设置一个事件规则,该规则会消耗总线上的任何事件,并将它们发送到 AWS 输出程序的队列中。
在到达队列之前,每个事件都必须作为事件规则的一部分进行转换,以适应出口程序的 lambda 预期事件结构。 转换的目标是将事件映射到出口程序可以处理的单个 AWS 资源。
队列中的事件会被出口程序的 lambda 自动消耗,该 lambda 会将相关 AWS 资源的更新状态与 Port 同步。
###单一事件的输入结构
AWS 输出程序的 lambda 接受具有以下结构的 JSON 事件:
- resource_type- 一个硬编码字符串,代表在 AWS Exporter 的- config.json中配置的 AWS 资源类型;
- region- 从事件中获取区域的 JQ 查询,通常值为- "\"<awsRegion>\"";
- action(可选,默认为upsert`)- 用于定义所需操作的 JQ 查询: "upsert "或 "delete "匹配资源的 Port 实体。通常基于事件名称,如下面的示例;
- identifier` - 用于计算资源标识符的 JQ 查询。如果操作是 "upsert",则应是 AWS Cloud Control API 资源标识符。否则,对于 "删除 "操作,应使用Port 实体标识符。建议使用与云控制 API 资源标识符相同的Port实体标识符(如适用),这样就可以对上载和删除事件使用相同的事件规则(同时也无需使用复杂的 JQ 过滤模式)。
此类 JSON 事件的示例
{
  "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"
}
AWS::Lambda::Function)的标识符公式,可以使用以下命令:aws cloudformation describe-type --type RESOURCE --type-name AWS::Lambda::Function --query "Schema" | jq 'fromjson | .primaryIdentifier | join("|")'
# Result
"/properties/FunctionName"
从这里可以看出,lambda 函数的标识符就是函数名。
另一个例子是 AWS::ECS::Service 资源类型:
aws cloudformation describe-type --type RESOURCE --type-name AWS::ECS::Service --query "Schema" | jq 'fromjson | .primaryIdentifier | join("|")'
# Result
"/properties/ServiceArn|/properties/Cluster"
这里的公式中有两个属性: /properties/ServiceArn 和/properties/Cluster。 当有多个属性时,标识符中的值用|分隔。
更多信息,请阅读here 。
活动规则
定义
通过事件规则,您可以指定要消费的确切事件,并定义将修改后的事件发送到的目标(包括对输入的转换)。
在深入 diveevent rule properties 之前,这里有一个用于管理 AWS 输出程序事件规则的 "CloudFormation YAML 模板 "的完整示例:
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"
              }
Properties
让我们回顾一下上述事件规则资源的属性。
- EventBusName "属性值为 "default",因为这是自动从各种 AWS 服务获取事件的总线:
Properties:
  EventBusName: default
  ...
- EventPattern "属性定义了要消费的事件,包括要处理的事件源、根据事件结构应用的过滤器。在此,我们定义了一种事件模式,以消费来自 lambda 服务的 Cloudtrail API 调用;在此基础上,我们仅过滤了 UpdateFunctionConfiguration、CreateFunction和DeleteFunction事件:
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
- 目标 "属性定义了生成事件的目标。对于 AWS 输出程序,我们希望将其自身的事件队列配置为目标:
Properties:
  ...
  Targets:
    - Id: "PortAWSExporterEventsQueue"
      Arn: { "Fn::ImportValue" : {"Fn::Sub": "${PortAWSExporterStackName}-EventsQueueARN" } }
      ...
- 目标 "属性中的 "InputTransformer "键定义了在将事件发送到目标队列之前将应用于事件的转换;
Properties:
  ...
  Targets:
    - Id: "PortAWSExporterEventsQueue"
      Arn: { "Fn::ImportValue" : {"Fn::Sub": "${PortAWSExporterStackName}-EventsQueueARN" } }
      InputTransformer:
        ...
- 输入转换器 "中的 "InputPathsMap "键定义了要从事件中提取的字段。它被用于JSONPath语法来配置提取:
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
        ...
例如,为 CreateFunction lambda API 调用发送到 EventBridge 总线的事件具有以下结构:
{
  ...
  "detail": {
    ...
    "eventSource": "lambda.amazonaws.com",
    "eventName": "CreateFunction20150331",
    "awsRegion": "eu-west-1",
    ...
    "requestParameters": {
        "functionName": "test-function",
        ...
    },
    "responseElements": {
        "functionName": "test-function",
        ...
    },
    ...
  }
}
下面示例中的 InputPathsMap 将只从 API 请求和响应中提取 awsRegion, eventName 和 functionName。
- InputTransformer中的InputTemplate键定义了将发送到目标队列的最终输入的模板,格式为输出器的 lambda[expects](#input-structure-for-a-single-event) 。该模板会被用于InputPathsMap` 中的 Values 来渲染:
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"
          }
在这里,"InputTemplate"(输入模板)接收从 "InputPathsMap"(输入路径图)中提取的信息,并构建一条消息,该消息将被发送到 SQS 队列,并被出口程序的 lambda 消耗。 消息包括:
- 硬编码资源类型(AWS::Lambda::Function);
- 事件中的 awsRegion字段;
- JQ 查询,根据事件名称确定操作("上载 "或 "删除 "Port实体);
- 根据 API 响应或请求中的函数名计算标识符的 JQ 查询。
下一步
示例
- 有关实用配置及其相应蓝图定义,请参阅examples 页面。
- 参考事件桥规则Terraform example