56

I'm building a monitoring tool based on AWS Lambda. Given a set of metrics, the Lambdas should be able to send SMS using Twilio API. To be able to use the API, Twilio provide an account SID and an auth token.

How and where should I store these secrets?

I'm currently thinking to use AWS KMS but there might be other better solutions.

Chris Martin
  • 30,334
  • 10
  • 78
  • 137
JonathanGailliez
  • 1,607
  • 2
  • 15
  • 21

5 Answers5

70

Here is what I've come up with. I'm using AWS KMS to encrypt my secrets into a file that I upload with the code to AWS Lambda. I then decrypt it when I need to use them.

Here are the steps to follow.

First create a KMS key. You can find documentation here: http://docs.aws.amazon.com/kms/latest/developerguide/create-keys.html

Then encrypt your secret and put the result into a file. This can be achieved from the CLI with:

aws kms encrypt --key-id some_key_id --plaintext "This is the scret you want to encrypt" --query CiphertextBlob --output text | base64 -D > ./encrypted-secret

You then need to upload this file as part of the Lambda. You can decrypt and use the secret in the Lambda as follow.

var fs = require('fs');
var AWS = require('aws-sdk');
var kms = new AWS.KMS({region:'eu-west-1'});

var secretPath = './encrypted-secret';
var encryptedSecret = fs.readFileSync(secretPath);

var params = {
  CiphertextBlob: encryptedSecret
};

kms.decrypt(params, function(err, data) {
  if (err) console.log(err, err.stack);
  else {
    var decryptedSecret = data['Plaintext'].toString();
    console.log(decryptedSecret);
  }
});

I hope you'll find this useful.

JonathanGailliez
  • 1,607
  • 2
  • 15
  • 21
  • 1
    This is great, but since the decryption takes a callback, wouldn't this mean that your function may get executed before you even have the secret? Assuming the secret is needed for the lambda to execute this could be a problem. – KerrM Aug 11 '16 at 12:10
  • 1
    Of course if you execute code after the decrypt call that need the secret, you must ensure that it is executed after the execution of the decrypt callback. You could use promise (never used it myself yet) or something like async.waterfall from http://caolan.github.io/async/ – JonathanGailliez Aug 12 '16 at 07:27
  • 2
    You can take this a step further and store the encrypted secret in S3. Give the lambda function a role where it can get objects from a specific bucket and that way you don't have to update the lambda function whenever the key changes, and don't have to worry about keeping the API stored on a machine. – bernays Dec 23 '16 at 16:58
  • Don't you have to somehow pass the encryption key to the decrypt function? – Kip Feb 07 '17 at 21:58
  • 2
    No. AWS will automatically know which key to use to decrypt the secret. – JonathanGailliez Feb 08 '17 at 07:30
  • 2
    Just to clarify that this code should need to be OUTSIDE of the handler. So that this will run only once and won't decrypt the secret in every function call. More information: https://forums.aws.amazon.com/thread.jspa?messageID=686261 – Alfonso Embid-Desmet May 25 '17 at 21:24
  • Has anyone trouble with permissions when doing fs.readFileSync? – Alfonso Embid-Desmet May 30 '17 at 16:56
  • I never had issue with permissions for fs.readFileSync on lambdas. – JonathanGailliez May 31 '17 at 07:31
  • My problem was due to my binary file with the encrypted secret not being included in the zip, for reference to others, that was because I was using `serverless-webpack` and that specific plugin seems to ignore the `package` > `include` configuration option, so I had to use `CopyWebpackPlugin` in order to specify that the binary file should be included in the zip. – Alfonso Embid-Desmet Jun 01 '17 at 16:43
  • 1
    Lambda environment variables already do this by default, and for free. If you use kms you need to manage and pay for use. – Edward Corrigall Aug 08 '18 at 20:46
15

As of AWS Lambda support for NodeJS 4.3, the correct answer is to use Environment Variables to store sensitive information. This feature integrates with AWS KMS, so you can use your own master keys to encrypt the secrets if the default is not enough.

Jamey
  • 1,595
  • 9
  • 23
  • 1
    Environment Variables would work but once you have to add the variable more than once, it becomes harder to maintain. Secrets Manager might be more appropriate. – Jack Marchetti Mar 14 '21 at 21:36
3

Well...that's what KMS was made for :) And certainly more secure than storing your tokens in plaintext in the Lambda function or delegating to a third-party service.

If you go down this route, check out this blog post for an existing usage example to get up and running faster. In particular, you will need to add the following to your Lambda execution role policy:

"kms:Decrypt",
"kms:DescribeKey",
"kms:GetKeyPolicy",

The rest of the code for the above example is a bit convoluted; you should really only need describeKey() in this case.

William Gaul
  • 3,181
  • 2
  • 15
  • 21
  • Hi thanks a lot for your answer but I think you might not have fully understood the concept behind KMS. Or maybe I haven't understood your answer. KMS is not a 'key store', you can't add your custom key to it. You have to use the ones Amazon create for you. Best regards, Jonathan. – JonathanGailliez Apr 13 '15 at 08:02
  • I am considering to use KMS for my configuration. If I understand correctly, I could encrypt my config file (key/value). Store it encrypted to KMS. And call it and decrypt when I need that file? – Amiga500 Jul 20 '18 at 07:52
3

There is a blueprint for a Nodejs Lambda function that starts off with decrypting an api key from kms. It provides an easy way to decrypt using a promise interface. It also gives you the role permissions that you need to give the lambda function in order to access kms. The blue print can be found by searching for "algorithmia-blueprint"

bernays
  • 77
  • 4
  • 1
    Link to any refrences – kevzettler Sep 27 '16 at 21:30
  • 2
    This is a helpful answer. Once inside console.aws.amazon.com/lambda, it's easy to find that blueprint. Create a function from the blueprint, and remove the S3 trigger if you have no bucket and just want to look at the code. Also answers @KerrM question below the accepted answer. – bebbi Oct 19 '16 at 07:43
-6

Whatever you choose to do, you should use a tool like GitMonkey to monitor your code repositories and make sure your keys aren't committed or pushed to them.

shaharsol
  • 991
  • 2
  • 10
  • 31