I have a private subnet with an ECS cluster where services, without public IP addresses, run behind an Application Load Balancer.
The Application Load Balancer is also private.
I have an API Gateway integrated through HTTP with that ALB (see this) using a VPC Link.
All my microservices work perfectly fine like that.
But now I need to add support for websockets and I need to create an API Gateway with protocol type WEBSOCKET, that has routes with HTTP integation, so that the websocket routes $connect
, $disconnect
, sendmessage
are transformed into HTTP requests.
The problem I have is that in order to use private integration I must specify the ALB's Arn, and I cannot specify a URL (see this). Regarding 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.
So in IntegrationUri, instead of specifying something such as https://mypublicdomain.com/My.Service/connect
where I could easily add the service path as part of the URL, I am forced to add the Application Load Balancer ARN, arn:aws:myalb...
and therefore I cannot play with URL paths to have the websocket routes integrate with a specific service behind the ALB.
In other words, How can I associate websocket routes at API Gateway with a specific service behind a private ALB?
PS: I have thought of using some listener rules with path pattern conditions that grab all traffic going to the ALB root /
to the desired service, but that's far from ideal because I would like to route based on something more obvious.
CloudFormation Sample:
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
UPDATE 1: Just after writing the question I thought.. If I can't route based on URI, maybe I can route at the ALB http listener based on some http header that I can set in the websocket's api gateway integration. So I'll keep that as a workaround in case I don't find a way to rewrite url path
UPDATE 2: This question is similar, but the answer is not detailed enough Rewrite destination path in api gateway integration request