Skip to content

Instantly share code, notes, and snippets.

@Limess
Last active April 7, 2018 16:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Limess/3680d62549b56ab75e41cbb7502fcf87 to your computer and use it in GitHub Desktop.
Save Limess/3680d62549b56ab75e41cbb7502fcf87 to your computer and use it in GitHub Desktop.
Serverless encryption thoughts

Vault

Encrypt secret configuration at rest in Vault. Access keys either:

1. At runtime using the API (either via REST or a client library, e.g. node-vault

Pros
  • Encrypted variables never exposed to AWS/in console.
  • Could be written in to a library and re-used based on approles.
  • CI can remain ambivalent to secret management.
Cons
  • All secret config access becomes asynchronous.
  • Changes to secrets in vault require a lambda redeploy as AWS is unaware that anything has changed (could invalidate periodically and refetch)
  • Vault downtime prevents new lambda containers from operating. Existing containers will be unaffected if loaded at startup.
  • Approle has to be created per application. Kickstarter have open sourced a lambda to do this based on cloudformation updates (designed for ECS)
  • Developers need to setup vault locally, local auth rather than approle must be used locally.
  • CI needs to define vault secrets are present if reliable deployments are desired.

Unsure on what affect this has on cold-start time of the lambda.

2. Pre-deploy

e.g. CircleCI Deploy -> Fetch from Vault -> Publish to Lambda This is the approach next currently use

Pros
  • Vault downtime does not affect the lambda.
  • Secret access remains synchronous.
  • Github/CI role can be used to access secrets.
  • Vault secrets can be easily verified to exist by CI.
Cons
  • Secrets now potentially stored in plaintext in AWS console/serverless deployment package.
  • Secrets need to be rencrypted with KMS if not stored in plaintext.
  • Developers need to setup vault locally and on CI.

AWS Secrets

It should be noted that all environment varaibles are encrypted automatically via AWS using a shared KMS key, however these variables are still visibile at rest by default.

There are two main serverless plugins in existent reflecting two main approaches for this.

1. Encrypt variables at rest and in transit using native AWS lambda KMS encyption:

https://docs.aws.amazon.com/lambda/latest/dg/env_variables.html#env_encrypt https://docs.aws.amazon.com/lambda/latest/dg/tutorial-env_console.html

This can then be decrypted using a snippet provided by AWS:

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

const encrypted = process.env['PGPASSWORD'];
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);
        });
    }
};

This incurs additional latency if decrypted at runtime source

latency to decrypt a secret using a KMS CMK is often around 2 seconds

Pros
  • Uses existing AWS infrastructure.
  • Only need to create a KMS key.
  • Native to AWS lambda
Cons
  • High latency (1-2s on cold starts)
  • Need additional AWS permissions
  • Not stored in vault.
  • Not sharable between lamba projects.
  • All secret config access becomes asynchronous.

2. Encrypt secrets at rest and in transit using KMS, access at runtime using KMS API

Existing serverless plugin to handle encryption/decryption:

This incurs additional latency if decrypted at runtime source

latency to decrypt a secret using a KMS CMK is often around 2 seconds

Pros
  • Uses existing AWS infrastructure.
  • Only requires KMS
  • Encrypted at rest and in transit
  • Native to AWS lambda
  • IAM KMS access handled by plugin
Cons
  • High latency (1-2s on cold starts)
  • Need additional AWS permissions
  • Not stored in vault.
  • Not sharable between lamba projects.
  • All secret config access becomes asynchronous.

3. Encypt the variables at rest in SSM Parameter Store and decrypt prior to deploy

These values are then natively available in serverless reference on pros and cons at rest.

Pros
  • Uses existing AWS infrastructure.
  • Defined in serverless.yml natively
  • Secret access doesn't change
  • Validated on serverless deploy
  • IAM role based
Cons
  • Need additional AWS permissions
  • Not stored in vault.
  • Visibile in the AWS console.
  • Visible using lambda GetFunctionConfiguration API call.
  • Changes to secrets in KMS (not managed by lambda) potentially require a lambda redeploy as the lambda is unaware anything has changed (could refetch secrets periodically).

4. Encypt the variables at rest in SSM Parameter Store and access at runtime

Then access these at runtime using the SSM api.

https://github.com/SC5/serverless-kms-secrets

Pros
  • Uses existing AWS infrastructure.
  • Only need to create a KMS key.
  • Low runtime cost to access SSM (~50ms max)
  • IAM role based
Cons
  • Need additional AWS permissions
  • Not stored in vault.
  • All secret config access becomes asynchronous.
  • Changes to secrets in KMS (not managed by lambda) potentially require a lambda redeploy as the lambda is unaware anything has changed, alternatively invalidate secrets and re-fetch periodically
  • CI needs to define KMS secrets are present if reliable deployments are desired.

Lastpass

Store variables in FT lastpass. Developers retrieve them and deploy locally/in circleCI Simplest solution, status quo.

Pros
  • Simple, just add as environment variables.
Cons
  • Each environment variable needs setting individually.
  • No encryption at rest.
  • Visible in the AWS console.
  • Visible using lambda GetFunctionConfiguration API call.
  • Not available programatically

Resources

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment