Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Decrypting multiple env. variables in AWS Lambda

I've got a number of encrypted environmental variables I need to decrypt in an AWS Lambda function. They give an example bit of code, but I'd rather not run a huge chunk for each value I need to decrypt:

const AWS = require('aws-sdk');

const encrypted = process.env['my_password'];
let decrypted;


function processEvent(event, context, callback) {
    // TODO handle the event here
}

exports.handler = (event, context, callback) => {
    if (decrypted) {
        processEvent(event, context, callback);
    } else {
        // Decrypt code should run once and variables stored outside of the function
        // handler so that these are decrypted once per container
        const kms = new AWS.KMS();
        kms.decrypt({ CiphertextBlob: new Buffer(encrypted, 'base64') }, (err, data) => {
            if (err) {
                console.log('Decrypt error:', err);
                return callback(err);
            }
            decrypted = data.Plaintext.toString('ascii');
            processEvent(event, context, callback);
        });
    }
};

I'm wondering if the AWS SDK includes a function that lets me decrypt multiple values at once. Failing that, is there a way to elegantly chain these calls together so they don't take up ~75 lines of my otherwise simple function?

like image 700
opticon Avatar asked Jun 27 '17 19:06

opticon


1 Answers

You can use promises to achieve this. See the example below for decrypting both a username and password via KMS. You can add as many additional decryption promises to the decryptPromises array as you'd like:


    const AWS = require('aws-sdk');

    const encrypted = {
        username: process.env.username,
        password: process.env.password
    };

    let decrypted = {};

    function processEvent(event, context, callback) {
        //do work
    }

    exports.handler = (event, context, callback) => {
        if ( decrypted.username && decrypted.password ) {
            processEvent(event, context, callback);
        } else {
            const kms = new AWS.KMS();

            const decryptPromises = [
                kms.decrypt( { CiphertextBlob: new Buffer(encrypted.username, 'base64') } ).promise(),
                kms.decrypt( { CiphertextBlob: new Buffer(encrypted.password, 'base64') } ).promise()
            ];

            Promise.all( decryptPromises ).then( data => {
                decrypted.username = data[0].Plaintext.toString('ascii');
                decrypted.password = data[1].Plaintext.toString('ascii');

                processEvent(event, context, callback);
            }).catch( err => {
                console.log('Decrypt error:', err);
                return callback(err);
            });
        }
    };

You can find more information on how promises have been implimented for the AWS SDK in the Support for Promises in the SDK documentation.

like image 100
Chris Silcock Avatar answered Oct 16 '22 18:10

Chris Silcock