how do I use aws secret manager with nodejs lambda
Solution 1
You need wait for the async call to finish.
Inside your main handler you will have something like:
// inside your main handler
exports.handler = async function(event, context) {
var secret = await getSecret('mySecret')
console.log('mysecret: ' + secret )
return ...
}
Solution 2
Here is a more simple example if someone will need to resolve this issue:
const result = await client
.getSecretValue({
SecretId: AWSConfig.secretName,
})
.promise();
const parsedResult = JSON.parse(result.SecretString);
Solution 3
There is a one more easier way to read from secret manager it.
let secretManager = new SecretsManager({ region: 'region-name' });
const data = await secretManager.getSecretValue({ SecretId: 'secretid' }).promise();
console.log(`data is: ${JSON.stringify(data)}`);
Solution 4
The aws-sdk
provides two means of getting values back from APIs. You can use the native callback mechanism, as shown above, or you can, instead, use .promise()
on the end of the call chain, to convert the API call to its promise equivalent.
E.g.
const data = await (secretManager.getSecret({ SecretId }).promise();
If you're using await
then your function needs to be async
as do all the functions calling it, unless they choose to use Promise's then
/catch
etc.
Solution 5
I've created a Synchronous solution which you can find here: https://github.com/jwerre/secrets
With this package you can load all your secrets inside of a particular namespace like so:
const config = require('@jwerre/secrets').configSync({
region: 'us-east-1',
env: 'production',
namespace: 'my-namespace',
});
This will retrieve all your secrets which may not be exactly what you want. If you want a single secret you can do it like this:
const config = require('@jwerre/secrets').secretSync({
region: 'us-west-2'
id: '/my-co/apis/'
});
Related videos on Youtube
red888
Updated on July 09, 2022Comments
-
red888 almost 2 years
I tried to wrap the example code snippet to get secrets in a function and then call it but it does not appear to be working. I suspect I am calling it asynchronously and I need to call it synchronously? I just want a function I can call to get a secret value and put it in a var.
this is the function:
//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'); } } }); }
Then I call it
// inside exports.handler = (event, context, callback) => { var secret = getSecret('mySecret') console.log('mysecret: ' + secret )
The secret var is always
undefined
EDIT: Async only works with promises so I had to make my function async and return a 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')
-
red888 over 4 yearsCould I also user a promise instead somehow?
-
iwaduarte about 4 yearsyep asyc or promises same same.
-
Peter about 3 yearsafter two days of countless tries to make this work ==> this did the trick!
-
Jamie almost 3 yearsperfect! I think everyone looks for the shorter method straight away.
-
insoftservice over 2 years@iwaduarte could you please provide complete code with async and await. where i can provide SecretString and other required param dynamically
-
insoftservice over 2 yearswhat is /my-co/apis is it secret name?
-
jwerre over 2 yearsYes indeed. I use slashed for my secrets so I can separate them for different kinds of deployment. For example
/production/lambda1/mysql/username
or/staging/api/config/aws/secrete
. Checkout the documentation in the readme. -
iwaduarte over 2 yearsThe code is complete. If you need additional help you should create a new question and put the link here.
-
insoftservice over 2 years
-
ZEE over 2 yearsThis is bad practice, awaiting for secret manager in the handler means, awaiting for it in every lambda call, which is not what you need, especially when you use the secrets for the db client which you need to initiate outside the handler.
-
iwaduarte over 2 yearsWhy is that bad practice ? I fail to see how would do otherwise. The idea is to remove secrets from within application. docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html. If could share the reasons as to why is a bad practice. I would be glad.
-
Dennix about 2 yearsNo idea, why the answers above did not work for me and why there multiple articles with much more complex solutions to this problem but thank you. This is the first solution to work for me :)
-
Aditya about 2 yearsThanks @Dennix, you made my day.