loading...
Cover image for Simplify secrets management with LaconiaJS

Simplify secrets management with LaconiaJS

ankcorn profile image Thomas Ankcorn ใƒป2 min read

The boilerplate code required to retrieve secrets from the various AWS services makes serverless applications harder than they should be to build, and test.

Not only are there two services to choose from but they donโ€™t provide a way to provide the value of the secret to a lambda at runtime. We have to choose and do the work to retrieve the secrets ourselves. Outrageous!

A cat typing furiously

Let's look at an example:

I want to create a function that needs to retrieve 2 secrets

  • A Stripe key that is stored in Secrets Manager
  • An api key for our companies serious business service in SSM Parameter Store

Here's the code using just the AWS SDK to retrieve the values:

const SecretsManager = require('aws-sdk/clients/secretsmanager');
const SSM = require('aws-sdk/clients/ssm');

module.exports.handler = async () => {

        // retrieve stripe keys
        const secretsManager = new SecretsManager({ region: 'eu-west-1' });
        const { SecretString } = await secretsManager.getSecretValue({ SecretId: 'external/stripe' }).promise();
        const stripe = JSON.parse(SecretString);

        // retrieve api key
        const ssm = new SSM({ region: 'eu-west-1' })
        const { Value: apiKey } = await ssm.getParameter({ Name: 'sb-api-key' }).promise();

        // serious business logic follows ๐Ÿ’
        // ...
}

Other than the fact it's a bit long there are some serious problems with this approach.

  • If we want to move the API key to secrets manager we have to change some application code - that's probably why it's still in SSM
  • We cannot unit test the business logic here without first mocking out the calls to the SSM and secrets manager.

LaconiaJS solves these problems really neatly. Here's the example solution using LaconiaJS:

Define 2 environment variables using your deployment framework of choice

LACONIA_CONFIG_STRIPE=secretsManager:external/stripe
LACONIA_CONFIG_SB_API_KEY=ssm:sb-api-key
const laconia = require('@laconia/core');
const config = require('@laconia/config');

function seriousBusiness(lambdaInput, { stripe, sbApiKey }) {
  // stripe and sbApiKey are passed into the function by laconia
}

module.exports.handler = laconia(seriousBusiness)
         .register(config.envVarInstances());

As you can see there is a lot less code, it's more malleable, and it's much clearer how we would test the business logic of this function.

Now when testing the seriousBusiness function we can pass in arbitrary values for the secrets instead of having to connect to production AWS resources.


test('serious business test', async () => {
        const input = {};
        expect(await seriousBusiness(input, { stripe: 'abc', sbApiKey: '123' })).toEqual({ message: 'Serious Business Complete' });
})

Finally

Even though I am pretty new to LaconiaJS its making serverless development much more productive and happy for me. I feel that I write less code and get to focus more on the business logic whilst using it. If you are want to learn more have a look at their website https://laconiajs.io/

Posted on Jun 30 by:

ankcorn profile

Thomas Ankcorn

@ankcorn

Software Engineer at @NearST. Organiser @LNUGorg. Coach @codebar.

Discussion

markdown guide