如何在 Node.js Lambda 上使用 AWS Secret Manager

34
我试图把获取密钥的示例代码段封装到一个函数中并调用它,但似乎没有起作用。我怀疑我是异步调用它,需要同步调用?我只想要一个函数,可以调用它来获取秘密值并将其放入变量中。
这是函数:
//outside exports.handler = (event, context, callback) => {
function getSecret(secretName) {
  // Load the AWS SDK
  var AWS = require('aws-sdk'),
      region = process.env.AWS_REGION,
      secretName = secretName,
      secret,
      decodedBinarySecret;

  // Create a Secrets Manager client
  var client = new AWS.SecretsManager({
      region: region
  });

  // In this sample we only handle the specific exceptions for the 'GetSecretValue' API.
  // See https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_GetSecretValue.html
  // We rethrow the exception by default.

  client.getSecretValue({SecretId: secretName}, function(err, data) {
      if (err) {
          if (err.code === 'DecryptionFailureException')
              // Secrets Manager can't decrypt the protected secret text using the provided KMS key.
              // Deal with the exception here, and/or rethrow at your discretion.
              throw err;
          else if (err.code === 'InternalServiceErrorException')
              // An error occurred on the server side.
              // Deal with the exception here, and/or rethrow at your discretion.
              throw err;
          else if (err.code === 'InvalidParameterException')
              // You provided an invalid value for a parameter.
              // Deal with the exception here, and/or rethrow at your discretion.
              throw err;
          else if (err.code === 'InvalidRequestException')
              // You provided a parameter value that is not valid for the current state of the resource.
              // Deal with the exception here, and/or rethrow at your discretion.
              throw err;
          else if (err.code === 'ResourceNotFoundException')
              // We can't find the resource that you asked for.
              // Deal with the exception here, and/or rethrow at your discretion.
              throw err;
      }
      else {
          // Decrypts secret using the associated KMS CMK.
          // Depending on whether the secret is a string or binary, one of these fields will be populated.
          if ('SecretString' in data) {
              return data.SecretString;
          } else {
              let buff = new Buffer(data.SecretBinary, 'base64');
              return buff.toString('ascii');
          }
    }
  });
}

然后我调用它。
// inside exports.handler = (event, context, callback) => {
var secret = getSecret('mySecret')
console.log('mysecret: ' + secret )

秘密变量始终是undefined

编辑:Async仅与Promise一起使用,因此我必须使我的函数异步并返回一个Promise:

async function mySecrets(secretName) {
    // Load the AWS SDK
    var AWS = require('aws-sdk'),
        region = process.env.AWS_REGION,
        secretName = secretName,
        secret,
        decodedBinarySecret;

    // Create a Secrets Manager client
    var client = new AWS.SecretsManager({
        region: region
    });

    return new Promise((resolve,reject)=>{
        client.getSecretValue({SecretId: secretName}, function(err, data) {

            // In this sample we only handle the specific exceptions for the 'GetSecretValue' API.
            // See https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_GetSecretValue.html
            // We rethrow the exception by default.
            if (err) {
                reject(err);
            }
            else {
                // Decrypts secret using the associated KMS CMK.
                // Depending on whether the secret is a string or binary, one of these fields will be populated.
                if ('SecretString' in data) {
                    resolve(data.SecretString);
                } else {
                    let buff = new Buffer(data.SecretBinary, 'base64');
                    resolve(buff.toString('ascii'));
                }
            }
        });
    });
}

.....
// inside handler
exports.handler = async (event) => {
....
var value = await mySecrets('mysecret')
6个回答

20

你需要等待异步调用完成。

在你的主处理程序中,你会有类似以下的代码:

// inside your main handler
exports.handler =  async function(event, context) {
    var secret = await getSecret('mySecret')
    console.log('mysecret: ' + secret )

    return ...
    }

1
我能否以某种方式使用Promise呢? - red888
2
异步或承诺都一样。 - iwaduarte
@iwaduarte,您能否提供带有async和await的完整代码,以便我可以动态地提供SecretString和其他所需参数。 - insoftservice
代码已经完成。如果您需要额外的帮助,请创建一个新问题并在此处放置链接。 - iwaduarte
https://stackoverflow.com/questions/68980785/retrieve-secrets-from-aws-secrets-manager-in-node-js - insoftservice
显示剩余2条评论

12

有一种更简单的方法可以从保密管理器中读取它。

let secretManager = new SecretsManager({ region: 'region-name' });
const data = await secretManager.getSecretValue({ SecretId: 'secretid' }).promise();
console.log(`data is: ${JSON.stringify(data)}`);

不知道为什么上面的答案对我不起作用,也不知道为什么有很多更复杂的解决方案文章,但还是谢谢。这是第一个对我有效的解决方案 :) - Dennix
谢谢 @Dennix,你让我的一天变得更美好了。 - Aditya
对我来说起作用了,唯一需要做的就是在SecretManager前面加上“AWS.”,如下所示: let secretManager = new AWS.SecretsManager({ region: 'region-name' }); - Asraar Wani

10

如果有人需要解决这个问题,这里有一个更简单的示例:

const result = await client
  .getSecretValue({
    SecretId: AWSConfig.secretName,
  })
  .promise();

const parsedResult = JSON.parse(result.SecretString);

经过两天的无数尝试,这个做法终于奏效了! - Peter
太好了!我认为每个人都会直接寻找更短的方法。 - Jamie

5

aws-sdk 提供了两种从 API 中获取值的方式。您可以使用原生回调机制,如上所示,或者您可以在调用链的末尾使用 .promise(),将 API 调用转换为其 Promise 等效形式。

例如:

const data = await secretManager.getSecret({ SecretId }).promise();

如果使用了 await,则您的函数需要是 async,所有调用它的函数也需要是 async,除非它们选择使用 Promise 的 then/catch 等方法。

2

我创建了一种同步解决方案,您可以在此处找到:https://github.com/jwerre/secrets

使用此软件包,您可以将所有秘密加载到特定命名空间中,如下所示:

const config = require('@jwerre/secrets').configSync({
    region: 'us-east-1',
    env: 'production',
    namespace: 'my-namespace',
});

这将检索出您所有的秘密,可能并不完全符合您的要求。如果您只想获取单个秘密,可以使用以下方法:

const config = require('@jwerre/secrets').secretSync({
    region: 'us-west-2'
    id: '/my-co/apis/'
});

/my-co/apis 是一个保密名称吗? - insoftservice
确实如此。我使用斜杠来保护我的机密,以便我可以将它们分离为不同类型的部署。例如/production/lambda1/mysql/username/staging/api/config/aws/secrete。请查看自述文件中的文档。 - jwerre

1
一种更好的方法是在异步 lambda 函数内部执行此操作。
示例 key:val => password:rootPassword
const secret = await secretClient.getSecretValue({SecretId: 'SecretKeyName'}).promise().then((data) => {
        return JSON.parse(data.SecretString);
})

然后作为secret.password进行访问。

注意:使用try/catch块自动处理错误。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接