amazon-web-services - 重写 Api Gateway websocket API 私有(private) http 与 ALB 集成中的目标路径

标签 amazon-web-services websocket aws-cloudformation aws-api-gateway aws-application-load-balancer

我有一个包含 ECS 集群的私有(private)子网,其中没有公共(public) IP 地址的服务在应用程序负载均衡器后面运行。

应用程序负载均衡器也是私有(private)的。

我有一个使用 VPC 链接通过 HTTP 与该 ALB 集成的 API 网关(请参阅 this )。

我所有的微服务都像这样完美地工作。

但现在我需要添加对 websockets 的支持,并且需要创建一个协议(protocol)类型为 WEBSOCKET 的 API 网关,该网关具有 HTTP 集成的路由,以便 websocket 路由 $connect, $disconnectsendmessage 被转换为 HTTP 请求。

我遇到的问题是,为了使用私有(private)集成,我必须指定 ALB 的 Arn,并且无法指定 URL(请参阅 this )。关于IntegrationUri:

For an HTTP API private integration, specify the ARN of an Application Load Balancer listener, Network Load Balancer listener, or AWS Cloud Map service. If you specify the ARN of an AWS Cloud Map service, API Gateway uses DiscoverInstances to identify resources. You can use query parameters to target specific resources. To learn more, see DiscoverInstances. For private integrations, all resources must be owned by the same AWS account.

因此,在 IntegrationUri 中,我不必指定诸如 https://mypublicdomain.com/My.Service/connect 之类的内容,这样我就可以轻松地将服务路径添加为 URL 的一部分,而是被迫添加应用程序负载均衡器 ARN,arn:aws:myalb...

因此我无法使用 URL 路径来将 Websocket 路由与 ALB 背后的特定服务集成

换句话说,如何将 API Gateway 上的 Websocket 路由与私有(private) ALB 后面的特定服务关联起来?

PS:我曾考虑过使用一些具有路径模式条件的监听器规则,以捕获所有前往 ALB 根 / 的流量到所需的服务,但这远非理想,因为我想路由基于更明显的东西。


CloudFormation 示例:

Resources:
  websocketApiGateway:
    Type: AWS::ApiGatewayV2::Api
    Properties:
      Name: websocket-gateway
      Description: Api Gateway for websocket
      ProtocolType: WEBSOCKET
      DisableExecuteApiEndpoint: false
      RouteSelectionExpression: $request.body.action

  connectRoute:
    Type: AWS::ApiGatewayV2::Route
    Properties:
      ApiId: !Ref websocketApiGateway
      RouteKey: $connect
      AuthorizationType: NONE
      OperationName: ConnectRoute
      RouteResponseSelectionExpression: $default
      Target: !Join
        - /
        - - integrations
          - !Ref connectIntegration

  connectIntegration:
    Type: AWS::ApiGatewayV2::Integration
    Properties:
      ApiId: !Ref websocketApiGateway
      Description: Websocket $connect integration
      IntegrationType: HTTP_PROXY
      IntegrationMethod: POST
      IntegrationUri: # I cannot use something like https://mypublicdomain.com/My.Service/connect
        Fn::ImportValue: !Sub my-alb-http-listener-id
      RequestParameters:
        "integration.request.header.domainName": "context.domainName"
        "integration.request.header.stage": "context.stage"
        "integration.request.header.connectionId": "context.connectionId"
      PayloadFormatVersion: 1.0

  connectRouteResponse:
    Type: AWS::ApiGatewayV2::RouteResponse
    Properties:
      ApiId: !Ref websocketApiGateway
      RouteId: !Ref connectRoute
      RouteResponseKey: $default

更新1:写完我想的问题后..如果我无法根据URI进行路由,也许我可以根据我可以设置的一些http header 在ALB http监听器上进行路由在 websocket 的 api 网关集成中。因此,我将保留它作为解决方法,以防我找不到重写 url 路径的方法

更新2:这个问题类似,但是答案不够详细Rewrite destination path in api gateway integration request

最佳答案

我并没有真正解决这个问题,但我有一个解决方法。

在 API 网关级别,Websocket 请求将转换为 HTTP 请求返回 API 网关。这并不理想,因为最好将 http 请求内部发送到集成,但它可以工作,并且希望它不会增加太多延迟,因为目的地是完全相同的 api 网关。我还添加了一些请求 header ,这些 header 允许我在 Web 应用程序级别提取最初位于 websocket 消息中的所需信息。

listenerRule:
  Type: AWS::ElasticLoadBalancingV2::ListenerRule
  Properties:
    Actions:
      - Type: forward
        TargetGroupArn: !Ref targetGroup
    Conditions:
      - Field: path-pattern
        PathPatternConfig: 
            Values:
              - !Sub
                - ${servicePath}*
                - servicePath: !FindInMap [microservice, settings, path]
    ListenerArn: 
      Fn::ImportValue: !Sub ${prefix}-alb-http-listener-id
    Priority: 2

现在在 api 网关我有我的 websocket 路由。像这样的事情

wsCommandRoute:
  Type: AWS::ApiGatewayV2::Route
  Properties:
    ApiId: !Ref wsApiGateway
    RouteKey: command
    AuthorizationType: NONE
    OperationName: CommandRoute
    RouteResponseSelectionExpression: $default
    Target: !Join
      - /
      - - integrations
        - !Ref wsCommandIntegration

wsCommandIntegration:
  Type: AWS::ApiGatewayV2::Integration
  Properties:
    ApiId: !Ref wsApiGateway
    Description: Websocket command integration
    IntegrationType: HTTP_PROXY
    IntegrationMethod: POST
    IntegrationUri:
      !Sub 
        - https://${domainName}${websocketServicePath}/ws/commands
        - domainName: !FindInMap [gateways, api, domainName]
          websocketServicePath: 
            Fn::ImportValue: !Sub ${prefix}-websocket-service-path
    RequestParameters:
      "integration.request.header.domainName": "context.domainName"
      "integration.request.header.stage": "context.stage"
      "integration.request.header.connectionId": "context.connectionId"
    PayloadFormatVersion: 1.0

wsCommandRouteResponse:
  Type: AWS::ApiGatewayV2::RouteResponse
  Properties:
    ApiId: !Ref wsApiGateway
    RouteId: !Ref wsCommandRoute
    RouteResponseKey: $default

如果有人有更好的方法,我很乐意将其标记为有效答案。

关于amazon-web-services - 重写 Api Gateway websocket API 私有(private) http 与 ALB 集成中的目标路径,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67604766/

相关文章:

amazon-web-services - 使 AWS RDS 可通过 Lambda 函数访问

amazon-web-services - 部署 CloudFormation 堆栈以创建 ElasticBeanstalk 应用程序时出现 InsufficientPrivilegesException

amazon-web-services - 在云形成模板中指定 yum 的版本

macos - 我无法将内容写入 var 文件

java - 尝试连接到 RDS 时 AWS EC2 间歇性 UnknownHostException

java - 在wss://ws.luno.com/api/1/stream/:pair上作为客户端连接到ssl Web套接字

ajax - 如何在不刷新页面的情况下将新的 HTML 数据从服务器推送到浏览器

node.js - 将 getUserMedia 流式传输到服务器

amazon-web-services - 如何在我的 CFN 模板中引用现有的 s3 存储桶,以便我的 lambda 可以使用该存储桶?

amazon-web-services - EC2 CloudFormation 中的卷标签和 block 设备映射标签有什么区别