15

当从使用AWS CLI命令行解密的密文,密文被解密没有问题:试图使用超时KMS结果lambda函数内解密的密文

$ 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" 
      ] 
     } 
    ] 
} 
  • 我已经编辑代码中的任何标识信息。

回答

28

与AWS支持人员,其中非常有帮助的一些深入交谈后,我们有一个答案:

为什么出现超时的主要原因是由于来自lambda函数中缺少连接到KMS服务,因为KMS服务在配置了Lambda功能的VPC中没有端点。

为了用于在VPC lambda函数连接到除亚马逊S3其它任何服务,确实有一个端点在VPC,拉姆达函数必须位于/与至少一个相关联的,但最好是两个私有子网,其路由表中包含目的地路由0.0.0.0/16到NAT网关。

它是不是可能使Lambda函数位于具有Internet网关的公有子网中。

步骤来得到一个VPC-LAMBDA约束函数来访问KMS和所有其他服务没有终点VPC:

  1. 创建或利用现有的专用子网,其中有一个路由表项的注意事项为0.0.0.0/0添加到NAT网关。
    • 如果您还没有NAT网关,路由表和子网,如上所述,您必须首先适当地创建并相互关联它们。
  2. 在创建Lambda函数时将Lambda函数附加到上面的专用子网,或者编辑Lambda函数以获得该配置。

如果按照这两个步骤,你应该能够从您的lambda函数中调用kms.encrypt和其他请求,这需要出站/出互联网连接,由于这些服务上的VPC内没有终点。

Visual overview of how Lambda works within a VPC

+1

我们遇到了同样的问题,这真的很有帮助! AWS支持人员解释了为什么公共VPC子网中的EC2实例能够访问KMS /其他服务,但Lambda函数不是? –

+1

他们没有具体解释,但是基于我对Lambda函数如何实例化的理解,这是由于Lambda函数位于他们自己的VPC中的临时容器中。 – zealoushacker

+0

在图中,互联网网关被描绘为在VPC子网中,这是非常的。 Internet网关与整个VPC相关联,但不在任何给定的子网中。 –

2

EC2实例皆预设自己的公网IP,使他们有没有问题访问需要访问互联网(如KMS)的任何服务。

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

+0

这取决于您对默认VPC中的EC2实例或“EC2 Classic”帐户中的EC2实例。但是,如果您创建了自己的VPC,实例默认情况下可能不会获得公共IP,并且需要NAT网关 - 这是创建VPC时的设置。 – RichVel

2

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

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