Serverless Secret Baker

A Serverless Framework Plugin for secure, performant, and deterministic secret management.

user  

vacasaoss

serverless-secret-baker

CircleCI Maintainability Test Coverage

A Serverless Framework Plugin for secure, performant, and deterministic secret management.

How it works

Secrets are first stored in AWS Parameter Store (aka SSM) for ease of management. At deploytime time this plugin will retrieve the encrypted value of the secrets, store them in a file with associated metadata, and add that file to the serverless deployment package.

When the Lambda is invoked an AWS SDK call is used to decrypt the stored ciphertext via KMS directly.

Prerequisites

  1. Create a custom KMS CMK.
  2. Upload secrets to SSM Parameter Store using the CMK
  3. Install this plugin with npm install --save-dev serverless-secret-baker
  4. Add to your serverless.yml the following to install the plugin:
plugins:
  - serverless-secret-baker
  1. Add to your serverless.yml the following to specify which secrets to retrieve from parameter store:
provider:
  environmentSecrets:
    - MY_SECRET

The plugin will create a json file with all the secrets. In the above example the ciphertext and ARN of the secret located at MY_SECRET will be stored in the file under the key MY_SECRET.

See example code in examples folder for reference.

  1. Ensure your Lambda has permission to decrypt the secret at runtime using the CMK. Example:
iamRoleStatements:
  - Effect: Allow
    Action:
      - kms:Decrypt
    Resource:
      - # REPLACE with ARN for your CMK
  1. Add a code snippet in your application to decrypt the secret:

Advanced Configuration

If you would like to name your secrets something different than the path in Parameter Store you can specify a name and path in the configuration like so:

provider:
  environmentSecrets:
    MY_SECRET: /path/to/ssm/secret

Or you can use a more explicit object syntax

provider:
  environmentSecrets:
    - name: CUSTOM_SECRET
      path: a/custom/secret/path 

This allows you to mix styles

provider:
  environmentSecrets:
    - MY_SECRET
    - MY_OTHER_SECRET
    - name: CUSTOM_SECRET
      path: a/custom/secret/path 

Why use this plugin?

There are many solutions for secret management with AWS Lambda. Unfortunately, a lot of the solutions unnecessarily expose the secrets in plain text, incur latency by invoking an API call to decrypt a secret with every lambda invocation, or require potentially complex cache invalidation for when a secret is rotated.

Here are some common patterns to secret management and their downsides:

  1. Use Lambda Environment Variables: The plaintext value of the secret is exposed insecurely within the Cloud Formation template. AWS explicitly recommends not storing sensitive information in Lambda Environment Variables as it is not encrypted in transit during deploy time.
  2. Use the built-in Serverless Framework for AWS Parameter Store:. By using the built-in syntax of ${ssm:/path/to/secret~true} this will retrieve the plaintext secret at packaging time and store it in an Environment Variables. This has the same downsides to 1).
  3. Use AWS Parameter Store or AWS Secret Manager at Runtime: Requires either retrieving the secret via API at every invocation of the Lambda (latency) or retrieving it once and caching the secret in the lambda global scope. If caching the secret in global scope a cache invalidation strategy is needed to refresh the secret when it is updated in Parameter Store / Secret Manager to prevent lambdas using old, potentially invalid secrets.

This plugin addresses these concerns by focusing on:

  1. Security: Secrets should always be encrypted at rest and in transit. The secrets are stored in Parameter Store using a custom KMS CMK. The only time it is decrypted is at lambda invocation.
  2. Performance: Minimize external dependencies and API calls. The secrets are retrieved directly from KMS. There is no runtime dependency on Parameter Store or Secrets Manager. In addition, the secret can be cached in the Lambda global scope so only a single API call per warmed up lambda is needed.
  3. Deterministic State: Complex cache invalidation strategies are not needed. Because the ciphertext is bundled with the lambda at deploy time the secrets can be modified at the source in AWS Parameter Store without effecting the runtime state. In order to apply the new secrets, a new deployment of the Lambdas is required allowing it to go through a CI/CD pipeline to catch any potential errors with secrets and to ensure that all the lambdas get the new secret at the same time.
view on Github

Latest commit b2f54ec on Sep 24, 2017

New to serverless?

To get started, pop open your terminal & run:

npm install serverless -g