Amazon web services 尝试使用KMS在Lambda函数中解密密文会导致超时

Amazon web services 尝试使用KMS在Lambda函数中解密密文会导致超时,amazon-web-services,aws-lambda,aws-sdk,aws-kms,aws-sdk-nodejs,Amazon Web Services,Aws Lambda,Aws Sdk,Aws Kms,Aws Sdk Nodejs,使用AWS CLI从命令行解密密文时,密文将被解密而不会出现问题: $ aws kms decrypt --ciphertext-blob fileb://encrypted-secrets --output text --query Plaintext --region us-east-1 | base64 --decode > decryped-secrets 尝试从js脚本执行此解密操作时,此解密操作也在本地工作: #!/usr/local/bin/node const fs =

使用AWS CLI从命令行解密密文时,密文将被解密而不会出现问题:

$ aws kms decrypt --ciphertext-blob fileb://encrypted-secrets --output text --query Plaintext --region us-east-1 | base64 --decode > decryped-secrets
尝试从js脚本执行此解密操作时,此解密操作也在本地工作:

#!/usr/local/bin/node

const fs = require('fs');
const AWS = require('aws-sdk');
const kms = new AWS.KMS({region:'us-east-1'});

const secretPath = './encrypted-secrets';
const encryptedSecret = fs.readFileSync(secretPath);

const params = {
      CiphertextBlob: encryptedSecret
};

kms.decrypt(params, function(err, data) {
  if (err) {
    console.log(err, err.stack);
  } else {
    const decryptedScret = data['Plaintext'].toString();
    console.log('decrypted secret', decryptedScret);
  }
});
但是,当试图在AWS Lambda函数的上下文中使用与上述几乎相同的代码执行此操作时,函数调用会导致超时:

'use strict';

const zlib = require('zlib');
const mysql = require('mysql');
const fs = require('fs');
const AWS = require('aws-sdk');
const kms = new AWS.KMS({region:'us-east-1'});

const secretPath = './encrypted-secrets';
const encryptedSecret = fs.readFileSync(secretPath);

const params = {
    CiphertextBlob: encryptedSecret
};

exports.handler = (event, context, callback) => {
    kms.decrypt(params, (err, data) => {
       if (err) {
            console.log(err, err.stack);
            return callback(err);
        } else {
            const decryptedScret = data['Plaintext'].toString();
            console.log('decrypted secret', decryptedScret);
            return callback(null, `Successfully processed ${parsed.logEvents.length} log events.`);
        }
    });
};
超时日志:

START RequestId: start-request-id-redacted Version: $LATEST
END RequestId: end-request-id-redacted
REPORT RequestId: report-requested-id-redacted  Duration: 10002.43 ms   Billed Duration: 10000 ms   Memory Size: 128 MB Max Memory Used: 18 MB  
2016-11-13T19:22:28.774Z task-id-redacted Task timed out after 10.00 seconds
注意事项:

  • 如果我注释掉对
    kms.decrypt
    的调用,并尝试
    console.log
    调用
    params
    或任何实际操作,则输出值时不会出现问题。
    kms.decrypt
    调用似乎存在某种问题,并且不会返回超过超时的实际错误
  • 附加到调用lambda函数的角色的策略包含附加的策略
    AWSLambdaVPCAccessExecutionRole
    ,以及以下附加的内联策略:
policygen-lambda_基本_执行_和_kms_解密-20161131221

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "sid-redacted",
            "Effect": "Allow",
            "Action": [
                "kms:Decrypt"
            ],
            "Resource": [
                "arn:aws:kms:us-east-1:account-redacted:key/key-id-redacted"
            ]
        }
    ]
}
  • 我已经从代码中修改了任何识别信息

在与AWS技术支持人员进行了深入的交谈后,我们得到了一个答案:

出现超时的主要原因是由于Lambda函数内缺少到KMS服务的连接,因为KMS服务在配置Lambda函数的VPC中没有端点

为了使专有网络中的Lambda功能连接到除Amazon S3以外的任何服务(该服务在专有网络中具有端点),Lambda功能必须位于至少一个(但最好是两个)私有子网中或与之关联,其路由表包括到NAT网关的0.0.0.0/16的目的地路由

Lambda功能不可能位于具有Internet网关的公共子网中

获取绑定VPC的Lambda函数以访问KMS和所有其他没有VPC端点的服务的步骤:

  • 创建或记录现有的私有子网,该子网具有NAT网关0.0.0.0/0的路由表条目。
    • 如果您还没有NAT网关、路由表和子网(如上所述),则必须先创建它们并将它们适当地关联起来
  • 创建Lambda函数时,将Lambda函数附加到上面的私有子网,或编辑Lambda函数以具有该配置
  • 如果您遵循这两个步骤,您应该能够调用Lambda函数中的
    kms.encrypt
    和其他请求,这些请求需要出站/出站互联网连接,因为这些服务在VPC中没有端点


    EC2实例默认带有自己的公共IP,因此它们在访问任何需要访问internet的服务(如KMS)时不会遇到问题


    连接到VPC的Lambda功能没有公共IP,因此要通过互联网(如KMS)访问服务,您需要按照zealoushacker的描述设置NAT。

    要补充zealoushacker的优秀答案,您还应该检查lambda的安全组设置是否具有指向0.0.0.0和任何端口的出站规则


    在我们的例子中,我们已经在私有子网中运行,但已将安全组限制在RDS数据库中。

    我们遇到了相同的问题,这非常有用!AWS支持人员是否解释了为什么公共VPC子网中的EC2实例能够访问KMS/其他服务,但Lambda函数不能?他们没有具体解释,但根据我对Lambda函数如何实例化的理解,这是因为Lambda函数位于各自VPC中的临时容器中。在图中,互联网网关如图所示位于VPC子网中,这是不准确的。互联网网关与整个专有网络相关联,但不存在于任何给定的子网中。值得注意的是,AWS现在有一个KMS的接口端点,您可以在专有网络中与lambdas一起使用:这是golden。节省时间抓挠我的头,这取决于-你是正确的EC2实例在默认的VPC,或在一个“EC2经典”帐户。但是,如果您已经创建了自己的VPC,那么实例在默认情况下可能不会获得公共IP,并且需要NAT网关-这是创建VPC时的一个设置。