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

Posted

技术标签:

【中文标题】尝试使用 KMS 在 Lambda 函数中解密密文会导致超时【英文标题】:Attempting to decrypt ciphertext within a Lambda function using KMS results in timeout 【发布时间】:2017-03-27 10:56:17 【问题描述】:

当使用 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.logparams 或其他任何东西,这些值将毫无问题地输出。 kms.decrypt 调用似乎存在某种问题,并且没有返回超出超时时间的实际错误。 附加到调用 lambda 函数的角色的策略包含附加的策略 AWSLambdaVPCAccessExecutionRole,以及以下附加的内联策略:

policygen-lambda_basic_execution_and_kms_decrypt-201611131221:


    "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"
            ]
        
    ]

我已经修改了代码中的所有识别信息。

【问题讨论】:

【参考方案1】:

在与非常有帮助的 AWS 支持人员进行了深入交谈后,我们得到了答案:

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

为了让 VPC 中的 Lambda 函数连接到除 Amazon S3 之外的任何服务,确实在 VPC 中有一个端点,Lambda 函数必须位于/关联至少一个,但最好是两个私有子网,它们的路由表包括到 NAT 网关的目标路由 0.0.0.0/16。

不可能让 Lambda 函数位于具有 Internet 网关的公共子网中。

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

    创建或记下现有私有子网,该子网具有 0.0.0.0/0 到 NAT 网关的路由表条目。 如果您还没有如上所述的 NAT 网关、路由表和子网,则必须首先创建它们并将它们适当地相互关联。 在创建 Lambda 函数时,将 Lambda 函数附加到上述私有子网,或编辑 Lambda 函数以具有该配置。

如果您遵循这两个步骤,您应该能够从您的 Lambda 函数中调用 kms.encrypt 和其他请求,这些请求需要出站/出站互联网连接,因为这些服务在您的 VPC 中没有端点。

【讨论】:

我们遇到了同样的问题,这真的很有帮助! AWS 支持人员是否解释了为什么公共 VPC 子网中的 EC2 实例能够访问 KMS/其他服务,而 Lambda 函数却不能? 他们没有具体解释,但根据我对 Lambda 函数是如何实例化的理解,这是由于 Lambda 函数位于它们自己的 VPC 中的临时容器中。 在图中,Internet 网关被描绘为位于 VPC 子网中,这是不准确的。互联网网关与整个 VPC 相关联,但不存在于任何给定子网中。 值得注意的是,AWS 现在有一个适用于 KMS 的接口端点,您可以在 VPC 中与 lambdas 一起使用:aws.amazon.com/blogs/security/… 这是黄金。节省时间挠头【参考方案2】:

EC2 实例默认带有自己的公共 IP,因此它们可以毫无问题地访问任何需要访问 Internet 的服务(例如 KMS)。

附加到您的 VPC 的 Lambda 函数没有公共 IP,因此要通过 Internet 访问服务(例如 KMS),您需要按照 zealoushacker 的描述设置 NAT。

【讨论】:

这取决于 - 您适合默认 VPC 或“EC2 Classic”账户中的 EC2 实例。但是,如果您创建了自己的 VPC,则默认情况下实例可能不会获得公共 IP,并且需要 NAT 网关 - 这是创建 VPC 时的设置。【参考方案3】:

要添加到 zealoushacker 的出色答案,您还应该检查您的 lambda 安全组设置是否具有指向 0.0.0.0 和任何端口的出站规则。

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

【讨论】:

【参考方案4】:

为了快速更新,我遇到了同样的问题,但现在我们可以直接将指向 KMS 的 Endpoint 添加到您的 lambda 附加到的 VPC。

您可以在这里找到详细信息:https://docs.aws.amazon.com/kms/latest/developerguide/kms-vpc-endpoint.html

我进行此更新是因为我即将遵循其他答案(应该仍然有效),但这种方式似乎更自然。

【讨论】:

请添加更多详细信息以扩展您的答案,例如工作代码或文档引用。

以上是关于尝试使用 KMS 在 Lambda 函数中解密密文会导致超时的主要内容,如果未能解决你的问题,请参考以下文章

解密aws kms密钥时出现Nodejs异步问题

KMS 加密 - 本地开发

Cloud Function 使用 KMS 密钥解密的权限被拒绝

使用默认 aws/S3 KMS 密钥对解密对象进行跨账户访问

AWS lambda 和 kms 密钥别名

谷歌云 KMS:加密有效但解密失败