尝试使用 KMS 在 Lambda 函数中解密密文会导致超时
Attempting to decrypt ciphertext within a Lambda function using KMS results in timeout
使用 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_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"
]
}
]
}
- 我已经从代码中编辑了所有识别信息。
在与提供了很大帮助的 AWS 支持人员进行了深入交谈后,我们得到了答案:
超时的主要原因是 Lambda 函数内部与 KMS 服务之间缺乏连接,因为 KMS 服务在配置 Lambda 函数的 VPC 中没有端点。
为了让 VPC 中的 Lambda 函数连接到 除 Amazon S3 之外的任何 服务,确实 在在 VPC 中,Lambda 函数必须位于 in/associated 至少一个,但最好是两个私有子网,其路由 table 包括到 NAT 网关的目标路由 0.0.0.0/16。
不可能 将 Lambda 函数置于具有互联网网关的 public 子网中。
获取绑定 VPC 的 Lambda 函数以访问 KMS 和所有其他没有 VPC 端点的服务的步骤:
- 创建或记录一个现有的私有子网,其中有一个路由 table 条目用于 0.0.0.0/0 到 NAT 网关。
- 如果您还没有如上所述的 NAT 网关、路由 Table 和子网,则必须先创建它们并将它们适当地关联起来。
- 在创建 Lambda 函数时将 Lambda 函数附加到上面的私有子网,或者编辑 Lambda 函数以具有该配置。
如果您遵循这两个步骤,您应该能够从您的 Lambda 函数中调用 kms.encrypt
和其他请求,这需要 outbound/egress 互联网连接,因为这些服务在内部没有端点您的 VPC。
EC2 实例默认带有自己的 public IP,因此它们可以毫无问题地访问任何需要访问互联网的服务(例如 KMS)。
附加到您的 VPC 的 Lambda 函数没有 public IP,因此要通过互联网访问服务(例如 KMS),您需要按照 zealoushacker 的描述设置 NAT。
要添加到 zealoushacker 的出色答案中,您还应该检查您的 lambda 安全组设置是否具有指向 0.0.0.0 和任何端口的出站规则。
在我们的例子中,我们已经 运行 在私有子网中,但将安全组限制在我们的 RDS 数据库中。
只是为了快速更新,我遇到了同样的问题,但现在我们可以直接将指向 KMS 的端点添加到您的 lambda 附加到的 VPC。
您可以在此处找到详细信息:https://docs.aws.amazon.com/kms/latest/developerguide/kms-vpc-endpoint.html
我进行此更新是因为我正要遵循其他答案(应该仍然有效),但这种方式似乎更自然。
使用 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_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"
]
}
]
}
- 我已经从代码中编辑了所有识别信息。
在与提供了很大帮助的 AWS 支持人员进行了深入交谈后,我们得到了答案:
超时的主要原因是 Lambda 函数内部与 KMS 服务之间缺乏连接,因为 KMS 服务在配置 Lambda 函数的 VPC 中没有端点。
为了让 VPC 中的 Lambda 函数连接到 除 Amazon S3 之外的任何 服务,确实 在在 VPC 中,Lambda 函数必须位于 in/associated 至少一个,但最好是两个私有子网,其路由 table 包括到 NAT 网关的目标路由 0.0.0.0/16。
不可能 将 Lambda 函数置于具有互联网网关的 public 子网中。
获取绑定 VPC 的 Lambda 函数以访问 KMS 和所有其他没有 VPC 端点的服务的步骤:
- 创建或记录一个现有的私有子网,其中有一个路由 table 条目用于 0.0.0.0/0 到 NAT 网关。
- 如果您还没有如上所述的 NAT 网关、路由 Table 和子网,则必须先创建它们并将它们适当地关联起来。
- 在创建 Lambda 函数时将 Lambda 函数附加到上面的私有子网,或者编辑 Lambda 函数以具有该配置。
如果您遵循这两个步骤,您应该能够从您的 Lambda 函数中调用 kms.encrypt
和其他请求,这需要 outbound/egress 互联网连接,因为这些服务在内部没有端点您的 VPC。
EC2 实例默认带有自己的 public IP,因此它们可以毫无问题地访问任何需要访问互联网的服务(例如 KMS)。
附加到您的 VPC 的 Lambda 函数没有 public IP,因此要通过互联网访问服务(例如 KMS),您需要按照 zealoushacker 的描述设置 NAT。
要添加到 zealoushacker 的出色答案中,您还应该检查您的 lambda 安全组设置是否具有指向 0.0.0.0 和任何端口的出站规则。
在我们的例子中,我们已经 运行 在私有子网中,但将安全组限制在我们的 RDS 数据库中。
只是为了快速更新,我遇到了同样的问题,但现在我们可以直接将指向 KMS 的端点添加到您的 lambda 附加到的 VPC。
您可以在此处找到详细信息:https://docs.aws.amazon.com/kms/latest/developerguide/kms-vpc-endpoint.html
我进行此更新是因为我正要遵循其他答案(应该仍然有效),但这种方式似乎更自然。