AWS Lambda(NodeJS)获取Secrets Manager密钥无响应问题
问题成因
核心问题是混用了两套不兼容的AWS SDK异步调用逻辑:
- 你将handler声明为
async异步函数,给getSecretValue加了await的同时,又传入了传统回调函数作为入参 - AWS JavaScript SDK v2的规则是:调用API方法时只要传入了回调,方法就不会返回Promise对象
- 这种写法下
await实际等待的是undefined,完全不会阻塞等待API请求返回。Lambda打印完SDK版本后就会直接走完函数执行流程、冻结运行环境,传入的回调根本没机会被触发,自然看不到回调里的任何日志输出。
修复方案
两种写法二选一即可,绝对不要同时混用回调和async/await模式:
方案1:async/await 写法(官方推荐)
去掉getSecretValue的回调入参,直接等待API返回的Promise,用try/catch统一捕获错误即可,修正后的可运行代码:
const aws = require("aws-sdk"); exports.handler = async (event) => { console.log("version = " + aws.VERSION) const client = new aws.SecretsManager({ version: '2017-10-17', region: 'eu-west-2' }); let secret, decodedBinarySecret; try { // 不传回调时,显式调用.promise()是最稳妥的写法,兼容所有v2版本SDK const data = await client.getSecretValue({ SecretId: 'mysecretid' }).promise(); console.log("I am here 1"); // Secrets Manager存储的RDS凭证默认是JSON字符串,直接解析即可拿到用户名、密码、端口等字段 if ('SecretString' in data) { secret = JSON.parse(data.SecretString); } else { let buff = Buffer.from(data.SecretBinary, 'base64'); decodedBinarySecret = buff.toString('ascii'); } console.log("I am here 3"); console.log(secret); // 后续直接用解析后的密钥信息连接RDS即可 return { statusCode: 200, body: 'Secret retrieved successfully' }; } catch (err) { console.log("I am here 2"); const errorCodes = [ 'DecryptionFailureException', 'InternalServiceErrorException', 'InvalidParameterException', 'InvalidRequestException', 'ResourceNotFoundException' ]; if (errorCodes.includes(err.code)) { console.error(`Request failed with code ${err.code}: ${err.message}`); } throw err; } };
方案2:传统回调写法(不推荐)
如果要保留回调逻辑,需要去掉handler的async声明,在回调执行完成后手动调用Lambda内置的callback方法通知函数执行结束,否则函数还是会提前退出:
const aws = require("aws-sdk"); // 去掉async,接收Lambda注入的context、callback参数 exports.handler = (event, context, callback) => { console.log("version = " + aws.VERSION) const client = new aws.SecretsManager({ version: '2017-10-17', region: 'eu-west-2' }); let secret, decodedBinarySecret; client.getSecretValue({ SecretId: 'mysecretid' }, function(err, data) { if (err) { console.log("I am here 2"); // 原有错误处理逻辑 callback(err); return; } console.log("I am here 1"); if ('SecretString' in data) { secret = data.SecretString; } else { // 注意:new Buffer()已被Node.js标记为废弃,统一使用Buffer.from() let buff = Buffer.from(data.SecretBinary, 'base64'); decodedBinarySecret = buff.toString('ascii'); } console.log("I am here 3"); console.log(secret); // 所有逻辑执行完成后必须调用callback返回结果,否则函数会卡住直到超时 callback(null, { statusCode: 200, body: 'success' }); }); };
额外提示:你原有代码里使用的
new Buffer()构造方法已经在Node.js 8之后的版本被标记为废弃,存在安全隐患,统一替换为Buffer.from()即可消除运行时警告。
内容的提问来源于stack exchange,提问作者pilotman
相关产品推荐
相关产品推荐

