【问题标题】:API_CONFIGURATION_ERROR when using AWS_IAM authorizer for AWS::Serverless::Api对 AWS::Serverless::Api 使用 AWS_IAM 授权方时的 API_CONFIGURATION_ERROR
【发布时间】:2021-09-25 07:18:42
【问题描述】:

我正在尝试使用 sam 模板设置具有单个 lambda 函数的私有 API,但无论我做什么,API 网关都会记录 API_CONFIGURATION_ERROR。我不知道我做错了什么。 docs 不是很具体。根据this example,我认为我的模板看起来不错。

我的代码使用 axios 和 aws4,我也尝试过 fetch 而不是 axios。当我使用 Postman 时,我也遇到了同样的错误,所以我真的不认为我的请求有问题。如果我只是禁用 IAM 授权,一切都会正常工作。

这是我尝试调用的 api 和 lambda 函数的模板。

AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: >
  iam-api-example
Parameters:
  SamplePrivateApiStageName:
    Type: String
    Default: endpoint
  SampleTableName:
    Type: String
    Default: SampleTable
Globals:
  Function:
    Runtime: nodejs14.x
    Timeout: 10
    MemorySize: 128
    Handler: app.lambdaHandler
Resources:

  SamplePrivateApi:
    Type: AWS::Serverless::Api
    Properties:
      Name: SamplePrivateApi
      StageName: !Ref SamplePrivateApiStageName
      Auth:
        DefaultAuthorizer: AWS_IAM
      AccessLogSetting:
        DestinationArn: !GetAtt SamplePrivateApiAccessLogs.Arn
        Format: '{ "requestId":"$context.requestId", "ip": "$context.identity.sourceIp", "requestTime":"$context.requestTime", "httpMethod":"$context.httpMethod","routeKey":"$context.routeKey", "path":"$context.path", "status":"$context.status","protocol":"$context.protocol", "responseLength":"$context.responseLength", "errorMessage":"$context.error.message", "responseType":"$context.error.responseType" }'
  SamplePrivateApiAccessLogs:
    Type: AWS::Logs::LogGroup

  GetQuestionFn:
    Type: AWS::Serverless::Function
    Properties:
      Policies:
        - AmazonDynamoDBFullAccess
      CodeUri: build/lambdas/private/advertisement/get-question
      Environment:
        Variables:
          TABLE_NAME: !Ref SampleTableName
      Events:
        GetQuestionFnEvent:
          Type: Api
          Properties:
            Path: /questions
            Method: GET
            RestApiId: !Ref SamplePrivateApi
            #Auth: 
              #Authorizer: "NONE" 

如果我通过取消注释 lambda 函数中的最后两个身份验证行(即使用 Authorizer:“NONE”)来停止使用 defaultAuthorizer,一切正常。所以只有当我让 defaultAuthorizer 负责时它才会失败。

我在 API 日志中得到的错误是:

{
    "requestId": "12311ec0-732d-4088-a641-71f05e4bd418",
    "ip": "x.xx.xxx.xxx",
    "requestTime": "16/Jul/2021:12:37:01 +0000",
    "httpMethod": "GET",
    "routeKey": "-",
    "path": "/endpoint/questions",
    "status": "500",
    "protocol": "HTTP/1.1",
    "responseLength": "36",
    "errorMessage": "Internal server error",
    "responseType": "API_CONFIGURATION_ERROR"
}

在 Postman 中,我使用 AWS 签名授权以及来自具有 AmazonAPIGatewayInvokeFullAccess 策略的 IAM 用户的访问密钥和秘密密钥。区域也应该是正确的。

我在另一个 lambda 函数(也有 AmazonAPIGatewayInvokeFullAccess 策略)中使用的 axios 代码目前看起来像这样。

import AWS from 'aws-sdk'
const aws4 = require('aws4')
const fetchQuestion = async () => {
  // Host is domain without https://
  const urlParts = QUESTION_API_DOMAIN.split('://')
  const host = urlParts.length > 1 ? urlParts[1] : ''

  if (!host) {
    console.error('No host could be extracted.')
    return null
  }

  const request = {
    host,
    method: 'GET',
    url: `${QUESTION_API_DOMAIN}/endpoint/questions`,
    path: `/endpoint/questions`,
  }

  const secretAccessKey = AWS.config.credentials?.secretAccessKey
  const accessKeyId = AWS.config.credentials?.accessKeyId

  if (!secretAccessKey || !accessKeyId) {
    console.error('No credentials could be found.')
    return null
  }

  let signedRequest = aws4.sign(request, {
    secretAccessKey: secretAccessKey,
    accessKeyId: accessKeyId,
    sessionToken: AWS.config.credentials?.sessionToken,
  })

  // delete signedRequest.headers['Host']
  // delete signedRequest.headers['Content-Length']

  try {
    const response = await axios(signedRequest)
    return response.data
  } catch (err) {
    console.error('Error while retrieving question:', err)
  }
}

不知道可能出了什么问题。

【问题讨论】:

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


    【解决方案1】:

    您的 API 网关需要分配一个角色,以允许它调用 lambda 函数(授权方)

    尝试使用 API Auth 部分中的 InvokeRole 属性 (https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-api-apiauth.html)。

    --- 更新了----

    调用角色 arn 必须指向角色 arn 而不是用户,请参见下面的示例

        Type: AWS::Serverless::Api
        Properties:
          Name: SamplePrivateApi
          StageName: !Ref SamplePrivateApiStageName
          Auth:
            DefaultAuthorizer: AWS_IAM
            InvokeRole: !GetAtt APIGatewayRole.Arn
          AccessLogSetting:
            DestinationArn: !GetAtt SamplePrivateApiAccessLogs.Arn
            Format: '{ "requestId":"$context.requestId", "ip": "$context.identity.sourceIp", "requestTime":"$context.requestTime", "httpMethod":"$context.httpMethod","routeKey":"$context.routeKey", "path":"$context.path", "status":"$context.status","protocol":"$context.protocol", "responseLength":"$context.responseLength", "errorMessage":"$context.error.message", "responseType":"$context.error.responseType" }'
      SamplePrivateApiAccessLogs:
        Type: AWS::Logs::LogGroup
    
    
    APIGatewayRole:
        Type: "AWS::IAM::Role"
        Properties:
          Path: "/"
          ManagedPolicyArns:
            - "arn:aws:iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs"
          Policies:
            - PolicyName: "authorizerLambdaInvokeAccess"
              PolicyDocument:
                Version: "2012-10-17"
                Statement:
                  - Effect: "Allow"
                    Action:
                      - lambda:InvokeAsync
                      - lambda:InvokeFunction
                    Resource: !Sub ${AuthorizerLambdaFunction.Arn}
    
          AssumeRolePolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Sid: "AllowApiGatewayServiceToAssumeRole"
                Effect: "Allow"
                Action:
                  - "sts:AssumeRole"
                Principal:
                  Service:
                    - "apigateway.amazonaws.com" ```
    

    【讨论】:

    • 谢谢,也许更近了一步,但还是有问题。如果我将 InvokeRole 设置为具有 AWSLambdaBasicExecutionRole 角色的 IAM 用户的 arn,我会收到 DEFAULT_5XX 而不是 API_CONFIGURATION_ERROR 的错误。我还尝试将 AWSLambdaBasicExecutionRole 策略与 API 的 InvokeRole 值 CALLER_CREDENTIALS 一起添加到发送 axios 请求的 lambda 函数中,但由于某种原因这不起作用。在这种情况下,我仍然会收到 API_CONFIGURATION_ERROR 错误。
    • 太好了,非常感谢 :D 这很有道理。我在您的解决方案中用 GetQuestionFn 替换了 AuthorizerLambdaFunction,它适用于我的情况。
    猜你喜欢
    • 2021-03-23
    • 2020-05-14
    • 2018-01-16
    • 2017-11-07
    • 2020-05-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-28
    相关资源
    最近更新 更多