node.js - 为什么在实现 AWS SecretsManager 时收到 `Endpoint request timed out` 错误?

标签 node.js amazon-web-services aws-lambda aws-cloudformation 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)
  });
};

这是相同的代码,但现在使用 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)
        });
    });    

};

这是我的云形成文件

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: '*'

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

但是,在使用 POSTMAN 部署和测试 API 调用时,使用 AWS SecretsManager 的代码会出现超时错误。我只是打电话

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

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

这里发生了什么?

最佳答案

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

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

关于node.js - 为什么在实现 AWS SecretsManager 时收到 `Endpoint request timed out` 错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68486934/

相关文章:

javascript - ( Node js上的Socket.io)用mysql数据更新div停止而不显示错误

amazon-web-services - Apache Drill 使用 S3 数据源速度慢得无法使用?

reactjs - 使用 axios 将文件上传到 S3 存储桶时出现 403

amazon-web-services - AWS无服务器项目无法通过Git共享?

node.js - Node JS Socket.IO 发射器(和 redis)

node.js - 将node_acl模块与SailsJs集成

node.js - 为什么我无法访问发送到 HTTP Firebase 云函数的此 POST 请求的正文或属性?

amazon-web-services - 查看lambda函数的console.logs

javascript - AWS lambda : Clarification on retrieving data from event object

python - 如何在某些后缀的s3中从一个桶复制到另一个桶