使用CloudFormation和API Gateway代理进行设置时,Lambda权限错误

时间:2018-02-12 06:52:18

标签: amazon-web-services lambda aws-api-gateway amazon-cloudformation

我正在尝试编写一个可以创建lambda函数并将其连接到API网关代理资源的cloudformation脚本。堆栈创建工作,但权限或集成配置有问题,当我测试端点时,我一直在

  

Mon Feb 12 06:45:28 UTC 2018:终点响应体之前   转换:无法   确定要授权的服务/操作名称   

     

Mon Feb 12 06:45:28 UTC 2018:端点响应标头:   {连接=保活,   的x AMZN-的requestId = 4fdf1e92-0fc0-11e8-b3f1-0134476f962c,   内容长度= 130,日期=星期一,2018年2月12日06:45:28 GMT}星期一2月12日   06:45:28 UTC 2018:由于配置错误导致执行失败:   格式错误的Lambda代理响应Mon Feb 12 06:45:28 UTC 2018:Method   完成状态: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

我已经坚持了一段时间了,任何指针都会非常感激。

2 个答案:

答案 0 :(得分:0)

首先,我注意到您的IntegrationHttpMethodANY。对于Lambdas,除非您使用{proxy+}配置,否则请尝试使用POST。我很确定CloudFormation文档仍然过时,但您会在this answer中找到一些有用的信息。

我注意到的第二件事是格式错误的代理响应,在您的情况下可能只是一个配置错误。只是为了排除这一点,在AWS支持中心处理格式错误的代理响应是answered。基本上,您的lambda响应应采用以下格式,包括不添加任何额外的键。

{
    "isBase64Encoded": true|false,
    "statusCode": httpStatusCode,
    "headers": { "headerName": "headerValue", ... },
    "body": "..."
}

您可以使用支持文档上的示例函数代替常规函数,以便您可以隔离问题。

答案 1 :(得分:0)

经过一些反复试验,结合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

我昨天(不工作)与此(工作)之间的差异摘要:

  1. Credentials部分删除了Integration个对象。
  2. IntegrationHttpMethod从ANY更改为POST(感谢Miles指出这一点)
  3. FunctionPermissions已更改SourceArn下以/*而不是/*/*/*
  4. 结束

    虽然在这种情况下我的lambda函数的响应不是问题,但重要的是它的格式正确。所以这是我的功能,希望在一个地方拥有一切将对人们有所帮助。

    def lambda_handler(event, context):
        response = {
            "isBase64Encoded": "false",
            "statusCode": 200,
            "headers": { "Content-Type": "application/json"},
            "body": "hello from sample function"
        }
    
        return response