AWS Cloudformation无法向Lambda函数添加权限 [英] AWS Cloudformation unable to add permission to Lambda function
问题描述
我在Cloudformation模板上遇到一个问题,其中正在创建POST方法并已正确设置调用权限,
但是正在创建GET或任何非POST方法,但是,
似乎没有正确设置调用权限。
以下是使用POST方法的工作模板-
AWSTemplateFormatVersion:'2010-09-09'
描述:具有Lambda集成的AWS API Gateway
#创建可重用参数
参数:
CorsOrigin:
类型:字符串
默认值:'*'
CorsHeaders:
类型:字符串
默认:'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'
CorsMethods:
类型:String
默认值:'OPTIONS,GET,PUT,POST,DELETE'
资源:
#创建Lambda作为后端,返回Hello world
BusinessLambda:
类型:AWS :: Lambda :: Func tion
属性:
代码:
ZipFile:|
exports.handler =异步(事件)=> {
let response = {
'statusCode':200,
'headers':{
'Access-Control-Allow-Origin':'*',
'Content-Type':'application / json'
},
'body':'Hello,World!'
};
返回响应;
};
说明:AWS Lambda函数
函数名称:'BusinessLambda'
处理程序:index.handler
内存大小:128
角色:!Sub'arn:aws:iam :: $ {AWS :: AccountId}:role / service-role / ScriptRole'
运行时:nodejs8.10
超时:15
#创建一个Lambda函数以充当授权者,返回允许的IAM策略
AuthorizerLambda:
类型:'AWS :: Lambda :: Function'
属性:
FunctionName:'AuthorizerLambda'
处理程序:处理程序。处理程序
运行时:nodejs8.10
代码:
S3Bucket:'some-bucket-name'
S3Key:'stage / deployable / authPrivate.zip'
说明: 'Auth test'
内存大小:128
超时:15
角色:!Sub'arn:aws:iam :: $$ {AWS :: AccountId}:role / service-role / ScriptRole'
#创建一个名为=>的API网关; test-api-gw
RestApiGateway:
类型:AWS :: ApiGateway :: RestApi
属性:
名称:test-api-gw
ApiKeySourceType:HEADER
描述:具有Lambda集成的API网关
EndpointConfiguration:
类型:
-EDGE
#创建一个称为=>的URL路径; / test
RestApi资源:
类型:AWS :: ApiGateway :: Resource
属性:
ParentId:!GetAtt RestApiGateway.RootResourceId
PathPart:'test'
RestApiId:!Ref RestApiGateway
#创建API网关自定义授权者
RestApiAuthorizer:
类型:AWS :: ApiGateway :: Authorizer
属性:
AuthorizerUri:!Sub arn:aws:apigateway:$ {AWS :: Region}:lambda:path / 2015-03-31 / functions / $ {AuthorizerLambda.Arn} / invocations
RestApiId:!Ref RestApiGateway
类型: REQUEST
IdentitySource:method.request.header.Authorization
名称:custom_authorizer
#提供Lambda的权限以用作API的授权者网关
RestApiAuthorizerPermission:
类型: AWS :: Lambda :: Permission
属性:
操作:lambda:InvokeFunction
函数名称:!GetAtt AuthorizerLambda.Arn
主体: apigateway.amazonaws .com
SourceArn:!Sub arn:aws:execute-api:$ {AWS :: Region}:$ {AWS :: AccountId}:$ {RestApiGateway} / authorizers / $ {RestApiAuthorizer}
#使用自定义授权者创建POST方法
ApiGatewayMethod:
类型:AWS :: ApiGateway :: Method
属性:
ApiKey必需:false
AuthorizationType: CUSTOM
AuthorizerId:!Ref RestApiAuthorizer
HttpMethod:POST
集成:
类型:AWS_PROXY
IntegrationHttpMethod: POST
Uri :! Sub'arn:aws:apigateway:$ {AWS :: Region}:lambda:path / 2015-03-31 / functions / arn:aws:lambda:$ {AWS :: Region}:$ {AWS :: AccountId}:函数:$ {!stageVariables.lambdaAlias} /调用的
IntegrationResponses:
-StatusCode:200
ResponseTemplates:
application / json:$ input.json('$')
ResponseParameters:
method.response.header.Access-Control-Allow-Headers:!Ref CorsHead ers
method.response.header.Access-Control-Allow-Methods:!Ref CorsMethods
method.response.header.Access-Control-Allow-Origin:!Ref CorsOrigin
RequestTemplates:
application / json:$ input.json('$')
方法响应:
-ResponseParameters:
method.response.header.Access-Control-Allow-Headers:true
method.response.header.Access-Control-Allow-Methods:true
method.response.header.Access-Control-Allow-Origin:true
StatusCode:'200'
RequestParameters :
method.request.querystring.name:false
OperationName:'lambda'
ResourceId:!Ref RestApiResource
RestApiId:!Ref RestApiGateway
#通过在/ test资源路径
APIGatewayOptionsMethod中创建OPTIONS方法来启用CORS:
类型: AWS :: ApiGateway :: Method
属性:
ResourceId:!Ref RestApiResour ce
RestApiId:!Ref RestApiGateway
AuthorizationType:NONE
HttpMethod:OPTIONS
Integration:
Type:MOCK
IntegrationResponse:
-ResponseParameters:
method.response.header.Access-Control-Allow-Headers:!Ref CorsHeaders
method.response.header.Access-Control-Allow-Methods:!Ref CorsMethods
method.response。 header.Access-Control-Allow-Origin:!Ref CorsOrigin
ResponseTemplates:
application / json:''
StatusCode:'200'
PassthroughBehavior:WHEN_NO_MATCH
RequestTemplates :
application / json:'{ statusCode:200}'
MethodResponse:
-ResponseModels:
application / json:'Empty'
ResponseParameters:
method.response.header.Access-Control-Allow-Headers:否
method.response.header.Access -Control-Allow-Methods:假
method.response.header.Access-Control-Allow-Origin:假
StatusCode:'200'
#提供API网关权限调用Lambda
LambdaPermission:
类型: AWS :: Lambda :: Permission
属性:
操作: lambda:InvokeFunction
函数名称:!GetAtt BusinessLambda .Arn
主体: apigateway.amazonaws.com
SourceArn:!Sub arn:aws:execute-api:$ {AWS :: Region}:$ {AWS :: AccountId}:$ { RestApiGateway} / * / POST / test
#部署API网关
ApiGatewayDeployment:
类型:AWS :: ApiGateway :: Deployment
DependsOn:ApiGatewayMethod
属性:
说明:Lambda API部署
RestApiId:!Ref RestApiGateway
#在API网关上创建一个名为=>的阶段。 dev
ApiGatewayStage:
类型:AWS :: ApiGateway :: Stage
属性:
DeploymentId:!Ref ApiGatewayDeployment
描述:API GW阶段dev
RestApiId :!Ref RestApiGateway
StageName:'dev'
变量:
'lambdaAlias':'BusinessLambda'
但是如果我将方法更改为GET,则无法使用-
#使用自定义授权者创建GET方法
ApiGatewayMethod:
类型:AWS :: ApiGateway :: Method
属性:
ApiKeyRequired:false
AuthorizationType : CUSTOM
AuthorizerId:!Ref RestApiAuthorizer
HttpMethod:GET
集成:
类型:AWS_PROXY
IntegrationHttpMethod: GET
Uri:!Sub 'arn:aws:apigateway:$ {AWS :: Region}:lambda:path / 2015-03-31 / functions / arn:aws:lambda:$ {AWS :: Region}:$ {AWS :: AccountId}:function :$ {!stageVariables.lambdaAlias} / invocations'
集成响应:
-StatusCode:200
ResponseTemplates:
application / json:$ input.json('$')
ResponseParameters:
method.response.header.Access-Control-Allow-Headers:!Ref CorsHeaders
method.response.header.Access-Control-Allow-Methods:!Ref CorsMethods
method.response.header.Access- Control-Allow-Origin:!Ref CorsOrigin
RequestTemplates:
application / json:$ input.json('$')
方法响应:
-ResponseParameters:
方法.response.header.Access-Control-Allow-Headers:true
方法.response.header.Access-Control-Allow-Methods:true
method.response.header.Access-Control-Allow-Origin :true
StatusCode:'200'
RequestParameters:
method.request.querystring.name:false
OperationName:'lambda'
ResourceId:!Ref RestApiResource
RestApiId:!Ref RestApiGateway
#提供API网关调用Lambda的权限
LambdaPermission:
类型: AWS :: Lambda ::权限
属性:
操作: lambda:InvokeFunction
函数名称:!GetAtt BusinessLambda.Arn
主体: apigateway.amazonaws.com
SourceArn :!子 arn:aws:execute-api:$ {AWS :: Region}:$ {AWS :: AccountId}:$ {RestApiGateway} / * / GET / test
AuthorizerLambda
的代码基本上是这样-
我需要做点什么吗像这样-
ApiGatewayMethod:
类型:AWS :: ApiGateway :: Method
属性:
ApiKey必需:false
AuthorizationType: CUSTOM
AuthorizerId:!Ref RestApiAuthorizer
HttpMethod:GET
集成:
类型: AWS_PROXY
IntegrationHttpMethod: POST
Got这可以通过使 IntegrationHttpMethod: POST
,
来解决。因此,无论方法的HTTP类型如何,
IntegrationHttpMethod看起来必须始终为POST。
I am facing an issue on the Cloudformation template where POST methods are getting created and invoke permissions are being set properly,
But the GET or any non POST methods are getting created but,
do not seem to have invocation permission being set properly.
Following is the working template with the POST method -
AWSTemplateFormatVersion: '2010-09-09'
Description: AWS API Gateway with a Lambda Integration
#Creating resusable parameters
Parameters:
CorsOrigin:
Type: String
Default: "'*'"
CorsHeaders:
Type: String
Default: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'"
CorsMethods:
Type: String
Default: "'OPTIONS,GET,PUT,POST,DELETE'"
Resources:
#Creating Lambda to act as a backend, returning Hello world
BusinessLambda:
Type: AWS::Lambda::Function
Properties:
Code:
ZipFile: |
exports.handler = async (event) => {
let response = {
'statusCode': 200,
'headers': {
'Access-Control-Allow-Origin': '*',
'Content-Type': 'application/json'
},
'body': 'Hello, World!'
};
return response;
};
Description: AWS Lambda function
FunctionName: 'BusinessLambda'
Handler: index.handler
MemorySize: 128
Role: !Sub 'arn:aws:iam::${AWS::AccountId}:role/service-role/ScriptRole'
Runtime: nodejs8.10
Timeout: 15
#Creating a Lambda function to act as an Authorizer, returns an allow IAM policy
AuthorizerLambda:
Type: 'AWS::Lambda::Function'
Properties:
FunctionName: 'AuthorizerLambda'
Handler: handler.handler
Runtime: nodejs8.10
Code:
S3Bucket: 'some-bucket-name'
S3Key: 'stage/deployable/authPrivate.zip'
Description: 'Auth test'
MemorySize: 128
Timeout: 15
Role: !Sub 'arn:aws:iam::${AWS::AccountId}:role/service-role/ScriptRole'
#Creating an API gateway called => test-api-gw
RestApiGateway:
Type: AWS::ApiGateway::RestApi
Properties:
Name: test-api-gw
ApiKeySourceType: HEADER
Description: An API Gateway with a Lambda Integration
EndpointConfiguration:
Types:
- EDGE
#Creating a url path called => /test
RestApiResource:
Type: AWS::ApiGateway::Resource
Properties:
ParentId: !GetAtt RestApiGateway.RootResourceId
PathPart: 'test'
RestApiId: !Ref RestApiGateway
#Creating an API Gateway Custom Authorizer
RestApiAuthorizer:
Type: AWS::ApiGateway::Authorizer
Properties:
AuthorizerUri: !Sub "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${AuthorizerLambda.Arn}/invocations"
RestApiId: !Ref RestApiGateway
Type: "REQUEST"
IdentitySource: method.request.header.Authorization
Name: custom_authorizer
#Providing permission to Lambda to be used as an Authorizer for the API Gateway
RestApiAuthorizerPermission:
Type: "AWS::Lambda::Permission"
Properties:
Action: lambda:InvokeFunction
FunctionName: !GetAtt AuthorizerLambda.Arn
Principal: "apigateway.amazonaws.com"
SourceArn: !Sub "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${RestApiGateway}/authorizers/${RestApiAuthorizer}"
#Creating a POST method with Custom Authorizer
ApiGatewayMethod:
Type: AWS::ApiGateway::Method
Properties:
ApiKeyRequired: false
AuthorizationType: "CUSTOM"
AuthorizerId: !Ref RestApiAuthorizer
HttpMethod: POST
Integration:
Type: AWS_PROXY
IntegrationHttpMethod: "POST"
Uri: !Sub 'arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:${!stageVariables.lambdaAlias}/invocations'
IntegrationResponses:
- StatusCode: 200
ResponseTemplates:
application/json: $input.json('$')
ResponseParameters:
method.response.header.Access-Control-Allow-Headers: !Ref CorsHeaders
method.response.header.Access-Control-Allow-Methods: !Ref CorsMethods
method.response.header.Access-Control-Allow-Origin: !Ref CorsOrigin
RequestTemplates:
application/json: $input.json('$')
MethodResponses:
- ResponseParameters:
method.response.header.Access-Control-Allow-Headers: true
method.response.header.Access-Control-Allow-Methods: true
method.response.header.Access-Control-Allow-Origin: true
StatusCode: '200'
RequestParameters:
method.request.querystring.name: false
OperationName: 'lambda'
ResourceId: !Ref RestApiResource
RestApiId: !Ref RestApiGateway
#Enabling CORS by creating an OPTIONS method on /test resource path
APIGatewayOptionsMethod:
Type: "AWS::ApiGateway::Method"
Properties:
ResourceId: !Ref RestApiResource
RestApiId: !Ref RestApiGateway
AuthorizationType: NONE
HttpMethod: OPTIONS
Integration:
Type: MOCK
IntegrationResponses:
- ResponseParameters:
method.response.header.Access-Control-Allow-Headers: !Ref CorsHeaders
method.response.header.Access-Control-Allow-Methods: !Ref CorsMethods
method.response.header.Access-Control-Allow-Origin: !Ref CorsOrigin
ResponseTemplates:
application/json: ''
StatusCode: '200'
PassthroughBehavior: WHEN_NO_MATCH
RequestTemplates:
application/json: '{"statusCode": 200}'
MethodResponses:
- ResponseModels:
application/json: 'Empty'
ResponseParameters:
method.response.header.Access-Control-Allow-Headers: false
method.response.header.Access-Control-Allow-Methods: false
method.response.header.Access-Control-Allow-Origin: false
StatusCode: '200'
#Provide permission for API Gateway to Invoke Lambda
LambdaPermission:
Type: "AWS::Lambda::Permission"
Properties:
Action: "lambda:InvokeFunction"
FunctionName: !GetAtt BusinessLambda.Arn
Principal: "apigateway.amazonaws.com"
SourceArn: !Sub "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${RestApiGateway}/*/POST/test"
#Deploying the API gateway
ApiGatewayDeployment:
Type: AWS::ApiGateway::Deployment
DependsOn: ApiGatewayMethod
Properties:
Description: Lambda API Deployment
RestApiId: !Ref RestApiGateway
#Create a stage on API Gateway called => dev
ApiGatewayStage:
Type: AWS::ApiGateway::Stage
Properties:
DeploymentId: !Ref ApiGatewayDeployment
Description: API GW Stage dev
RestApiId: !Ref RestApiGateway
StageName: 'dev'
Variables:
'lambdaAlias' : 'BusinessLambda'
But if I change the method to GET, it doesn't work -
#Creating a GET method with Custom Authorizer
ApiGatewayMethod:
Type: AWS::ApiGateway::Method
Properties:
ApiKeyRequired: false
AuthorizationType: "CUSTOM"
AuthorizerId: !Ref RestApiAuthorizer
HttpMethod: GET
Integration:
Type: AWS_PROXY
IntegrationHttpMethod: "GET"
Uri: !Sub 'arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:${!stageVariables.lambdaAlias}/invocations'
IntegrationResponses:
- StatusCode: 200
ResponseTemplates:
application/json: $input.json('$')
ResponseParameters:
method.response.header.Access-Control-Allow-Headers: !Ref CorsHeaders
method.response.header.Access-Control-Allow-Methods: !Ref CorsMethods
method.response.header.Access-Control-Allow-Origin: !Ref CorsOrigin
RequestTemplates:
application/json: $input.json('$')
MethodResponses:
- ResponseParameters:
method.response.header.Access-Control-Allow-Headers: true
method.response.header.Access-Control-Allow-Methods: true
method.response.header.Access-Control-Allow-Origin: true
StatusCode: '200'
RequestParameters:
method.request.querystring.name: false
OperationName: 'lambda'
ResourceId: !Ref RestApiResource
RestApiId: !Ref RestApiGateway
#Provide permission for API Gateway to Invoke Lambda
LambdaPermission:
Type: "AWS::Lambda::Permission"
Properties:
Action: "lambda:InvokeFunction"
FunctionName: !GetAtt BusinessLambda.Arn
Principal: "apigateway.amazonaws.com"
SourceArn: !Sub "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${RestApiGateway}/*/GET/test"
The code for AuthorizerLambda
is basically this -
https://github.com/awslabs/aws-apigateway-lambda-authorizer-blueprints/blob/master/blueprints/nodejs/index.js
The /test
API work with POST HTTP method
,
After changing to GET HTTP method
I get the following error -
{
"message": "Internal server error"
}
I found that in the GET case, the Authorizer is getting called,
But control doesn't get passed to the Business Lambda function.
To resolve this -
1. I have to remove the Authorizer from the method
2. Run the add-permission command using CLI
3. Deploy the API
4. Add the Authorizer to the method
5. Deploy again
Related issue -
https://forums.aws.amazon.com/thread.jspa?threadID=240699
Do I need to do something like this -
ApiGatewayMethod:
Type: AWS::ApiGateway::Method
Properties:
ApiKeyRequired: false
AuthorizationType: "CUSTOM"
AuthorizerId: !Ref RestApiAuthorizer
HttpMethod: GET
Integration:
Type: AWS_PROXY
IntegrationHttpMethod: "POST"
Got this resolved by making IntegrationHttpMethod: "POST"
,
So irrespective of the Method's HTTP type,
The IntegrationHttpMethod must always be POST it seems.
这篇关于AWS Cloudformation无法向Lambda函数添加权限的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!