This example demonstrates how to store secrets like API keys encrypted in your repository, decrypting them with AWS KMS at runtime inside the Lambda function.
- Provide secrets like API keys to your Lambda functions without ever committing plaintext to source control
While repository hosting services like Github or Bitbucket have very high security standards it's recommended to not store your unencrypted secrets there. In addition in larger teams not everybody needs to have access to those secrets of your production environment.
Encrypting your secrets per stage with a KMS key and only adding the encrypted files to your repository is a sensible strategy to fulfill the previously described goals. Only principals granted kms:Decrypt on the key (in this example, the Lambda function's execution role) can read the secrets back.
serverless.ymlprovisions a customer-managed KMS key (SecretsKey) and grants theresetPasswordfunction's execution rolekms:Decrypton it.secrets.<stage>.ymlholds your plaintext secrets locally. It's gitignored - never commit it.npm run encrypt -- <stage>encryptssecrets.<stage>.ymlwith the KMS key intosecrets.<stage>.yml.encrypted, which is safe to commit.npm run decrypt -- <stage>reverses that, for local editing.- At runtime,
handler.jsreads the packagedsecrets.<stage>.yml.encryptedfile, callsKMSClient'sDecryptCommand, and caches the decrypted values for the lifetime of the execution environment (warm invocations skip the KMS round trip).
npm installCopy secrets.example.yml to secrets.dev.yml and fill in real values:
cp secrets.example.yml secrets.dev.ymlSESSION_KEY: 'your-session-signing-key-here'
EMAIL_SERVICE_API_KEY: 'your-email-service-api-key-here'serverless deployGrab the key id/alias from the SecretsKeyId stack output (or run serverless info).
KMS_KEY_ID=<key-id-from-stack-output> npm run encrypt -- devSuccessfully encrypted 'secrets.dev.yml' to 'secrets.dev.yml.encrypted'Commit secrets.dev.yml.encrypted - it can safely be checked into version control.
serverless deployserverless invoke -f resetPassword --log{
"statusCode": 200,
"body": "{\"message\":\"Password sent.\"}"
}
--------------------------------------------------------------------
SESSION_KEY: your-session-signing-key-here
EMAIL_SERVICE_API_KEY: your-email-service-api-key-hereEdit secrets.dev.yml, then re-run:
KMS_KEY_ID=<key-id-from-stack-output> npm run encrypt -- devSuccessfully encrypted 'secrets.dev.yml' to 'secrets.dev.yml.encrypted'If you've lost your local secrets.dev.yml, decrypt it back from the committed .encrypted file:
STAGE=dev npm run decrypt -- devSuccessfully decrypted 'secrets.dev.yml.encrypted' to 'secrets.dev.yml'The same commands work for any stage - just swap dev for prod:
serverless deploy --stage prod
KMS_KEY_ID=<prod-key-id-from-stack-output> npm run encrypt -- prodMake sure the unencrypted secrets.*.yml files are listed in .gitignore (they already are here) so they're never checked into your repository - only the .encrypted files should be committed.