使用 CloudFormation 和 API 网关代理设置时出现 Lambda 权限错误
Lambda permissions error when setup using CloudFormation and API Gateway proxy
我正在尝试编写一个 cloudformation 脚本来创建一个 lambda 函数并将其连接到 API 网关代理资源。堆栈创建有效,但权限或集成配置有问题,当我测试端点时,我不断收到
Mon Feb 12 06:45:28 UTC 2018 : Endpoint response body before
transformations: Unable to
determine service/operation name to be authorized
Mon Feb 12 06:45:28 UTC 2018 : Endpoint response headers:
{Connection=keep-alive,
x-amzn-RequestId=4fdf1e92-0fc0-11e8-b3f1-0134476f962c,
Content-Length=130, Date=Mon, 12 Feb 2018 06:45:28 GMT} Mon Feb 12
06:45:28 UTC 2018 : Execution failed due to configuration error:
Malformed Lambda proxy response Mon Feb 12 06:45:28 UTC 2018 : Method
completed with status: 502
这是我的 cloudformation 脚本:
AWSTemplateFormatVersion: 2010-09-09
Description: An API that proxies requests to another HTTP endpoint
Resources:
MyFunction:
Type: 'AWS::Lambda::Function'
Properties:
Handler: samplefunction.lambda_handler
Runtime: python2.7
Code:
S3Bucket: "ilya-lambdas"
S3Key: "lambda-code.zip"
Role: 'arn:aws:iam::acc-id:role/service-role/basic_lambda_role'
Api:
Type: 'AWS::ApiGateway::RestApi'
Properties:
Name: foo3
Resource:
Type: 'AWS::ApiGateway::Resource'
Properties:
ParentId: !GetAtt Api.RootResourceId
RestApiId: !Ref Api
PathPart: 'test'
RootMethod:
Type: 'AWS::ApiGateway::Method'
Properties:
AuthorizationType: NONE
HttpMethod: ANY
ResourceId: !GetAtt Api.RootResourceId
RestApiId: !Ref Api
Integration:
IntegrationHttpMethod: ANY
IntegrationResponses:
- StatusCode: 200
SelectionPattern: .*
Type: AWS_PROXY
PassthroughBehavior: WHEN_NO_MATCH
Uri: !Join ["", ["arn:aws:apigateway:", "us-east-1", ":lambda:path/2015-03-31/functions/", !GetAtt MyFunction.Arn, "/invocations"] ]
Credentials: 'arn:aws:iam::acc-id:role/service-role/basic_lambda_role'
ProxyMethod:
Type: 'AWS::ApiGateway::Method'
Properties:
HttpMethod: ANY
ResourceId: !Ref Resource
RestApiId: !Ref Api
AuthorizationType: NONE
Integration:
IntegrationHttpMethod: ANY
IntegrationResponses:
- StatusCode: 200
SelectionPattern: .*
Type: AWS_PROXY
Uri: !Join ["", ["arn:aws:apigateway:", "us-east-1", ":lambda:path/2015-03-31/functions/", !GetAtt MyFunction.Arn, "/invocations"] ]
PassthroughBehavior: WHEN_NO_MATCH
Credentials: 'arn:aws:iam::acc-id:role/service-role/basic_lambda_role'
FunctionPermissions:
Type: "AWS::Lambda::Permission"
Properties:
Action: "lambda:InvokeFunction"
FunctionName: !GetAtt MyFunction.Arn
Principal: "apigateway.amazonaws.com"
SourceArn: !Join [ "", ["arn:aws:execute-api:", !Ref "AWS::Region", ":", !Ref "AWS::AccountId", ":", !Ref Api, "/*/*/*" ] ]
Deployment:
DependsOn:
- MyFunction
- RootMethod
- ProxyMethod
Type: 'AWS::ApiGateway::Deployment'
Properties:
RestApiId: !Ref Api
StageName: prod
我已经坚持了一段时间,任何指点将不胜感激。
首先,我注意到你的 IntegrationHttpMethod
是 ANY
。对于 Lambda,除非您使用 {proxy+}
配置,否则请尝试使用 POST
。我很确定 CloudFormation 文档对此仍然过时,但您会在 this answer.
中找到一些有用的信息
我注意到的第二件事是格式错误的代理响应,在您的情况下,这可能只是配置错误。只是为了排除这种情况,在 AWS 支持中心 answered 处理格式错误的代理响应。基本上,您的 lambda 响应应采用以下格式,包括不添加任何额外的键。
{
"isBase64Encoded": true|false,
"statusCode": httpStatusCode,
"headers": { "headerName": "headerValue", ... },
"body": "..."
}
您可以使用支持文档中的示例函数代替常规函数,以便隔离问题。
经过反复试验,结合 Miles 的建议,我得到了可以工作的 CloudFormation 脚本:
AWSTemplateFormatVersion: 2010-09-09
Description: An API that proxies requests to another HTTP endpoint
Resources:
MyFunction:
Type: 'AWS::Lambda::Function'
Properties:
Handler: samplefunction.lambda_handler
Runtime: python2.7
Code:
S3Bucket: "ilya-lambdas"
S3Key: "lambda-code.zip"
Role: !Join ["", ["arn:aws:iam::", !Ref "AWS::AccountId", ":role/service-role/basic_lambda_role"] ]
Api:
Type: 'AWS::ApiGateway::RestApi'
Properties:
Name: foo3
Resource:
Type: 'AWS::ApiGateway::Resource'
Properties:
ParentId: !GetAtt Api.RootResourceId
RestApiId: !Ref Api
PathPart: 'test'
RootMethod:
Type: 'AWS::ApiGateway::Method'
Properties:
AuthorizationType: NONE
HttpMethod: ANY
ResourceId: !GetAtt Api.RootResourceId
RestApiId: !Ref Api
Integration:
IntegrationHttpMethod: POST
Type: AWS_PROXY
PassthroughBehavior: WHEN_NO_MATCH
Uri: !Join ["", ["arn:aws:apigateway:", "us-east-1", ":lambda:path/2015-03-31/functions/", !GetAtt MyFunction.Arn, "/invocations"] ]
ProxyMethod:
Type: 'AWS::ApiGateway::Method'
Properties:
HttpMethod: ANY
ResourceId: !Ref Resource
RestApiId: !Ref Api
AuthorizationType: NONE
Integration:
IntegrationHttpMethod: POST
Type: AWS_PROXY
Uri: !Join ["", ["arn:aws:apigateway:", "us-east-1", ":lambda:path/2015-03-31/functions/", !GetAtt MyFunction.Arn, "/invocations"] ]
PassthroughBehavior: WHEN_NO_MATCH
FunctionPermissions:
Type: "AWS::Lambda::Permission"
Properties:
Action: "lambda:InvokeFunction"
FunctionName: !GetAtt MyFunction.Arn
Principal: "apigateway.amazonaws.com"
SourceArn: !Join [ "", ["arn:aws:execute-api:", !Ref "AWS::Region", ":", !Ref "AWS::AccountId", ":", !Ref Api, "/*" ] ]
Deployment:
DependsOn:
- MyFunction
- RootMethod
- ProxyMethod
Type: 'AWS::ApiGateway::Deployment'
Properties:
RestApiId: !Ref Api
StageName: prod
我昨天(不工作)和这个(工作)之间的差异总结:
- 从
Integration
部分中删除了 Credentials
对象。
- 将
IntegrationHttpMethod
从 ANY 更改为 POST(感谢 Miles 指出这一点)
- 在
FunctionPermissions
下将 SourceArn
更改为以 /*
结尾,而不是 /*/*/*
虽然在此实例中我的 lambda 函数的响应没有问题,但正确格式化它很重要。所以这是我的功能,希望所有这些都集中在一个地方会对人们有所帮助。
def lambda_handler(event, context):
response = {
"isBase64Encoded": "false",
"statusCode": 200,
"headers": { "Content-Type": "application/json"},
"body": "hello from sample function"
}
return response
我正在尝试编写一个 cloudformation 脚本来创建一个 lambda 函数并将其连接到 API 网关代理资源。堆栈创建有效,但权限或集成配置有问题,当我测试端点时,我不断收到
Mon Feb 12 06:45:28 UTC 2018 : Endpoint response body before transformations: Unable to determine service/operation name to be authorized
Mon Feb 12 06:45:28 UTC 2018 : Endpoint response headers: {Connection=keep-alive, x-amzn-RequestId=4fdf1e92-0fc0-11e8-b3f1-0134476f962c, Content-Length=130, Date=Mon, 12 Feb 2018 06:45:28 GMT} Mon Feb 12 06:45:28 UTC 2018 : Execution failed due to configuration error: Malformed Lambda proxy response Mon Feb 12 06:45:28 UTC 2018 : Method completed with status: 502
这是我的 cloudformation 脚本:
AWSTemplateFormatVersion: 2010-09-09
Description: An API that proxies requests to another HTTP endpoint
Resources:
MyFunction:
Type: 'AWS::Lambda::Function'
Properties:
Handler: samplefunction.lambda_handler
Runtime: python2.7
Code:
S3Bucket: "ilya-lambdas"
S3Key: "lambda-code.zip"
Role: 'arn:aws:iam::acc-id:role/service-role/basic_lambda_role'
Api:
Type: 'AWS::ApiGateway::RestApi'
Properties:
Name: foo3
Resource:
Type: 'AWS::ApiGateway::Resource'
Properties:
ParentId: !GetAtt Api.RootResourceId
RestApiId: !Ref Api
PathPart: 'test'
RootMethod:
Type: 'AWS::ApiGateway::Method'
Properties:
AuthorizationType: NONE
HttpMethod: ANY
ResourceId: !GetAtt Api.RootResourceId
RestApiId: !Ref Api
Integration:
IntegrationHttpMethod: ANY
IntegrationResponses:
- StatusCode: 200
SelectionPattern: .*
Type: AWS_PROXY
PassthroughBehavior: WHEN_NO_MATCH
Uri: !Join ["", ["arn:aws:apigateway:", "us-east-1", ":lambda:path/2015-03-31/functions/", !GetAtt MyFunction.Arn, "/invocations"] ]
Credentials: 'arn:aws:iam::acc-id:role/service-role/basic_lambda_role'
ProxyMethod:
Type: 'AWS::ApiGateway::Method'
Properties:
HttpMethod: ANY
ResourceId: !Ref Resource
RestApiId: !Ref Api
AuthorizationType: NONE
Integration:
IntegrationHttpMethod: ANY
IntegrationResponses:
- StatusCode: 200
SelectionPattern: .*
Type: AWS_PROXY
Uri: !Join ["", ["arn:aws:apigateway:", "us-east-1", ":lambda:path/2015-03-31/functions/", !GetAtt MyFunction.Arn, "/invocations"] ]
PassthroughBehavior: WHEN_NO_MATCH
Credentials: 'arn:aws:iam::acc-id:role/service-role/basic_lambda_role'
FunctionPermissions:
Type: "AWS::Lambda::Permission"
Properties:
Action: "lambda:InvokeFunction"
FunctionName: !GetAtt MyFunction.Arn
Principal: "apigateway.amazonaws.com"
SourceArn: !Join [ "", ["arn:aws:execute-api:", !Ref "AWS::Region", ":", !Ref "AWS::AccountId", ":", !Ref Api, "/*/*/*" ] ]
Deployment:
DependsOn:
- MyFunction
- RootMethod
- ProxyMethod
Type: 'AWS::ApiGateway::Deployment'
Properties:
RestApiId: !Ref Api
StageName: prod
我已经坚持了一段时间,任何指点将不胜感激。
首先,我注意到你的 IntegrationHttpMethod
是 ANY
。对于 Lambda,除非您使用 {proxy+}
配置,否则请尝试使用 POST
。我很确定 CloudFormation 文档对此仍然过时,但您会在 this answer.
我注意到的第二件事是格式错误的代理响应,在您的情况下,这可能只是配置错误。只是为了排除这种情况,在 AWS 支持中心 answered 处理格式错误的代理响应。基本上,您的 lambda 响应应采用以下格式,包括不添加任何额外的键。
{
"isBase64Encoded": true|false,
"statusCode": httpStatusCode,
"headers": { "headerName": "headerValue", ... },
"body": "..."
}
您可以使用支持文档中的示例函数代替常规函数,以便隔离问题。
经过反复试验,结合 Miles 的建议,我得到了可以工作的 CloudFormation 脚本:
AWSTemplateFormatVersion: 2010-09-09
Description: An API that proxies requests to another HTTP endpoint
Resources:
MyFunction:
Type: 'AWS::Lambda::Function'
Properties:
Handler: samplefunction.lambda_handler
Runtime: python2.7
Code:
S3Bucket: "ilya-lambdas"
S3Key: "lambda-code.zip"
Role: !Join ["", ["arn:aws:iam::", !Ref "AWS::AccountId", ":role/service-role/basic_lambda_role"] ]
Api:
Type: 'AWS::ApiGateway::RestApi'
Properties:
Name: foo3
Resource:
Type: 'AWS::ApiGateway::Resource'
Properties:
ParentId: !GetAtt Api.RootResourceId
RestApiId: !Ref Api
PathPart: 'test'
RootMethod:
Type: 'AWS::ApiGateway::Method'
Properties:
AuthorizationType: NONE
HttpMethod: ANY
ResourceId: !GetAtt Api.RootResourceId
RestApiId: !Ref Api
Integration:
IntegrationHttpMethod: POST
Type: AWS_PROXY
PassthroughBehavior: WHEN_NO_MATCH
Uri: !Join ["", ["arn:aws:apigateway:", "us-east-1", ":lambda:path/2015-03-31/functions/", !GetAtt MyFunction.Arn, "/invocations"] ]
ProxyMethod:
Type: 'AWS::ApiGateway::Method'
Properties:
HttpMethod: ANY
ResourceId: !Ref Resource
RestApiId: !Ref Api
AuthorizationType: NONE
Integration:
IntegrationHttpMethod: POST
Type: AWS_PROXY
Uri: !Join ["", ["arn:aws:apigateway:", "us-east-1", ":lambda:path/2015-03-31/functions/", !GetAtt MyFunction.Arn, "/invocations"] ]
PassthroughBehavior: WHEN_NO_MATCH
FunctionPermissions:
Type: "AWS::Lambda::Permission"
Properties:
Action: "lambda:InvokeFunction"
FunctionName: !GetAtt MyFunction.Arn
Principal: "apigateway.amazonaws.com"
SourceArn: !Join [ "", ["arn:aws:execute-api:", !Ref "AWS::Region", ":", !Ref "AWS::AccountId", ":", !Ref Api, "/*" ] ]
Deployment:
DependsOn:
- MyFunction
- RootMethod
- ProxyMethod
Type: 'AWS::ApiGateway::Deployment'
Properties:
RestApiId: !Ref Api
StageName: prod
我昨天(不工作)和这个(工作)之间的差异总结:
- 从
Integration
部分中删除了Credentials
对象。 - 将
IntegrationHttpMethod
从 ANY 更改为 POST(感谢 Miles 指出这一点) - 在
FunctionPermissions
下将SourceArn
更改为以/*
结尾,而不是/*/*/*
虽然在此实例中我的 lambda 函数的响应没有问题,但正确格式化它很重要。所以这是我的功能,希望所有这些都集中在一个地方会对人们有所帮助。
def lambda_handler(event, context):
response = {
"isBase64Encoded": "false",
"statusCode": 200,
"headers": { "Content-Type": "application/json"},
"body": "hello from sample function"
}
return response