为什么在实施 AWS SecretsManager 时出现“端点请求超时”错误?

Pea*_*Gen 5 amazon-web-services node.js aws-cloudformation aws-lambda aws-api-gateway

我正在使用 AWS Lambda、API Gateway、RDS (MySQL) 开发 REST API。我正在使用 Node.js。

这是我的正常 AWS Lambda 代码,调用数据库表来获取数据并通过 REST API 发送数据。

const mysql = require('mysql');
const con = mysql.createConnection({
  host     : "****.****.****.rds.amazonaws.com",
  user     : "****",
  password : "****",
  port     : 3306,
  database : "****"
});

exports.getAllRoles = (event, context, callback) => {
  // allows for using callbacks as finish/error-handlers
  context.callbackWaitsForEmptyEventLoop = false;
  const sql = "select * from role";
  con.query(sql, function (err, result) {
    if (err) throw err;

    var response = {
        "statusCode": 200,
        "headers": {
            "Content-Type": "application/json"
        },
        "body": JSON.stringify(result),
        "isBase64Encoded": false
    };
    callback(null, response)
  });
};
Run Code Online (Sandbox Code Playgroud)

这是相同的代码,但现在使用AWS SecretsManager

const mysql = require('mysql');


// Load the AWS SDK
var AWS = require('aws-sdk'),
    region = "us-east-1",
    secretName = "test-secret",
    secret,
    decodedBinarySecret;

// Create a Secrets Manager client
var client = new AWS.SecretsManager({
    region: region
});


exports.getAllRoles = (event, context, callback) => {

    client.getSecretValue({
        SecretId: secretName
    }, function (err, data) {
        if (err) {
            throw err;
        } else {
            // Decrypts secret using the associated KMS CMK.
            // Depending on whether the secret is a string or binary, one of these fields will be populated.
            if ('SecretString' in data) {
                secret = data.SecretString;
            } else {
                let buff = new Buffer(data.SecretBinary, 'base64');
                decodedBinarySecret = buff.toString('ascii');
            }
        }
        // Your code goes here. 
        const secretObj = JSON.parse(secret);

        //Create MySQL Connection
        const con = mysql.createConnection({
            host     : secretObj.host,
            user     : secretObj.user,
            password : secretObj.password,
            port     : secretObj.port,
            database : secretObj.database
          });

        // allows for using callbacks as finish/error-handlers
        context.callbackWaitsForEmptyEventLoop = false;
        const sql = "select * from role";
        con.query(sql, function (err, result) {
            if (err) throw err;

            var response = {
                "statusCode": 200,
                "headers": {
                    "Content-Type": "application/json"
                },
                "body": JSON.stringify(result),
                "isBase64Encoded": false
            };
            callback(null, response)
        });
    });    

};
Run Code Online (Sandbox Code Playgroud)

这是我的云形成文件

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
  aaaa-restapi

  Sample SAM Template for aaaa-restapi
  
# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
  Function:
    Timeout: 100
    VpcConfig:
        SecurityGroupIds:
          - sg-4424242424
        SubnetIds:
          - subnet-424242424242

Resources:
  
  GetAllRolesFunction:
    Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
    Properties:
      CodeUri: aaaa-restapi/
      Handler: role-getall.getAllRoles
      Runtime: nodejs14.x
      Events:
        HelloWorld:
          Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
          Properties:
            Path: /role/getall
            Method: get
  

  LambdaRole:
    Type: 'AWS::IAM::Role'
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com
            Action:
              - 'sts:AssumeRole'
      Path: /
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
      Policies:
        - PolicyName: root
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Action:
                  - ec2:DescribeNetworkInterfaces
                  - ec2:CreateNetworkInterface
                  - ec2:DeleteNetworkInterface
                  - ec2:DescribeInstances
                  - ec2:AttachNetworkInterface
                Resource: '*'
Run Code Online (Sandbox Code Playgroud)

我的代码没有AWS SecretsManager在部署时工作正常。

然而,当部署和测试 API 调用时,代码AWS SecretsManager给出了。我只是打电话timeout errorPOSTMAN

https://*****.****-api.****-1.amazonaws.com/Prod/role/getall

"message": "Endpoint request timed out"即使在控制台中,我也只看到了其他内容。使用 执行时相同的代码可以正常工作sam invoke local GetAllRolesFunction。测试时也很好sam local start-api。仅当上传到 AWS 并进行 API 调用时才会出现此问题。

这里发生了什么?

jar*_*mod 4

来自 API Gateway 的错误消息“端点请求超时”表明您的 API 调用的 Lambda 函数完成时间超过 29 秒。

我猜测您的 Lambda 函数正在 VPC 中运行,并且您已正确设置到(私有)RDS 数据库的网络路由,但您没有到 Secrets Manager 服务端点的网络路由,因此该请求超时。如果是这样,您需要Secrets Manager 的 VPC 终端节点或路由到公共互联网的 NAT(或 NAT 网关)。