【问题标题】:AWS SAM template (with OpenAPI) for deploying HTTP API with custom Lambda authorizerAWS SAM 模板(带有 OpenAPI),用于使用自定义 Lambda 授权程序部署 HTTP API
【发布时间】:2020-10-07 00:05:11
【问题描述】:

我已经设法通过带有 OpenAPI 定义的 yaml SAM 模板部署了具有不同路由和 lambda 集成的 AWS HTTP API,但我坚持将自定义 lambda 授权程序添加到我的路由中。当我部署堆栈时,API 创建超时:

ROLLBACK_IN_PROGRESS                     AWS::CloudFormation::Stack               CloudArYer                               The following resource(s) failed to
                                                                                                                           create: [Api]. . Rollback requested by
                                                                                                                           user.
CREATE_FAILED                            AWS::ApiGatewayV2::Api                   Api                                      Internal server error (Service:
                                                                                                                           AmazonApiGatewayV2; Status Code: 500;
                                                                                                                           Error Code: InternalServerException;
                                                                                                                           Request ID: 18242cfd-
                                                                                                                           cc94-4909-a26a-6631806f94e7; Proxy:
                                                                                                                           null)

这是我的模板的主要部分,其中包含 API 定义:

...
  AuthorizerLambdaTemplate:
    Type: AWS::Serverless::Application
    Properties:
      Location: ./templates/Authorizer-template-function.yaml
      Parameters:
        ProjectName: !Sub "${ProjectName}"
        ProjectApiKey: !Sub "${ProjectApiKey}"

  Api:
    Type: AWS::Serverless::HttpApi
    Properties:
      StageName: CloudArYerAPI
      CorsConfiguration:
        AllowCredentials: true
        AllowHeaders: "*"
        AllowMethods:
          - GET
          - POST
          - PUT
        AllowOrigins:
          - https://*
      DefinitionBody:
        openapi: 3.0.1
        info:
          title: CoudArYer-API
          description: HTTP API for connected chicken coop (Cloud Ar Yer)
          version: 2020-09-26
        paths:
          /config/{device}:
            get:
              x-amazon-apigateway-integration:
                $ref: "#/components/x-amazon-apigateway-integrations/GETLambda"
          /event/{type}:
            post:
              x-amazon-apigateway-integration:
                $ref: "#/components/x-amazon-apigateway-integrations/POSTLambda"
          /image/{origin}/{device}:
            put:
              x-amazon-apigateway-integration:
                $ref: "#/components/x-amazon-apigateway-integrations/PUTLambda"

        security:
          - CloudArYer-Authorizer: []

        components:
          securitySchemes:
            CloudArYer-Authorizer:
              type: apiKey
              name: authorization
              in: header
              x-amazon-apigateway-authtype: custom
              x-amazon-apigateway-authorizer:
                type: request
                identitySource: $request.header.authorization
                authorizerUri: 
                  Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${AuthorizerLambdaTemplate.Outputs.FunctionArn}/invocations
                authorizerCredentials: !GetAtt ApiGatewayAuthorizerRole.Arn
                authorizerPayloadFormatVersion: "2.0"
                authorizerResultTtlInSeconds: 60
                enableSimpleResponses: true

          x-amazon-apigateway-integrations:
            PUTLambda:
              payloadFormatVersion: "2.0"
              type: "aws_proxy"
              httpMethod: "POST"
              uri:
                Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${PUTImageLambdaTemplate.Outputs.FunctionArn}/invocations
              connectionType: "INTERNET"
            GETLambda:
              payloadFormatVersion: "2.0"
              type: "aws_proxy"
              httpMethod: "POST"
              uri:
                Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${GETConfigLambdaTemplate.Outputs.FunctionArn}/invocations
              connectionType: "INTERNET"
            POSTLambda:
              payloadFormatVersion: "2.0"
              type: "aws_proxy"
              httpMethod: "POST"
              uri:
                Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${POSTEventLambdaTemplate.Outputs.FunctionArn}/invocations
              connectionType: "INTERNET"

  ApiGatewayAuthorizerRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument: 
        Version: "2012-10-17"
        Statement: 
          - Effect: "Allow"
            Principal: 
              Service: 
                - "apigateway.amazonaws.com"
            Action: 
              - sts:AssumeRole
      Policies: 
        - PolicyName: "InvokeAuthorizerFunction"
          PolicyDocument: 
            Version: "2012-10-17"
            Statement: 
              - Effect: "Allow"
                Action:
                  - lambda:InvokeAsync
                  - lambda:InvokeFunction
                Resource: !GetAtt AuthorizerLambdaTemplate.Outputs.FunctionArn
...

我的授权 lambda 是在嵌套堆栈中定义的 (AuthorizerLambdaTemplate)

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
  AuthorizerFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: !Sub "${ProjectName}-Authorizer-Lambda"
      CodeUri: ../src/authorizer
      Handler: handler.authorizer
      Runtime: nodejs10.x
      Role: !Sub "${CustomAuthorizerFunctionRole.Arn}"
      Environment:
        Variables:
          ProjectApiKey: !Sub "${ProjectApiKey}"

  CustomAuthorizerFunctionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument: 
        Version: "2012-10-17"
        Statement:
          - Effect: "Allow"
            Principal: 
              Service: 
                - "lambda.amazonaws.com"
            Action: 
              - sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

Parameters:
  ProjectName: 
    Type: String
  ProjectApiKey:
    Type: String

Outputs:
  FunctionArn:
    Description: Arn Authorizer function
    Value: !GetAtt AuthorizerFunction.Arn

并且 lambda 的代码在外部目录中定义如下

exports.authorizer = async(event) => {
    let response = {
        "isAuthorized": false,
        "context": {
            "stringKey": "test"
        }
    };

    if (event.headers.authorization === process.env.ProjectApiKey) {
        response = {
            "isAuthorized": true,
            "context": {
                "stringKey": "test"
            }
        };
    }

    return response;
};

我不明白为什么在创建 API 时部署被阻止...并且因 InternalServerException 而失败。我在堆栈定义上哪里错了。我浏览了许多网站,sn-ps...但新 HTTP API 的信息较少,例如没有解决我的问题的线索。

感谢您的潜在帮助! :-)

【问题讨论】:

    标签: amazon-web-services aws-lambda authorization amazon-cloudformation openapi


    【解决方案1】:

    您可以仅使用 SAM 添加 Lambda 授权方,并且无服务器函数可以引用授权方。授权方的 cloudformation 应如下所示:

    LambdaAuthorizer:
        Type: 'AWS::ApiGatewayV2::Authorizer'
        Properties:
             Name: LambdaAuthorizer
             ApiId: !Ref HttpApi
             AuthorizerType: REQUEST
             AuthorizerUri: arn:aws:apigateway:{region}:lambda:path/2015-03-31/functions/arn:aws:lambda: {region}:{account id}:function:{Function name}/invocations
             IdentitySource:
                 - $request.header.Authorization
             AuthorizerPayloadFormatVersion: 2.0
    
    TestGET:
        Type: AWS::Serverless::Function
        Properties:
            CodeUri: .
            Handler: items.get
            Runtime: nodejs12.x
            Events:
            GetAPI:
                Type: Api
                Properties:
                    Auth:
                        Authorizer: LambdaAuthorizer
                    RestApiId: !Ref Api
                    Path: /items
                    Method: get
    

    使用 HTTP API 的 Lambda 授权者文档:https://aws.amazon.com/blogs/compute/introducing-iam-and-lambda-authorizers-for-amazon-api-gateway-http-apis/

    如果您仍然希望使用开放 api 规范,那么您的 yaml 结构是不正确的。要通过开放 api 规范添加安全性,它应该如下所示:

    securityDefinitions:
        LambdaAuthorizer:
            type: "apiKey"
            name: "Authorization"
            in: "header"
            x-amazon-apigateway-authtype: "custom"
            x-amazon-apigateway-authorizer:
                authorizerUri: !Sub "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:${LambdaAuthorizer}/invocations"
                authorizerResultTtlInSeconds: 300
                identitySource: "method.request.header.Authorization"
                type: "request"
    

    注意:这不在组件下。它应该位于顶层的 DefinitionBody 之下。

    定义正文中的自定义授权人文档:https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-swagger-extensions-authorizer.html

    【讨论】:

      猜你喜欢
      • 2018-05-27
      • 2021-09-17
      • 2020-10-08
      • 1970-01-01
      • 1970-01-01
      • 2020-05-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多