Skip to content
This repository has been archived by the owner on Nov 6, 2021. It is now read-only.

Commit

Permalink
v2.0 Release
Browse files Browse the repository at this point in the history
Multi-provider support
Large updates
  • Loading branch information
shortjared committed Jun 8, 2016
1 parent 3152e2d commit a733244
Show file tree
Hide file tree
Showing 20 changed files with 1,293 additions and 168 deletions.
3 changes: 2 additions & 1 deletion .jshintrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"node": true,
"globalstrict": true,
"predef": [ "describe", "beforeEach", "afterEach", "it" ]
"esnext": true,
"predef": [ "describe", "beforeEach", "afterEach", "it", "__ENV_VARS__", "__HANDLER_REQUIRE__" ]
}
33 changes: 33 additions & 0 deletions LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
The MIT License (MIT)

Copyright (c) 2015 Serverless, Inc. http://www.serverless.com

The following license applies to all parts of this software except as
documented below:

====

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

====

All files located in the node_modules and external directories are
externally maintained libraries used by this software which have their
own licenses; we recommend you read them, as their terms may differ from
the terms above.
90 changes: 73 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,31 @@
# Serverless Secrets : MAKE SECRETS GREAT AGAIN
![serverless_secrets_logo](https://cloud.githubusercontent.com/assets/1689118/15905519/23bf2208-2d83-11e6-96fb-7dc1edd359ee.png)

*A no fuss way of getting secrets into your Serverless functions, compatible with [Credstash](https://github.com/fugue/credstash)*

# WARNING: STILL SUPER IN DEVELOPMENT, DON'T ACTUALLY USE THIS FOR PRODUCTION (Or look at the source code 😕)
*A no fuss way of getting secrets into your Serverless functions*

**Problem:** The Serverless project currently offers no good way of managing secrets. There is the `_meta` folder which is ignored from a git repo by default, but what if you are working in a team? You could put it in the repo, but "secrets" in a git repo is bad practice.

So, what if you could put `_meta` in a secure place and share it around the team? That's what [Serverless meta sync](https://github.com/serverless/serverless-meta-sync) is for... but, then you still have secrets either floating around on developers machines, things could still be out of sync, you have to access control the files to proper machines in your pipeline... it's all not fun.

**Solution:** The `_meta` folder is actually quite good at what it does, and in our humble opinion version controlling it in git is fine, if you had a way to still protect your secrets. So, that's why we are building Severless Secrets. Use [Credstash](https://github.com/fugue/credstash) to put / version / manage your secrets, and use magic strings in your `_meta` folder. That's it.

# Multi-Provider Support

Serverless Secrets supports multiple providers, and is built to easily allow for more. You can use as many or few providers in each project as you desire.

# Setup
**KMS** Raw KMS wrapping of short strings, the easiest to get started with.
**KMS File** Wraps a file with encryption, allowing large blogs to be encrypted.
**Credstash** A [CredStash](https://github.com/fugue/credstash) compliant decryptor, most flexible and feature rich option, but more setup required.

Install / setup credstash. To make things easy on yourself just use defaults (table: credential-store, region: us-east-1)
# Project Setup

In the root of your Serverless project...
`npm install serverless-secrets --save`


# KMS & KMS File Providers Setup

### AWS Setup

Configure the IAM policy for the lambda functions that will use encrypted secrets. Don't forget to deploy resources.
```
# s-resources-cf.json
Expand All @@ -28,6 +36,56 @@ Configure the IAM policy for the lambda functions that will use encrypted secret
],
"Effect": "Allow",
"Resource": "arn:aws:kms:${region}:${awsAccountId}:key/${keyId}"
}
```

### Secrets in `_meta`

Use a magic string in your `_meta` folder to denote an encrypted secret. Prefixing any variable with `kms::` or `kmsfile::` tells the plugin to fetch and decrypt it with the matching provider.

```
# _meta/variables/s-variables-common.json
# _meta/variables/s-variables-stage.json
# _meta/variables/s-variables-stage-region.json
{
...
"secretText": "kms::kmskey::lsjfl39uf3s9faofjas3f9as3ufo23h2hui2h3r9823/23r2382934",
"secretFile": "kmsfile::kmskey::iuwmkdSLkjef83lsjef9303nskfj393hselkjfJf/soehf33jh::file.txt"
}
```

In both cases, the decryption will be automatically and the full plaintext will
be loaded into the env variable specified in s-function.json. You may still want to do
post processing on it, particularly in the case of the `kmsfile` provider.

### Encryption

**KMS**
`serverless secrets encrypt --provider kms --plaintext SuperSecretString`
`serverless secrets encrypt -p kms -t SuperSecretString`

**KMS File**
`serverless secrets encrypt --provider kmsfile --file file.txt`
`serverless secrets encrypt -p kmsfile -f file.txt`

The KMS File encryptor can work with relative file paths so you can keep all your secrets outside of your repo.
`serverless secrets encrypt -p kmsfile -f ../../secrets-out-of-repo/file.txt`


# Credstash Provider Setup
Install / setup [CredStash](https://github.com/fugue/credstash). To make things easy on yourself just use defaults (table: credential-store, region: us-east-1)

Configure the IAM policy for the lambda functions that will use encrypted secrets. Don't forget to deploy resources.
```
# s-resources-cf.json
{
"Action": [
"kms:Decrypt"
],
"Effect": "Allow",
"Resource": "arn:aws:kms:${region}:${awsAccountId}:$[key|alias]/${keyId}"
},
{
"Action": [
Expand All @@ -40,29 +98,27 @@ Configure the IAM policy for the lambda functions that will use encrypted secret
}
```

Use the magic string in your `_meta`folder to denote an encrypted secret. Prefixing any variable with `secret::` tells the plugin to fetch and decrypt it. Postfixing a secret with `::{version}` tells it to fetch a version of the given number. (You could probably use alphanumeric too if you wanted.)
**NOTE:** You can override default CredStash region and table with CREDSTASH_TABLE and CREDSTASH_REGION environment variables.

### Secrets in `_meta`

Use a magic string in your `_meta` folder to denote an encrypted secret. Prefixing any variable with `credstash::` tells the plugin to fetch and decrypt it with the credstash provider. Postfixing a secret with `::{version}` tells it to fetch a version of the given number. (You could probably use alphanumeric too if you wanted.)
```
# _meta/variables/s-variables-common.json
# _meta/variables/s-variables-stage.json
# _meta/variables/s-variables-stage-region.json
{
...
"secretThing": "secret::secret-thing", # Grabs the latest version of a secret
"secretThing": "secret::secret-thing::1" # Grabs the specific version of a secret
"secretThing": "credstash::secret-thing", # Grabs the latest version of a secret
"secretThing": "credstash::secret-thing::1" # Grabs the specific version of a secret
}
```

# Security
### Encryption
Use the CredStash CLI provided by credstash to manage your secrets. The CredStash interface has not been re-implemented Serverless Secrets.

> It's pretty good.
> - Abraham Lincoln

# Performance

You will pay a performance penalty of around a second or so on a cold container start for round trips with DynamoDB and KMS. However, after the cold startup, you are clear for takeoff with a nice warmed up cache and basically no time cost.

# Best Practices

> Ask not what your secrets can do for you, ask what you can do for your secrets.
> - JFK, probably
11 changes: 11 additions & 0 deletions decryptor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
var AWS = require('aws-sdk');
var kms = new AWS.KMS({region: 'us-east-1'});

CiphertextBlobBase64 = "CiDZOVE8Sg9RUIiajI+8gPaN5ChCUVn2EYTKRtpcDQ+s0RKXAQEBAgB42TlRPEoPUVCImoyPvID2jeQoQlFZ9hGEykbaXA0PrNEAAABuMGwGCSqGSIb3DQEHBqBfMF0CAQAwWAYJKoZIhvcNAQcBMB4GCWCGSAFlAwQBLjARBAz9fryxCa9nQ5Q+JbQCARCAKwAFcGxl3ec9+yzjZN8GRTbB0AGlhnadyf97DIzK+xSF7syOtjoUVKJpH5o="

kms.decrypt({CiphertextBlob: new Buffer(CiphertextBlobBase64, 'base64')}, function(err, response) {
if (err) console.log(err, err.stack);
else{
console.log(new Buffer(response.Plaintext).toString('utf-8'));
}
});
16 changes: 13 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
{
"name": "serverless-secrets",
"version": "1.0.2",
"version": "2.0.0",
"description": "A serverless plugin for managing secrets, Credstash compatible.",
"main": "src/index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"test": "echo \"Error: no test specified\" && exit 1",
"prepublish": "make"
},
"repository": {
"type": "git",
"url": "https://github.com/trek10inc/serverless-secrets"
},
"keywords": [
"serverless",
"serverless secrets",
"serverless management",
"serverless plugin",
"secrets",
"env"
Expand All @@ -23,8 +26,15 @@
},
"homepage": "https://github.com/trek10inc/serverless-secrets",
"dependencies": {
"aes-js": "^2.0.0",
"aws-sdk": "^2.3.9",
"bluebird": "^3.1.1",
"lodash": "^4.0.0"
"lodash": "^4.13.1",
"mkpath": "^1.0.0",
"ncp": "^2.0.0"
},
"devDependencies": {
"browserify": "^13.0.1",
"uglify-js": "^2.6.2"
}
}
16 changes: 16 additions & 0 deletions src/decryptors/nodejs4.3/_serverless_handler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
'use strict';

var decryptor = require('./serverless-secrets/decryptor');

var envVars = __ENV_VARS__;
for (var key in envVars) {
process.env[key] = envVars[key];
}

var originalHandler = __HANDLER_REQUIRE__;

module.exports.handler = function(event, context, callback) {
decryptor(function(){
return originalHandler(event, context, callback);
});
};
47 changes: 47 additions & 0 deletions src/decryptors/nodejs4.3/serverless-secrets/decryptor/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
'use strict';

var providers = require('../providers');

/*
The brilliance of this whole plan is that "process.env" is a global variable.
We override an "encrypted" string for a provider, and we only have to do it
once for a single container. process.env acts as a "cache" of sorts.
*/

function decryptor(callback){
var encryptedStrings = [];

for(var key in process.env){
var parsedVar = process.env[key].split(/::(.+)/);

if(typeof providers[parsedVar[0]] !== 'undefined'){
encryptedStrings.push({key: key, provider:parsedVar[0], rawString: parsedVar[1]});
}
}

// Return right away if no encrypted strings
if(!encryptedStrings.length){
return callback();
}

// Avoid other dependencies at all cost for smaller footprint
var decryptedVars = 0;
encryptedStrings.forEach(function(item){
console.log("Decrypting", item.key);
providers[item.provider](item.rawString, function(err, decryptedVar) {

if(err) console.log(err);
else{
process.env[item.key] = decryptedVar;
}

decryptedVars++;
if(decryptedVars === encryptedStrings.length) {
return callback();
}

});
});
}

module.exports = decryptor;
Loading

0 comments on commit a733244

Please sign in to comment.