使用 CloudFormation 时,AWS Lambda 函数缺少由 websocket 网关触发
AWS Lambda function is missing trigger by websocket gateway when using CloudFormation
我正在尝试 set-up 到 AWS 中 Lambda 函数的 websocket 网关。当我手动执行此操作时,我可以成功部署 websocket 并使用 wscat
进行试用。但是我想使用 CloudFormation 构建架构。
我的 CloudFormation yaml 文件的结构如下所示:
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
lambdaRole:
Type: String
Default: ...
backendRole:
Type: String
Default: ...
lambdaImage:
Type: String
Default: ...
Resources:
MyLambdaFunction:
Type: AWS::Lambda::Function
Properties:
Code:
ImageUri: !Sub ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${backendRole}:${lambdaImage}
Description: lambda connect function
FunctionName: myLambdaFunction
MemorySize: 128
Role: !Sub arn:aws:iam::${AWS::AccountId}:role/${lambdaRole}
Timeout: 3
PackageType: Image
MyWebSocket:
Type: AWS::ApiGatewayV2::Api
Properties:
Name: MyWebSocket
ProtocolType: WEBSOCKET
RouteSelectionExpression: $request.body.action
MyIntegration:
Type: AWS::ApiGatewayV2::Integration
Properties:
ApiId: !Ref MyWebSocket
Description: Lambda Integration
IntegrationType: AWS_PROXY
IntegrationUri: !Join
- ''
- - 'arn:'
- !Ref 'AWS::Partition'
- ':apigateway:'
- !Ref 'AWS::Region'
- ':lambda:path/2015-03-31/functions/'
- !GetAtt MyLambdaFunction.Arn
- /invocations
IntegrationMethod: POST
MyConnectRoute:
Type: AWS::ApiGatewayV2::Route
Properties:
ApiId: !Ref MyWebSocket
RouteKey: $connect
Target: !Join
- /
- - integrations
- !Ref MyIntegration
MyDefaultRoute:
Type: AWS::ApiGatewayV2::Route
Properties:
ApiId: !Ref MyWebSocket
RouteKey: $default
Target: !Join
- /
- - integrations
- !Ref MyIntegration
MyResponseRoute:
Type: AWS::ApiGatewayV2::Route
Properties:
ApiId: !Ref MyWebSocket
RouteKey: add
RouteResponseSelectionExpression: $default
Target: !Join
- /
- - integrations
- !Ref MyIntegration
MyRouteResponse:
Type: AWS::ApiGatewayV2::RouteResponse
Properties:
RouteId: !Ref MyResponseRoute
ApiId: !Ref MyWebSocket
RouteResponseKey: $default
MyIntegrationResponse:
Type: AWS::ApiGatewayV2::IntegrationResponse
Properties:
IntegrationId: !Ref MyIntegration
IntegrationResponseKey: /201/
ApiId: !Ref MyWebSocket
testStage:
Type: AWS::ApiGatewayV2::Stage
DependsOn:
- MyConnectRoute
- MyDefaultRoute
- MyResponseRoute
Properties:
ApiId: !Ref MyWebSocket
StageName: testStage
MyDeployment:
Type: AWS::ApiGatewayV2::Deployment
Properties:
ApiId: !Ref MyWebSocket
Description: My Deployment
StageName: !Ref testStage
堆栈的构建没有任何错误,并且(几乎)一切看起来都符合我的预期。然而,除了在手动构建版本中,将 Lambda 函数集成到 websocket 中似乎没有为 Lambda 函数添加所需的触发器。当我手动将 Lambda 函数添加到 API 网关时,这会自动添加触发器。
我需要在 CloudFormation Yaml 文件中更改什么才能将触发器添加到 Lambda 函数?
当 Lambda 函数手动添加到 API 网关时,触发器自动添加到 Lambda 函数:
使用 CloudFormation 将 Lambda 函数添加到 API 网关时未添加触发器:
我猜你需要 AWS::Lambda::Permission
资源,例如:
LambdaPermission:
Type: AWS::Lambda::Permission
Properties:
Action: lambda:invokeFunction
FunctionName: !GetAtt MyLambdaFunction.Arn
Principal: apigateway.amazonaws.com
SourceArn:
Fn::Join:
- ''
- - 'arn:aws:execute-api:'
- Ref: AWS::Region
- ":"
- Ref: AWS::AccountId
- ":"
- Ref: MyWebSocket
- "/*"
它可能需要一些调整 - 它适用于 AWS::ApiGateway::RestApi
,不确定 AWS::ApiGatewayV2::Api
是否有区别。
看起来您可能只需要包含 api 网关的 Lambda 权限。
LambdaFunctionPermission:
Type: "AWS::Lambda::Permission"
Properties:
Action: "lambda:InvokeFunction"
Principal: apigateway.amazonaws.com
FunctionName: !Ref MyLambdaFunction
DependsOn: MyWebSocket
如果您在创建 Cloudformation 时遇到问题,那么创建一个用于日志记录的帐户配置并像这样链接网关资源的 dependsOn 顺序可能会有所帮助。
ApiGwAccountConfig:
Type: "AWS::ApiGateway::Account"
Properties:
CloudWatchRoleArn: !GetAtt "rRoleForCloudtrail.Arn"
rRoleForCloudtrail:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- apigateway.amazonaws.com
Action:
- sts:AssumeRole
Policies:
-
PolicyName: "apigateway-cloudwatch"
PolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: "Allow"
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:DescribeLogGroups
- logs:DescribeLogStreams
- logs:PutLogEvents
- logs:GetLogEvents
- logs:FilterLogEvents
Resource: "*"
testStage:
Type: AWS::ApiGatewayV2::Stage
Properties:
ApiId: !Ref MyWebSocket
StageName: testStage
DefaultRouteSettings:
DetailedMetricsEnabled: true
LoggingLevel: INFO
DataTraceEnabled: true
DependsOn: ApiGwAccountConfig
MyDeployment:
Type: AWS::ApiGatewayV2::Deployment
DependsOn:
- MyConnectRoute
- MyDefaultRoute
- MyResponseRoute
Properties:
ApiId: !Ref MyWebSocket
Description: My Deployment
StageName: !Ref testStage
我正在尝试 set-up 到 AWS 中 Lambda 函数的 websocket 网关。当我手动执行此操作时,我可以成功部署 websocket 并使用 wscat
进行试用。但是我想使用 CloudFormation 构建架构。
我的 CloudFormation yaml 文件的结构如下所示:
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
lambdaRole:
Type: String
Default: ...
backendRole:
Type: String
Default: ...
lambdaImage:
Type: String
Default: ...
Resources:
MyLambdaFunction:
Type: AWS::Lambda::Function
Properties:
Code:
ImageUri: !Sub ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${backendRole}:${lambdaImage}
Description: lambda connect function
FunctionName: myLambdaFunction
MemorySize: 128
Role: !Sub arn:aws:iam::${AWS::AccountId}:role/${lambdaRole}
Timeout: 3
PackageType: Image
MyWebSocket:
Type: AWS::ApiGatewayV2::Api
Properties:
Name: MyWebSocket
ProtocolType: WEBSOCKET
RouteSelectionExpression: $request.body.action
MyIntegration:
Type: AWS::ApiGatewayV2::Integration
Properties:
ApiId: !Ref MyWebSocket
Description: Lambda Integration
IntegrationType: AWS_PROXY
IntegrationUri: !Join
- ''
- - 'arn:'
- !Ref 'AWS::Partition'
- ':apigateway:'
- !Ref 'AWS::Region'
- ':lambda:path/2015-03-31/functions/'
- !GetAtt MyLambdaFunction.Arn
- /invocations
IntegrationMethod: POST
MyConnectRoute:
Type: AWS::ApiGatewayV2::Route
Properties:
ApiId: !Ref MyWebSocket
RouteKey: $connect
Target: !Join
- /
- - integrations
- !Ref MyIntegration
MyDefaultRoute:
Type: AWS::ApiGatewayV2::Route
Properties:
ApiId: !Ref MyWebSocket
RouteKey: $default
Target: !Join
- /
- - integrations
- !Ref MyIntegration
MyResponseRoute:
Type: AWS::ApiGatewayV2::Route
Properties:
ApiId: !Ref MyWebSocket
RouteKey: add
RouteResponseSelectionExpression: $default
Target: !Join
- /
- - integrations
- !Ref MyIntegration
MyRouteResponse:
Type: AWS::ApiGatewayV2::RouteResponse
Properties:
RouteId: !Ref MyResponseRoute
ApiId: !Ref MyWebSocket
RouteResponseKey: $default
MyIntegrationResponse:
Type: AWS::ApiGatewayV2::IntegrationResponse
Properties:
IntegrationId: !Ref MyIntegration
IntegrationResponseKey: /201/
ApiId: !Ref MyWebSocket
testStage:
Type: AWS::ApiGatewayV2::Stage
DependsOn:
- MyConnectRoute
- MyDefaultRoute
- MyResponseRoute
Properties:
ApiId: !Ref MyWebSocket
StageName: testStage
MyDeployment:
Type: AWS::ApiGatewayV2::Deployment
Properties:
ApiId: !Ref MyWebSocket
Description: My Deployment
StageName: !Ref testStage
堆栈的构建没有任何错误,并且(几乎)一切看起来都符合我的预期。然而,除了在手动构建版本中,将 Lambda 函数集成到 websocket 中似乎没有为 Lambda 函数添加所需的触发器。当我手动将 Lambda 函数添加到 API 网关时,这会自动添加触发器。
我需要在 CloudFormation Yaml 文件中更改什么才能将触发器添加到 Lambda 函数?
当 Lambda 函数手动添加到 API 网关时,触发器自动添加到 Lambda 函数:
使用 CloudFormation 将 Lambda 函数添加到 API 网关时未添加触发器:
我猜你需要 AWS::Lambda::Permission
资源,例如:
LambdaPermission:
Type: AWS::Lambda::Permission
Properties:
Action: lambda:invokeFunction
FunctionName: !GetAtt MyLambdaFunction.Arn
Principal: apigateway.amazonaws.com
SourceArn:
Fn::Join:
- ''
- - 'arn:aws:execute-api:'
- Ref: AWS::Region
- ":"
- Ref: AWS::AccountId
- ":"
- Ref: MyWebSocket
- "/*"
它可能需要一些调整 - 它适用于 AWS::ApiGateway::RestApi
,不确定 AWS::ApiGatewayV2::Api
是否有区别。
看起来您可能只需要包含 api 网关的 Lambda 权限。
LambdaFunctionPermission:
Type: "AWS::Lambda::Permission"
Properties:
Action: "lambda:InvokeFunction"
Principal: apigateway.amazonaws.com
FunctionName: !Ref MyLambdaFunction
DependsOn: MyWebSocket
如果您在创建 Cloudformation 时遇到问题,那么创建一个用于日志记录的帐户配置并像这样链接网关资源的 dependsOn 顺序可能会有所帮助。
ApiGwAccountConfig:
Type: "AWS::ApiGateway::Account"
Properties:
CloudWatchRoleArn: !GetAtt "rRoleForCloudtrail.Arn"
rRoleForCloudtrail:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- apigateway.amazonaws.com
Action:
- sts:AssumeRole
Policies:
-
PolicyName: "apigateway-cloudwatch"
PolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: "Allow"
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:DescribeLogGroups
- logs:DescribeLogStreams
- logs:PutLogEvents
- logs:GetLogEvents
- logs:FilterLogEvents
Resource: "*"
testStage:
Type: AWS::ApiGatewayV2::Stage
Properties:
ApiId: !Ref MyWebSocket
StageName: testStage
DefaultRouteSettings:
DetailedMetricsEnabled: true
LoggingLevel: INFO
DataTraceEnabled: true
DependsOn: ApiGwAccountConfig
MyDeployment:
Type: AWS::ApiGatewayV2::Deployment
DependsOn:
- MyConnectRoute
- MyDefaultRoute
- MyResponseRoute
Properties:
ApiId: !Ref MyWebSocket
Description: My Deployment
StageName: !Ref testStage