I have a websocket in a proxy service (this service is a CloudFormation stack), my FE app connects to this websocket.
one of the websocket routes, let's call it "startFeedback", needs to invoke a Lambda in another CloudFormation stack. This is the CloudFormation code (using serverless framework) I used for that:
First of all I need a websocket route:
startFeedbackWebsocketsRoute:
Type: 'AWS::ApiGatewayV2::Route'
DependsOn:
- 'WebsocketsApi'
- 'FeedbackFlowStartFeedbackWebsocketsIntegration'
Properties:
ApiId:
Ref: 'WebsocketsApi'
RouteKey: 'startFeedback'
AuthorizationType: 'NONE'
Target:
Fn::Join:
- '/'
- - 'integrations'
- Ref: 'FeedbackFlowStartFeedbackWebsocketsIntegration'
then an integration to be invoked by that route:
FeedbackFlowStartFeedbackWebsocketsIntegration:
Type: 'AWS::ApiGatewayV2::Integration'
DependsOn: 'WebsocketsApi'
Properties:
ApiId:
Ref: 'WebsocketsApi'
IntegrationType: 'AWS_PROXY'
IntegrationUri:
Fn::Join:
- ''
- - 'arn:'
- Ref: 'AWS::Partition'
- ':apigateway:'
- Ref: 'AWS::Region'
- ':lambda:path/2015-03-31/functions/'
- Fn::ImportValue: demo-feedback-stack-${sls:stage}-FeedbackFlowStartFeedbackLambdaArn
- '/invocations'
In the sample code above, I am importing the ARN of the lambda that I wish to invoke
Last thing I need is a Lambda permission to allows API gateway to trigger the Lambda
FeedbackFlowStartFeedbackPermission:
Type: 'AWS::Lambda::Permission'
DependsOn:
- 'WebsocketsApi'
Properties:
FunctionName:
Fn::ImportValue: demo-feedback-stack-${sls:stage}-FeedbackFlowStartFeedbackLambdaArn
Action: 'lambda:InvokeFunction'
Principal: 'apigateway.amazonaws.com'
Whenever my app connects to the websocket, it calls $connect route, which invokes a Lambda in the same stack and runs some routine procedures which work fine. But after that when it calls the "startFeedback" route and needs to invoke a lambda from a separate stack, it always returns:
{"message": "Forbidden", "connectionId":***"myConnectionID"***, "requestId":***"myRequestId"***}
I thought it was a problem with permissions, so I tampered around with it and tried different things like creating an IAM role and attaching it to my integration to make sure it can actually invoke the lambda, but without luck.
this is the IAM role I created to try and fix the problem if it was a permissions problem:
FeedbackFlowStartFeedbackWebsocketsRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: apigateway.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: ApiGatewayInvokeLambdaPolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action: lambda:InvokeFunction
Resource:
Fn::ImportValue: demo-feedback-stack-${sls:stage}-FeedbackFlowStartFeedbackLambdaArn
Am I missing something here?
According to AWS Docs for AWS::ApiGatewayV2::Integration
, for Websockets we need to always add IntegrationMethod: POST
I was missing that from my CloudFormation code
Update: Actually it also turns out that when we manually create API Gateway routes and integrations, serverless framework doesn't understand that those resources that we are adding are related to our WebsocketApi...so serverless framework doesn't understand it has to redeploy the api
As a workaround... we added the timestamp to websocket description so we force serverless framework to always redeploy the websocket api since it sees a change
provider: {
websocketsDescription: `Websockets API for messaging: ${new Date().toISOString()}`
}