AWS Cloudformation无法向Lambda函数添加权限 [英] AWS Cloudformation unable to add permission to Lambda function

查看:89
本文介绍了AWS Cloudformation无法向Lambda函数添加权限的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆